-
-
windows下静态反调小结
-
发表于:
2019-6-26 22:10
3793
-
reversing.kr的twist简直是反调的专场,现将《逆向工程核心原理》和本题中的静态反调原理进行整理,划分为三类总结如下。
基于PEB
检测PEB中的相关成员。
PEB.BeingDebugged
值的说明:当程序被调试时,PEB.BeingDebugged值为1,否则为0
读取方法:[pPEB+ 2] == [FS:30] + 2
例如:
MOV EAX,DWORD PTR FS:[30] ;获取进程环境块(FS:[0]存放TEB,FS:[30]存PEB地址)
MOVZX EAX,BYTE PTR DS:[EAX+2] ;获取PEB中描述状态的字节信息
PEB.Ldr
- 值的说明:PEB.Ldr存储_PEB_LDR_DATA的地址,该地址位于堆区,当程序被调试时,堆区未被使用的位置会有成片的0xEFEEEFEE和0xABABABAB,否则应该是一堆随机数据。
- 读取方法:[pPEB+0xC]
- 仅适用于xp,以后的系统就不这样了
PEB.ProcessHeap
PEB.ProcessHeap的指针位于PEB的0x18处,即PEB.ProcessHeap == pPEB + 0X18。单纯的PEB.ProcessHeap没有意义,有意义的是其指向的HEAP结构体成员,HEAP == [pPEB + 0X18]。pHEAP可以通过函数GetProcessHeap()获取。
- Heap.Flags——位于HEAP的0xC或0x40,被调试时为2,即pHEAP + 0xC == 2或pHEAP + 0x40 == 2。
- Heap.ForceFlag ——位于HEAP的0x10或0x44,被调试时为0,即pHEAP + 0x10 == 0或pHEAP + 0x44 == 0。
- 注意事项
- 不同的系统,Flag和ForceFlag的位置不同。xp的为0xC和0x10。
- 如果调试器是附加到程序上的,则检测不起作用。
PEB.NtGlobalFlag
- 值的说明:当程序被调试时PEB.NtGlobalFlag为0x70
- 读取方法:pPEB + 0X68
- 注意事项
一个关键问题,如何获得PEB地址?
PEB结构体指针存储在TEB结构体的0x30的位置,所以一般通过TEB来获取。TEB都存储在FS段起始处,也就是FS:00,并且TEB自己还在0x18的位置存了一个自己的指针(至今不知为什么这么搞),所以TEB地址也是[FS:18]。TEB地址也可以使用函数ntdll.NtCurrentTeb()来获取。
综上,pPEB == [FS:30] == [FS:18] + 0X30
基于函数
IsDebuggerPresent()
- 原理:读取PEB.BeingDebugged并返回
NtQueryInformationProcess()
根据第二个参数(枚举类型)获取不同的进程信息并返回到第三个参数中,其中有一些与程序调试相关。
- ProcessDebugPort (或7)
- 原理:进程处于调试状态时,系统就会为其分配一个调试端口。调试状态下返回0xFFFFFFFF,非调试状态下为0.
- ProcessDebugObjectHandle(或0x1E)
- 原理:调试进程时会生成调试对象,因此调试状态下返回调试对象句柄,非调试状态下返回NULL。
- ProcessDebugFlag(或0x1F)
CheckRemoteDebuggerPresent()
NtQuerySystemInformation()
- 原理:将第一个参数设为0x23(或SystemKernelDebuggerInformation),通过该函数判断系统是否开启了内核调试。
NtQueryObject() *
- 原理:获取调试内核对象,查找其中有没有调试对象(先挖坑...)
ZwSetInformationThread()
- 原理:当第二个参数为ThreadHideFromDebugger时,该函数的功能是将线程与调试器分离。但是,该函数内部首先会自己检测该线程是否与被调试器附加,如果是则将线程终止,不是则返回。
- 注意事项:有一定的破坏性。
GetThreadContext()
基于调试器
查看进程列表中是否有调试器原理:
- 原理:将进程列表中的进程名称与调试器的进程名称一一比对
- 绕过方式
- 修改获取进程列表的函数的返回值
- 修改调试器的进程名......
查看窗口
- 原理:使用FindWindow查看看是否有OD、IDA等调试器窗口存在
- 绕过方式
查注册表
- 原理:读取应用安装注册表,查看系统中是否安装了调试器
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)