逆向工程实战手册 第 8 章

第 8 章 反调试与反分析对抗

分析目标往往会反咬你:检测调试器、检测虚拟机、自校验、混淆指令。本章按"检测面 → 绕过面"组织,看懂检测点就等于看懂绕过法。

📍 知识点地图 | 主题:反调试与对抗 | 前置:第4-6章 | 后续:第40章 | 核心概念:反调试检测、LD_PRELOAD、Qiling绕过、混淆

8.1 反调试总分类

类别 原理 平台
API 检测 IsDebuggerPresent 等 API Windows
内核/结构检测 PEB 标志、NtQueryInformationProcess Windows
时序检测 单步执行太慢 → 检测 全平台
信号/异常检测 信号处理、异常行为 Linux
反 VM/沙箱 CPUID、MAC、硬件指纹、资源检查 全平台
反 DBI 检测 Frida/Pin 注入痕迹 全平台
自校验 代码哈希、完整性检查 全平台
反汇编干扰 花指令、不透明谓词、控制流平坦化 全平台

8.2 Linux 反调试速查

ptrace 家族(最常见)

// 核心思路:自己先 ptrace(PTRACE_TRACEME),调试器就无法再附加
ptrace(PTRACE_TRACEME, 0, 0, 0);

绕过: 1. LD_PRELOAD 替换 ptracelibc.soptrace 函数替换成永远返回 0 2. GDB 设置set follow-fork-mode child + set detach-on-fork on 3. patch 掉调用:把 call ptrace NOP 掉 4. Qiling 模拟ql.set_syscall("ptrace", lambda: 0)

/proc 检测

// 读 /proc/self/status 的 TracerPid 字段,非 0 表示被跟踪
FILE *f = fopen("/proc/self/status", "r");

绕过:Hook/替换 fopen+fgets,或 patch 比较逻辑,或 LD_PRELOAD。

时序检测

// 两次 gettimeofday/clock_gettime 差值过大 → 被调试
// rdtsc 指令直读 CPU 周期

绕过:LD_PRELOAD 冻结 time()/gettimeofday;或 patch 阈值;或 Qiling 环境时钟可控。

SIGTRAP / 信号检测

单步会产生 SIGTRAP;程序自己装 signal handler 数信号次数

绕过:handle SIGTRAP nostop noprint pass(GDB),或 Hook signal。

8.3 Windows 反调试速查

检测 绕过
IsDebuggerPresent() Hook 返回 0 / patch mov eax,0; ret
CheckRemoteDebuggerPresent 同上
NtQueryInformationProcess(ProcessDebugPort) Hook Nt 层
PEB.BeingDebugged 字段 patch [fs:30h] 检查点
NtSetInformationThread(ThreadHideFromDebugger) 检测线程是否被隐藏
堆标志(Heap Flags / ForceFlags) 调试分配特征
TLS 回调检测 IDA 里看 .tls 回调表
软件断点扫描(0xCC) 检测断点字节
硬件断点检测(DR0-DR3) 读调试寄存器
异常基检测 异常分发路径差异
时间检查 GetTickCount Hook 冻结时间

工具:x64dbg + ScyllaHide 插件(一键反反调试)、pe-sieve 检测注入。

8.4 反 VM / 反沙箱

检测 原理 绕过
CPUID hypervisor bit 虚拟化标志位 模拟 CPUID 返回物理机特征
MAC 地址前缀 00:0C:29 (VMware) 等 改网卡 MAC
硬件指纹 SMBIOS/DMI 改配置
时序 VM 里指令慢 调阈值
资源检查 CPU 核数 / 内存 / 磁盘小 = 沙箱 改系统资源
文件/注册表痕迹 VBox 驱动、VMware tools 清理痕迹
用户名 / 窗口标题 "sandbox"/"virus" 关键字 环境自检

8.5 反 DBI(检测 Frida 等)

Frida 检测点:

/proc/self/maps 中 frida-agent 痕迹
frida-server 默认端口 27042
线程名 gum-js-loop / gmain
libgadget.so 等标志性模块

绕过: - Frida Gadget 更名 + 配置 interaction: listen 隐藏端口 - spawn 早期注入(比检测代码更早执行) - 内存 patch 检测点(先 Hook 检测函数) - Qiling/Unicorn 模拟:物理上不存在注入痕迹

8.6 代码完整性 / 自哈希

程序运行时对自己文件/内存哈希,与期望值比对 → 防 patch

绕过: 1. 找到哈希比较点 patch(je/jne 翻转) 2. 动态内存 patch(哈希的是文件,内存可以改) 3. 同时 patch 哈希期望值

8.7 反汇编干扰(静态侧)

不透明谓词(Opaque Predicates)

pushfq; pop rax       ; 恒真/恒假的花指令
cmp eax, 0x2B0F; jne x ; 看似分支实则恒跳

去混淆:D-810(IDA 插件)的 Opaque predicate removal

花指令 / 交错指令

指令流中间插入垃圾字节,跳转落在指令中间

应对:radare2 -x 分析、手动修复指令边界(undefine + 重新 define code)。

控制流平坦化(OLLVM)

switch-case 分发器把每个基本块串起来 → 控制流面目全非

去平坦化工具: - D-810(IDA 插件,首选):Unflattener + MBA simplification - obpo-plugin(IDA):右键 dispatcher → OBPO 一键处理 - ollvm-unflattener(Miasm 脚本) - ollvm-breaker(Binary Ninja) - deollvm(ARM64 + Unicorn) - GOOMBA(Ghidra) - Miasm / Triton 符号执行手动去

混合布尔算术(MBA)

(x & y) + (x | y) == x + y
(x ^ y) + 2*(x & y) == x + y
(x | y) - (x & ~y) == y
(x | y) & ~(x & y) == x ^ y

识别 + 化简:SiMBA(pip install simba-simplifier)、D-810 内置 MBA simplification、angr/Z3 自动化简。

8.8 其他高级反分析模式

模式 现象 应对
自修改代码 运行时解密自身 动态 dump / Unicorn 跟踪
异常处理混淆 逻辑藏在异常 handler Hook VEH/SEH
信号处理器侧信道 SIGFPE 计数暗示答案 strace 数信号
无调用链执行 栈帧操纵串联函数 逆序恢复处理链
fork+pipe+死分支 子进程算 flag,父进程死代码 patch 死分支比较值
多线程反调试 诱饵线程 + 信号处理 MBA 逐个线程分析
隐藏导入 哈希解析 API 识别哈希算法后还原

8.9 通用绕过检查清单

□ 识别检测类型(API/结构/时序/VM/DBI/自校验/静态干扰)
□ 优先选不碰二进制的方案: LD_PRELOAD / Frida / Qiling / 环境改造
□ 需要 patch 时: 先备份,改比较点或返回值,不要改逻辑主干
□ patch 后验证: 程序能跑通且行为符合预期
□ 反汇编干扰 → 先去混淆工具链(D-810 → obpo → Miasm)
□ 多检测叠加 → 分层逐个击破,记录每层的检测点

动手练习

  1. 写一个含 ptrace 检测的 C 程序,用三种方式绕过(LD_PRELOAD / patch / Qiling)。
  2. 写一个控制流平坦化的小程序(可用 ollvm 编译或用现成样本),用 D-810 去平坦化。
  3. 用 IDA 识别一个样本里的不透明谓词,观察它恒真/恒假。
  4. 分析一个带时序检测的样本,冻结时间后跑通。

深入阅读

  • 仓库:skills/reverse-engineering/anti-analysis.md(94 种反分析技术大全,本仓库最硬核的一篇)
  • 仓库:skills/reverse-engineering/tools-advanced.md(D-810 / obpo / Miasm / GOOMBA 用法)
  • 仓库:skills/reverse-engineering/patterns.md(Nanomites、自修改代码、SIGILL/SIGFPE 侧信道)
  • 仓库:skills/reverse-engineering/references/ollvm-deobfuscation.md(OLLVM 去混淆专项)
  • 仓库:skills/mobile-reverse/references/anti-detection-bypass.md(移动端多层绕过)
  • 仓库:skills/edr-bypass-re/(对抗防御产品的逆向方法论)