反调试技术总结: 静态

终于, 花了三周时间(期间经历了本科最后一门期末考试)学到了高级逆向技术, 反调试

反调试

反调试有各种各样的技术, 针对不同调试器和OS版本. 同时更新很快, 日新月异, 浓缩了设计者和破解者的攻防博弈智力对抗.

分类(摘自ReverseCore50章)
在这里插入图片描述
主要是按静态和动态反调试技术来分类.
静态反调试技术
通过探测调试状态来反调试.
动态反调试技术
扰乱调试的跟踪功能, 使调试者无法查看代码与数据.



静态反调试

检测调试状态的方法主要有, 调试器检测法, 调试环境检测, 强制隔离调试器等. 破解方式则主要是通过修改探测代码所获取的信息, 欺骗探测过程, 使反调试失效.

PEB

PEB(Process Environment Block)结构体包含了进程被调试的信息. 所以可以通过检测这个信息来确定进程是否被调试.
注意每个版本的操作系统都有不同的PEB结构体, 所以需要灵活分析. 举例是在XP系统下.
与反调试相关的PEB结构体中的数据项是
在这里插入图片描述
BeingDebugged是调试状态的标志, Ldr, ProcessHeap, NTGlobalFlag是调试进程的堆内存特性相关的参数.

(复习一下PEB寻址

# 两种方式
# 第一种 通过FS段寄存器直接获取
MOV EAX, DWORD PTR FS:[0x30]; FS[0x30] = address of PEB

# 第二种 先获取TEB的地址再获取PEB地址
MOV EAX, DWORD PTR FS:[0x18]; FS[0x18] = address of TEB
MOV EAX, DWORD PTR DS:[EAX + 0x30]; DS[EAX + 0x30] = address of PEB

# 这是XP SP3系统下的结构体寻址, 不同版本OS的TEB和PEB结构体有可能不同, 必须辩证分析.

BeingDebugged
调试状态下, BeingDebugged == 1, IsDebuggerPresent() API是获取PEB.BeingDebugged的值并判断调试状态的接口. 破解很直接, 修改BeingDebugged值为0即可.

Ldr
调试时, 堆内存区域会有特殊标识, 比如未使用的堆内存区域全部填充了0xEEEEEEEE, 很容易辨认是否在调试状态. PEB.Ldr指向_PEB_LDR_DATA_结构体, 该结构体在堆内存里, 所以只需要扫描这个地址范围查看是否有0xEEEEEEEE区域就能判断是否在调试状态. 不过利用附加功能将进程附加到调试器时, 不会出现这种情况.
XP系统下的破解方法是将所有0xEEEEEEEE覆写为null. 但之后的系统无效.

Process Heap
指向HEAP结构体的指针, HEAP结构体如下
在这里插入图片描述
调试状态下, Flags和Force Flags会设定成特定值. 利用附加功能将进程附加到调试器时, 也不会出现这种情况.
XP下的破解是将HEAP.Flags和HEAP.ForceFlags的值重新设定为正常运行时的2与0即可.

NtGlobalFlag
调试状态下, PEB.NtGlobalFlag == 0x70, 检测即可知道是否在调试. 不过附加的方式进行调试PEB.NtGlobalFlag的值不变.
破解方法, PEB.NtGlobalFlag ← 0.

NtQueryInformationProcess()

一种检测调试器的技术, NtQueryInformationProcess()是可以获取各种与进程调试相关信息的API.
函数定义
在这里插入图片描述第二参数PROCESSINFOCLASS ProcessInformationClass是一个枚举类型. 包括
与调试器探测相关的有ProcessDebugPort, ProcessDebugObjectHandle, ProcessDebugFlags.

ProcessDebugPort
当参数ProcessInformationClass == ProcessDebugPort时, 系统分配进程一个调试端口Debug port. NtQueryInformationProcess()则会获取调试端口.

ProcessDebugObjectHandle
当参数ProcessInformationClass == ProcessDebugObjectHandle时, 参数三会得到一个调试对象, 调试时这个值存在, 非调试状态该值为null

ProcessDebugFlags
当参数ProcessInformationClass == ProcessDebugFlags时, 参数三得到调试状态标志, 0是正在调试, 1是非调试状态.


NTQuerySystemInformation()

基于调试环境的反调试技术. NTQuerySystemInformation()API是一个系统函数, 可以获取OS信息.
在这里插入图片描述

第一个参数SystemInformationClass传入SystemKernelDebuggerInformation, 第二个参数SystemInformation为结构体SYSTEM_KERNEL_DEBUGGER_INFORMATION的地址, SYSTEM_KERNEL_DEBUGGER_INFORMATION.DebuggerEnabled == 1则表明系统处于调试状态.


NtQueryObject()

调试器调试进程时, 会创建一个调试对象类型的内核对象, 检测这个对象就可以判断是否存在进程被调试. ntdll!NtQueryObject() API可以获取系统内核对象的信息.


ZwSetInformationThread()

强制分离被调试者和调试器技术. ZwSetInformationThread() API可以强制将被调试着从调试器中抽离出来.在这里插入图片描述
第一个参数ThreadHandle接收当前进程句柄, 第二个参数ThreadInformationClass表示线程信息类型. 设置ThreadInformationClass = ThreadHideFromDebugger, 调用函数后, 调试进程就会分离出来.
破解方法, 钩取ZwSetInformationThread(), 或者运行时修改ThreadInformationClass为0.

对比另一个API DebugActiveProcessStop(), ZwSetInformationThread()是通过隐藏进程使调试器接收不到调试进程的信息, 从而分离被调试进程. DebugActiveProcessStop()是直接分离调试器和被调试进程达到分离目的.

TLS回调函数

在TLS回调函数中使用IsDebuggerPresent()来判断调试状态, 再决定程序是否进行运行. (TLS回调函数先于EP代码执行, 所以可以在TLS回调中添加判断条件来确定调试状态)


ETC

思想很简单, 只需要检测系统是否运行了特定用于调试的进程就可以了, 没必要非得整的很复杂.
比如用各个WIN32 API检测是否存在OllyDbg.exe, VMWareService.exe, 程序运行路径是否有"TEST", "ANALYSIS"等名称.
破解也很简单, 调试时在检测特定进程名称的API处断点, 修改名称参数即可, 当然也可钩取相应API修改信息, 即可绕过检测.





动态反调试

下一篇博客

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值