CheckRemoteDebuggerPresent这个API可以检测是否有调试器的存在,而且这个和PEB里面的BeingDebugged无关了。看一下CheckRemoteDebuggerPresent的声明:
__in HANDLE hProcess,
__in_out PBOOL pbDebuggerPresent
);
第一个参数是进程句柄,第二参数用于存放结果。返回值表示函数是否执行成功,
; 堆栈示意图
;push pBool ; ebp + c
;push hProcess ; ebp + 8
;push retaddr ; ebp + 4
;push ebp <-------------------------------------------
|
7C85AA22 > 8BFF MOV EDI,EDI ; |
7C85AA24 55 PUSH EBP ; |
7C85AA25 8BEC MOV EBP,ESP ;<-|
7C85AA27 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 ; hProcess == 0 ?
7C85AA2B 56 PUSH ESI ;
7C85AA2C 74 35 JE SHORT 7C85AA63 ; jmp exit
7C85AA2E 8B75 0C MOV ESI,DWORD PTR SS:[EBP+C] ; esi = pBool
7C85AA31 85F6 TEST ESI,ESI ; esi == 0?
7C85AA33 74 2E JE SHORT 7C85AA63 ; jmp exit
7C85AA35 6A 00 PUSH 0 ; push 0
7C85AA37 6A 04 PUSH 4 ; push 4
7C85AA39 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8] ;
7C85AA3C 50 PUSH EAX ; push offset hProcess
7C85AA3D 6A 07 PUSH 7 ; push ProcessDebugPort
7C85AA3F FF75 08 PUSH DWORD PTR SS:[EBP+8] ; push hProcess
7C85AA42 FF15 AC10807C CALL DWORD PTR DS:[<&ntdll.NtQueryInform> ; ntdll.ZwQueryInformationProcess
7C85AA48 85C0 TEST EAX,EAX ; eax == 0 ?
7C85AA4A 7D 08 JGE SHORT 7C85AA54 ; eax >= 0 -----------
7C85AA4C 50 PUSH EAX ; push eax |
7C85AA4D E8 ABE9FAFF CALL 7C8093FD ; call 7C8093FD |
7C85AA52 EB 16 JMP SHORT 7C85AA6A ; jmp |
7C85AA54 33C0 XOR EAX,EAX ; eax = 0 <-----------
7C85AA56 3945 08 CMP DWORD PTR SS:[EBP+8],EAX ; hProcess == 0 ?
7C85AA59 0F95C0 SETNE AL ; hProcess != 0 --> al = 1 (else al = 0)
7C85AA5C 8906 MOV DWORD PTR DS:[ESI],EAX ; *pBool = eax
7C85AA5E 33C0 XOR EAX,EAX ; eax = 0
7C85AA60 40 INC EAX ; eax = 1
7C85AA61 EB 09 JMP SHORT 7C85AA6C ; jmp ----------------
7C85AA63 6A 57 PUSH 57 ; push 57 |
7C85AA65 E8 D8E8FAFF CALL 7C809342 ; call 7C809342 |
7C85AA6A 33C0 XOR EAX,EAX ; eax = 0 |
7C85AA6C 5E POP ESI ; <-------------------
7C85AA6D 5D POP EBP ;
7C85AA6E C2 0800 RETN 8 ; return
--------------------------------------------------------------------------------
<span style="font-family:Arial;background-color: rgb(255, 255, 255);"></span>
CheckRemoteDebuggerPresent实际上调用了ntdll里面的ZwQueryInformationProcess来检测。这是一个Native API,声明如下:
NTSTATUS NtQueryInformationProcess (
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);
<span style="font-family:Arial;background-color: rgb(255, 255, 255);"></span>
这里第二个参数是7,实际上被定义为ProcessDebugPort
测试代码如下:
HMODULE hKernel32Dll = ::LoadLibrary(TEXT("kernel32.dll"));
if (NULL != hKernel32Dll)
{
fnCheckRemoteDebuggerPresent fn =
(fnCheckRemoteDebuggerPresent)::GetProcAddress(hKernel32Dll, "CheckRemoteDebuggerPresent");
if (!fn)
{
::FreeLibrary(hKernel32Dll);
return DGBTOOL_NO;
}
BOOL bDebuggerPresent = FALSE;
if(fn(GetCurrentProcess(), &bDebuggerPresent)
&&bDebuggerPresent)
{
::FreeLibrary(hKernel32Dll);
return DBGTOOL_CUSTOM;
}
else
{
::FreeLibrary(hKernel32Dll);
return DGBTOOL_NO;
}
}
return DGBTOOL_NO;
过掉方法:Hook住CheckRemoteDebuggerPresent,调用了ZwQueryInformationProcess之前的je改成jmp来跳过Zw这个函数~~OD还会在ZwQueryInformationProcess这个函数的调用地址强行改了,去调用作者的一个函数,该函数中根据是否查询的是7来决定时候调用ZwQueryInformationProcess: