这本书的反调试技术分成了静态反调试技术、动态反调试技术、高级反调试技术
我只是写下来作为一个笔记提示,其中可能有些写的略微简略,也应不乏谬误,欢迎提出意见,我再将其修缮
静态反调试技术:
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前缀的区别:
https://docs.microsoft.com/zh-cn/windows-hardware/drivers/kernel/using-nt-and-zw-versions-of-the-native-system-services-routines
附函数定义以及一些结构体:
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(枚举类型)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2020-12-29 00:15
被哈桑编辑
,原因: 更新反调试技术