首页 > 逆向调试 > 调试与反调试(3)–CheckRemoteDebuggerPresent

调试与反调试(3)–CheckRemoteDebuggerPresent

CheckRemoteDebuggerPresent这个API可以检测是否有调试器的存在,而且这个和PEB里面的BeingDebugged无关了。看一下CheckRemoteDebuggerPresent的声明:

BOOL WINAPI CheckRemoteDebuggerPresent(
  __in          HANDLE hProcess,
  __in_out      PBOOL pbDebuggerPresent
);

第一个参数是进程句柄,第二参数用于存放结果。返回值表示函数是否执行成功。来一个测试实例吧:

// 作者:代码疯子
// 博客:http://www.programlife.net/
// 转载请注明:本文来自程序人生——Www.ProgramLife.Net
#include <windows.h>
 
int WINAPI WinMain(
	   HINSTANCE	hInstance,
	   HINSTANCE	hPrevInstance,
	   LPSTR		lpCmdLine,
	   int			nCmdShow)
{
	BOOL bRes = FALSE;
	if (CheckRemoteDebuggerPresent(GetCurrentProcess(), &bRes))
	{
		MessageBox(NULL, 
			TEXT("Oooo, Debugger Found!"),
			TEXT(">_<!!!"),
			MB_ICONWARNING);
	}
 
	return 0;
}

用OllyDbg跟踪CheckRemoteDebuggerPresent,(Ctrl + G),看一下反汇编代码(我已经写好注释了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
; Analysised by 代码疯子
; 堆栈示意图
;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。下面再把我写的源代码贴出来。(这里参考了《加密与解密第三版》书上的资料,但是我发现书上写的东西有错误,具体请看http://bbs.pediy.com/showthread.php?t=132759).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// 作者:代码疯子
// 博客:http://www.programlife.net/
// 转载请注明:本文来自程序人生——Www.ProgramLife.Net
#include <windows.h>
 
typedef enum _PROCESSINFOCLASS {
	ProcessBasicInformation,	// 0
	ProcessQuotaLimits,			// 1
	ProcessIoCounters,			// 2
	ProcessVmCounters,			// 3
	ProcessTimes,				// 4
	ProcessBasePriority,		// 5
	ProcessRaisePriority,		// 6
	ProcessDebugPort,			// 7 Debug
	ProcessExceptionPort,
	ProcessAccessToken,
	ProcessLdtInformation,
	ProcessLdtSize,
	ProcessDefaultHardErrorMode,
	ProcessIoPortHandlers,          // Note: this is kernel mode only
	ProcessPooledUsageAndLimits,
	ProcessWorkingSetWatch,
	ProcessUserModeIOPL,
	ProcessEnableAlignmentFaultFixup,
	ProcessPriorityClass,
	ProcessWx86Information,
	ProcessHandleCount,
	ProcessAffinityMask,
	ProcessPriorityBoost,
	ProcessDeviceMap,
	ProcessSessionInformation,
	ProcessForegroundInformation,
	ProcessWow64Information,
	ProcessImageFileName,
	ProcessLUIDDeviceMapsEnabled,
	ProcessBreakOnTermination,
	ProcessDebugObjectHandle,
	ProcessDebugFlags,
	ProcessHandleTracing,
	ProcessIoPriority,
	ProcessExecuteFlags,
	ProcessResourceManagement,
	ProcessCookie,
	ProcessImageInformation,
	MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
} PROCESSINFOCLASS;
 
typedef NTSTATUS (__stdcall *pNtQueryInformationProcessProto) (
	__in HANDLE ProcessHandle,
	__in PROCESSINFOCLASS ProcessInformationClass,
	__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
	__in ULONG ProcessInformationLength,
	__out_opt PULONG ReturnLength
	);
 
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
 
BOOL CHECK_REMOTE_DEBUGGER_PRESENT(HANDLE hProcess, PBOOL pbRes)
{
	NTSTATUS status;
	HMODULE hNtdll = LoadLibrary(TEXT("ntdll"));
	pNtQueryInformationProcessProto NtQueryInformationProcess = NULL;
 
	if (hNtdll != NULL)
	{
		NtQueryInformationProcess =
			(pNtQueryInformationProcessProto)GetProcAddress(
			hNtdll, "NtQueryInformationProcess");
	}
	if (hNtdll == NULL || NtQueryInformationProcess == NULL)
	{
		return FALSE;
	}
 
	if (hProcess && pbRes)
	{
		status = NtQueryInformationProcess(hProcess, 
			ProcessDebugPort, 
			&hProcess, 
			4, 
			0);
		FreeLibrary(hNtdll);
		if (!NT_SUCCESS(status))
		{
			// BaseSetLastNTError(rv);
			return FALSE;
		}
		else
		{
			*pbRes = (BOOL)hProcess;
			return TRUE;
		}
	}
	else
	{
		SetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
	}
}
 
int WINAPI WinMain(
				   HINSTANCE	hInstance,
				   HINSTANCE	hPrevInstance,
				   LPSTR		lpCmdLine,
				   int			nCmdShow)
{
	BOOL bRes = FALSE;
	HANDLE hProcess = GetCurrentProcess();
	CHECK_REMOTE_DEBUGGER_PRESENT(hProcess, &bRes);
	if (bRes)
	{
		MessageBox(NULL, 
			TEXT("Oooo, Debugger Found!"),
			TEXT(">_<!!!"),
			MB_ICONWARNING);
	}
 
	return 0;
}

觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> 调试与反调试(3)–CheckRemoteDebuggerPresent
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



  1. 千羽鸣
    2011年4月23日10:49 | #1

    你现在是越来越精于此道了啊,下个月金山那边招实习,有兴趣没?

    [回复]

  2. 2011年4月23日15:47 | #2

    我觉得你已经有能力去破解一些付费软件了,完全可以赚点小钱了

    [回复]

  3. 2011年4月23日20:34 | #3

    @千羽鸣
    哪里,Windows真TM复杂,感觉个人力量很渺小,只是照着书上看一些东西。金山网络好像25号去武汉面试,我在想过去不过去,主要是发的简历都没有回信。

    你说的是西山居还是毒霸呢?我已经投了不少简历了,就是奇怪为什么都没有反应。忘了你是喜欢游戏的,想去西山居是吧?

    [回复]

  4. 2011年4月23日20:35 | #4

    @C瓜哥
    其实这些都是很基础的东西,加密解密,矛与盾的较量啊 呵呵

    [回复]

  5. god’sshit
    2013年4月25日17:37 | #5

    我就在金山。。。。。。。。。的附近的公司。。。。。 [em012]

    [回复]

    代码疯子 回复:

    @god’sshit, [em013] 珠海?

    [回复]