反调试功能<CheckRemoteDebuggerPresent>

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 

--------------------------------------------------------------------------------

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
	);

这里第二个参数是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:

原文地址:https://www.cnblogs.com/hgy413/p/3693453.html