windows常见反调试

1. PEB

0×002 BeingDebugged
正常运行:0×0 调试态:0×1
0x00c Ldr:指向堆内存区地址
调试状态堆内存全部填充为0xFEEEFEEE
0×018 ProcessHeap:指向HEAP结构体
0x00c Flags 正常运行:0×2 调试态:0×50000062
0×010 ForceFlags 正常运行:0×2 调试态:0×40000060
0×068 NtGlobalFlag
正常运行:0×0 调试态:0×70
代码示例:

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
#include
#include
extern “C” BOOL WINAPI IsDebuggerPresent(VOID);
int main()
{
FARPROC pProc = NULL;
LPBYTE pTeb = NULL;
LPBYTE pPeb = NULL;
LPBYTE pLdr = NULL;
LPBYTE pHeap = NULL;
DWORD dst[4] = {0xEEFEEEFE, 0xEEFEEEFE, 0xEEFEEEFE, 0xEEFEEEFE};
//BeingDebugged
printf(“BeingDebugged———\n”);
if (IsDebuggerPresent())
{
printf(“Debugger Detected!\n”);
}
else
{
printf(“No Debugger!\n”);
}
//Ldr
printf(“\nLdr———\n”);
pProc = GetProcAddress(GetModuleHandle(“ntdll.dll”), “NtCurrentTeb”);
pTeb = (LPBYTE)(*pProc)();
pPeb = (LPBYTE)*(LPDWORD)(pTeb + 0×30);
pLdr = (LPBYTE)*(LPDWORD)(pPeb + 0xc);
__try
{
while (1)
{
if (!memcmp(dst, pLdr, sizeof(dst)))
{
printf(“Debugger Detected!\n”);
break;
}
pLdr++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf(“No Debugger!\n”);
}
//ProcessHeap
printf(“\nProcessHeap———\n”);
pHeap = (LPBYTE)*(LPDWORD)(pPeb + 0×18);
if (*(LPDWORD)(pHeap + 0x0c) == 0×50000062 || *(LPDWORD)(pHeap + 0×10) == 0×40000060)
{
printf(“Debugger Detected!\n”);
}
else
{
printf(“No Debugger!\n”);
}
//NtGlobalFlag
printf(“\nNtGlobalFlag———\n”);
if (*(LPDWORD)(pPeb + 0×68) == 0×70)
{
printf(“Debugger Detected!\n”);
}
else
{
printf(“No Debugger!\n”);
}
printf(“\n\n”);
return 0;
}

2. NtQueryInformationProcess

1
2
3
4
5
6
7
NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess (
HANDLE ProcessHandle,       // 进程句柄
PROCESSINFOCLASS   InformationClass, // 信息类型
PVOID      ProcessInformation,     // 缓冲指针
ULONG     ProcessInformationLength, // 以字节为单位的缓冲大小
PULONG    ReturnLength OPTIONAL // 写入缓冲的字节数
);

第二个枚举参数中的三个域可以用来做反调试
ProcessDebugPort = 0×7
正常运行:0×0 调试态:0xFFFFFFFF
ProcessDebugObjectHandle = 0x1E
正常运行:NULL 调试态:调试对象句柄
ProcessDebugFlags = 0x1F
正常运行:0×1 调试态:0×0
代码示例:

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
proc = (NTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandle(“ntdll.dll”), “NtQueryInformationProcess”);
//ProcessDebugPort = 0×7
(*proc)(GetCurrentProcess(), ProcessDebugPort, &dwRet, sizeof(dwRet), NULL);
if (dwRet != 0)
{
printf(“Debugger Detected!\n”);
}
else
{
printf(“No Debugger!\n”);
}
//ProcessDebugObjectHandle = 0x1e
(*proc)(GetCurrentProcess(), ProcessDebugObjectHandle, &dwRet, sizeof(dwRet), NULL);
if (dwRet != 0)
{
printf(“Debugger Detected!\n”);
}
else
{
printf(“No Debugger!\n”);
}
//ProcessDebugFlags = 0x1f
(*proc)(GetCurrentProcess(), ProcessDebugFlags, &dwRet, sizeof(dwRet), NULL);
if (dwRet == 0)
{
printf(“Debugger Detected!=%d\n”, dwRet);
}
else
{
printf(“No Debugger!\n”);
}

3. NtQueryObject

当调试器调试一个进程时,会创建一个调试类型的内核对象,检测系统中是否有调试对象即可判断是否有进程正在被调试。
获取内核对象信息链表,遍历链表中对象类型,如果有DebugObject类型对象则说明有程序正在被调试。

4. ZwSetInformationThread

隐藏线程,使调试器无法接收调试事件。
第二个参数是个枚举类型的,这个域可以用来反调试ThreadHideFromDebugger:0×11
代码示例:

1
2
3
4
5
6
7
8
9
int main()
{
MYZWSETINFOMATIONTHREAD proc = NULL;
proc = (MYZWSETINFOMATIONTHREAD)GetProcAddress(GetModuleHandle(“ntdll.dll”), “ZwSetInformationThread”);
proc(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);
printf(“done\n”);
system(“pause”);
return 0;
}

5. DebugActiveProcessStop

这个函数可以把调试器与被调试进程的调试关系解除,这样调试器也就接收不到被调试进程的调试事件了。

6. FindWindow

通过这个函数获取调试器窗口的句柄,如果调试器窗口存在就会返回一个非零的值。

7. TLS回调

Tls回调函数会优先于EP代码执行,所以可以在函数中写入检测代码,在进程还没有开始运行之前就可以知道是否正在被调试。TLS其实不算反调试技术,只有在结合了其他反调试技术才会有反调试的效果。
代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include
#include
void NTAPI Tls_Callback(PVOID h, DWORD dwReason, PVOID pv)
{
if( DLL_PROCESS_ATTACH == dwReason )
{
if (IsDebuggerPresent())
{
printf(“Debugger Detected!\n”);
}
}
}
#pragma comment(linker, “/INCLUDE:__tls_used”)
#pragma data_seg(“.CRT$XLX”)
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { Tls_Callback, 0 };
#pragma data_seg()
int main()
{
printf(“tls callback anti-debug————\n\n”);
system(“pause”);
return 0;
}

8. SEH

1)
a.安装seh处理函数
b.故意触发一个异常,跳转到刚注册的seh处理函数中
c.在seh处理函数中写入检测代码
2)
a.SetUnhandledExceptionFilter更改默认顶层异常处理函数
b.触发异常,跳转到更改过的顶层异常处理函数中
c. 在seh处理函数中写入检测代码

9. 进程快照

CreateToolhelp32Snapshot、Process32First、Process32Next
这几个函数可以用来建立一个系统正在运行的进程快照,然后遍历进程快照查找是否有常见的调试器进程正在运行也可用作反调试。

本文章转至[三叶草](http://syclover.sinaapp.com/?cat=4)