这本书的反调试技术分成了静态反调试技术、动态反调试技术、高级反调试技术
我只是写下来作为一个笔记提示,其中可能有些写的略微简略,也应不乏谬误,欢迎提出意见,我再将其修缮
静态反调试技术:
A) PEB结构体可用来进行反调试的四项:
+0x002 BeingDebugged ;UChar
…
+0x00c Ldr ;Ptr32_RTL_USER_PROCESS_PARAMETERS
…
+0x018 ProcessHeap ;Ptr32 Void
…
+0x068 NtGlobalFlag ;Uint48
1. BeingDebugged 一个Flag
被调试:1
非调试:0
相关函数:IsDebuggerPresent() ;获取PEB.BeingDebugged值来判断
破解:将BeingDebugged值置1
2. Ldr
Ldr指向一个在堆中创建的_PEB_LDR_DATA结构体
而调试进程的时候,未使用的堆内存区域全部填充着0xEEFEEEFE
破解:将0xEEFEEEFE全部用NULL填充
注:XP系统之后不适用
3. Process Heap
指向HEAP结构体的指针
非调试状态:
此结构体Flags(+0xC)被设置为0x2
Force Flags(+0x10)被设置为0x0
相关函数:GetProcessHeap() 获取结构体地址
注:仅XP系统可用
4. NtGlobalFlag
调试状态:值为0x70
FLG_HEAP_ENABLE_TAIL_CHECK(0X10)|
FLG_HEAP_ENABLE_FREE_CHECK(0X20)|
FLG_HEAP_VALIDATE_PARAMETERS(0X40)
非调试状态:值为0
破解之法:该值设0
注:将运行中的进程附加到调试器时,NtGlobalFlag值不变
附:PEB位置查找方式
1.
FS:[0x30]=address of PEB
2.
FS:[0x18]=address of TEB -> EAX (FS:[0x0]为TEB偏移0x0处的值)
[EAX+0x30] = address of PEB
这种方法是上一种的扩展形式,看起来比较麻烦
B) NtQueryInformationProcess() API探测调试器技术
第二个参数——枚举类型,指定特定值,函数会将信息设置到第三个参数中
ProcessDebugPort ;+0x7
ProcessDebugObjectHandle ;+0x1E
ProcessDebugFlags ;+0x1F
以下针对第三个参数:
ProcessDebugPort获取调试端口——调试的时候系统分配进程一个调试端口FFFFFFFF,非调试状态为0
ProcessDebugObjectHandle获取调试对象句柄——如果进程处于调试状态,调试句柄值就存在,非调试状态为NULL
ProcessDebugFlags调试标志——调试状态,为0;非调试状态,为1。
附:
1.函数定义

2. 枚举类型

C) NtQuerySystemInformation()——基于调试环境检测的反调试技术(检测当前OS是否在调试模式下运行)
第一个参数 SYSTEM_INFORMATION_CLASS SystemInformationClass
SYSTEM_INFORMATION_CLASS是枚举类型
值为SystemKernelDebuggerInformation(0x23)时
第二个参数PVOID SystemInformation被填入
SYSTEM_KERNEL_DEBUGGER_INFORMATION结构体地址
系统处于调试状态:
SYSTEM_KERNEL_DEBUGGER_INFORMATION.DebuggerEnabled=1
破解:以正常模式启动windows
附:
1.SYSTEM_INFORMATION_CLASS枚举类型

2.函数定义

D) NtQueryObject()——调试器调试进程时,系统会创建一个内核调试对象
第二个参数OBJECT_INFORMATION_CLASS ObjectInformationClass赋予特定值,相关信息会被填入第三个参数PVOID ObjectInformation
arg2:
OBJECT_INFORMATION_CLASS ObjectInformationClass是一个枚举类型,ObjectAllTypesInformation(0x3)获取系统所有对象信息,再从中检测是否存在调试对象。
arg3:(when arg2 == 0x3)
ObjectInformation
系统所有对象信息,先将其转换为POBJECT_ALL_INFORMATION类型
OBJECT_ALL_INFORMATION是一个结构体,前面加上一个大写字母P代表指向这个结构体的指针。结构体的第二个成员
OBJECT_TYPE_INFORMATION ObjectTypeInformation结构体的第一个成员TypeName,当此项为”DebugObject”时,说明正在调试
循环直到结束,如果没有,则不在调试中
亦即判断
ObjectInformation->ObjectTypeInformation->TypeName == “DebugObject”
与否
破解:
将函数第二个参数从0x3改为0x0,或者钩取对应api函数
注意:书中举的例子是ZwQueryObject()而非NtQueryObject()
书中并没有对其作解释,下面是微软给的说法

关于Nt前缀与Zw前缀的区别:
adbK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3P5X3S2Q4x3X3c8U0L8W2)9J5c8Y4N6A6L8X3c8G2N6%4y4Q4x3X3c8Z5j5i4u0V1N6$3q4J5k6g2)9J5c8X3c8J5K9i4k6W2M7Y4y4Q4x3V1k6C8k6i4u0F1k6h3I4Q4x3V1k6#2M7$3W2F1k6#2)9J5k6r3&6@1i4K6u0V1j5h3&6V1i4K6u0V1P5Y4N6Q4x3X3c8$3k6i4u0K6K9h3!0F1M7#2)9J5k6r3!0X3i4K6u0V1N6r3S2W2i4K6u0V1L8X3q4@1K9i4k6W2i4K6u0V1M7%4W2K6N6r3g2E0i4K6u0V1M7$3g2J5N6X3W2U0k6i4y4Q4x3X3c8J5L8%4g2@1K9h3&6W2M7H3`.`.
附函数定义以及一些结构体:
1.NtQueryObject()函数定义

2. SYSTEM_INFORMATION_CLASS枚举类型

3. OBJECT_ALL_INFORMATION结构体

4. OBJECT_TYPE_INFORMATION结构体
E) ZwSetInformationThread()——强制分离调试器
第一个参数ThreadHandle(枚举类型)用来接收当前线程的句柄
第二个参数ThreadInformationClass表示线程信息,当其设置为ThreadHideFromDebugger(0x11)后,调试进程会被分离出来。
非调试状态:该函数没有任何影响
调试状态:调试器终止,停止自身进程
破解:将ThreadInformationClass参数改为0x0
或者钩取此api函数
附:
1.ThreadHandle(枚举类型)

[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2020-12-29 00:15
被哈桑编辑
,原因: 更新反调试技术