在R3下对NTDLL里面的Zw函数的HOOK 大部分都是在函数前几个字节做HOOK,或者IAT之类的.这样的HOOK 虽然比较方便,不过也存在一个很大的弊端,就是函数HOOK 很容易被检测,所以我们需要一种更猥琐的HOOK方式.当然这只是相对.而不是真的很猥琐......
NTDLL里面的ZW函数大部分都是这样的
MOV EAX,1
MOV EDX,7FFE0300
CALL DWORD PTR DS:[EDX]
RETN 20
NTDLL里面的ZW函数都是通过系统全局共享内存7FFE0300调用KiFastSystemCall进入内核,所以我们要做的就是HOOK这个函数.
77866190 > 8BD4 MOV EDX,ESP
77866192 0F34 SYSENTER
77866194 > C3 RETN
大家看到了,大小5个字节 而且还有个返回函数,所以我们只能短跳再长跳.....
void HookSystemCall_HOOK()
{
DWORD dwOldProtect;
HMODULE hModule = GetModuleHandleA("NTDLL.dll");
DWORD dwKiFastSystemCall = PtrToUlong(GetProcAddress(hModule, "KiFastSystemCall"));
VirtualProtect(ULongToPtr(dwKiFastSystemCall - 0xA), 100, PAGE_EXECUTE_READWRITE, &dwOldProtect);
*(PWORD)ULongToPtr(dwKiFastSystemCall) = 0xF4EB;
*(PBYTE)ULongToPtr(dwKiFastSystemCall - 0xA) = 0xE9;
*(PDWORD)ULongToPtr(dwKiFastSystemCall - 0x9) = PtrToUlong(KiFastSystemCall) - (dwKiFastSystemCall - 0xA) - 5;
}
接下来就是JMP到我们的函数里面了.接下来要处理的就是把我们要的ZW函数给分拣出来.大家肯定注意到ZW的汇编代码MOV EAX,1,没错这个1就是ZW函数的序号.既然如此分拣出我们要的函数也不是什么问题
__declspec(naked) void KiFastSystemCall()
{
__asm{
cmp eax,1 ;EAX保存着我们需要的函数的序号.我们跳.....
jz Label
jmp KiFastSystemCallEx
;其他的返回原始KiFastSystemCall的地方,当然,原来的函数已经被我们JMP出来啦.需要特别处理
Label:
add esp,4
;不再返回到原始的ZwAccessCheck函数里面.而是直接返回调用ZwAccessCheck的函数.
jmp MyZwAccessCheck ;
}
}
上面的函数就是我们的KiFastSystemCall啦.接下来就是我们的MyZwAccessCheck函数.还有一个我们需要自己进入内核的KiFastSystemCallEx函数,我们自己构造一个.当然我们还需要构造一个新的ZwAccessCheck函数,原始的那个函数调用的KiFastSystemCall已经被我们HOOK了.
//自己构造一个KiFastSystemCall 这样原始的RETN问题就解决了.
__declspec(naked) void KiFastSystemCallEx()
{
__asm {
mov edx,esp
__emit 0x0F
__emit 0x34
retn
}
}
//跳板函数
__declspec(naked) NTSTATUS NTAPI ZwAccessCheck(
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN HANDLE ClientToken,
IN ACCESS_MASK DesiredAccess,
IN PGENERIC_MAPPING GenericMapping,
OUT PPRIVILEGE_SET PrivilegeSet,
OUT PULONG ReturnLength,
OUT PACCESS_MASK GrantedAccess,
OUT PNTSTATUS AccessStatus)
{
__asm
{
MOV EAX,1
CALL KiFastSystemCallEx
RETN 20
}
}
NTSTATUS NTAPI MyZwAccessCheck(
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN HANDLE ClientToken,
IN ACCESS_MASK DesiredAccess,
IN PGENERIC_MAPPING GenericMapping,
OUT PPRIVILEGE_SET PrivilegeSet,
OUT PULONG ReturnLength,
OUT PACCESS_MASK GrantedAccess,
OUT PNTSTATUS AccessStatus)
{
return ZwAccessCheck(
ISecurityDescriptor,
ClientToken,
DesiredAccess,
GenericMapping,
PrivilegeSet,
ReturnLength,
GrantedAccess,
AccessStatus);
}
差不多一个意思....剩下的就是依葫芦画瓢....自由发挥了.
[课程]FART 脱壳王!加量不加价!FART作者讲授!