首页
论坛
专栏
课程

[调试逆向] [其他内容] windows下静态反调小结

2019-6-26 22:10 996

[调试逆向] [其他内容] windows下静态反调小结

2019-6-26 22:10
996

reversing.kr的twist简直是反调的专场,现将《逆向工程核心原理》和本题中的静态反调原理进行整理,划分为三类总结如下。

基于PEB

检测PEB中的相关成员。

  1. 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中描述状态的字节信息
      
  2. PEB.Ldr

    • 值的说明:PEB.Ldr存储_PEB_LDR_DATA的地址,该地址位于堆区,当程序被调试时,堆区未被使用的位置会有成片的0xEFEEEFEE和0xABABABAB,否则应该是一堆随机数据。
    • 读取方法:[pPEB+0xC]
    • 仅适用于xp,以后的系统就不这样了
  3. 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。
      • 如果调试器是附加到程序上的,则检测不起作用。
  4. 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

基于函数

  1. IsDebuggerPresent()

    • 原理:读取PEB.BeingDebugged并返回
  2. NtQueryInformationProcess()

    根据第二个参数(枚举类型)获取不同的进程信息并返回到第三个参数中,其中有一些与程序调试相关。

    • ProcessDebugPort (或7)
      • 原理:进程处于调试状态时,系统就会为其分配一个调试端口。调试状态下返回0xFFFFFFFF,非调试状态下为0.
    • ProcessDebugObjectHandle(或0x1E)
      • 原理:调试进程时会生成调试对象,因此调试状态下返回调试对象句柄,非调试状态下返回NULL。
    • ProcessDebugFlag(或0x1F)
      • 原理:获取PEB+464的值,调试状态下返回0。
  3. CheckRemoteDebuggerPresent()

    • IsDebuggerPresent的远程版
  4. NtQuerySystemInformation()

    • 原理:将第一个参数设为0x23(或SystemKernelDebuggerInformation),通过该函数判断系统是否开启了内核调试。
  5. NtQueryObject() *

    • 原理:获取调试内核对象,查找其中有没有调试对象(先挖坑...)
  6. ZwSetInformationThread()

    • 原理:当第二个参数为ThreadHideFromDebugger时,该函数的功能是将线程与调试器分离。但是,该函数内部首先会自己检测该线程是否与被调试器附加,如果是则将线程终止,不是则返回。
    • 注意事项:有一定的破坏性。
  7. GetThreadContext()

    • (挖坑:还没搞清楚)

基于调试器

  1. 查看进程列表中是否有调试器原理:

    • 原理:将进程列表中的进程名称与调试器的进程名称一一比对
    • 绕过方式
      • 修改获取进程列表的函数的返回值
      • 修改调试器的进程名......
  2. 查看窗口

    • 原理:使用FindWindow查看看是否有OD、IDA等调试器窗口存在
    • 绕过方式
      • 修改参数
      • 修改返回值
  3. 查注册表

    • 原理:读取应用安装注册表,查看系统中是否安装了调试器


[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最新回复 (7)
编程小白 2019-6-27 16:52
2
0
你这是静态反调?
小白鼠_897235 1 2019-6-27 21:58
3
0
你这是静态反调?
猪会被杀掉 1 2019-6-27 22:18
4
0
你这是静态反调?
CDM小菜 1 2019-6-28 16:58
5
0
是呀,我理解的静态反调就是通过某种方法获取某些数据来判断程序是否处于调试状态或是否可能被调试,这种反调只对程序运行路径有影响,对调试器没有影响,破解这种反调时只需要篡改这些数据;而动态反调会使调试器发生异常。(参考的《逆向工程核心原理》这本书的分类)
乐活 2019-6-28 17:37
6
0
大佬的步步逼问
whathhh 2019-6-28 17:37
7
0
你这是静态反调?
killpy 2 2019-7-1 14:13
8
0
学习了 温故知新 感谢
游客
登录 | 注册 方可回帖
返回