关于 code-obfuscation-deobfuscation
code-obfuscation-deobfuscation 是面向逆向分析人员的原生二进制混淆分析手册,帮助识别混淆模式,并选择静态、动态、符号执行或模拟方法还原程序结构与行为。
主要功能
- 01混淆模式分类
- 02不透明谓词与垃圾代码分析
- 03自修改代码检查
- 04控制流平坦化还原
- 05虚拟机保护与字符串分析
- 06反反汇编分析
适用场景
- 01还原控制流平坦化二进制
- 02检查运行时解密的代码
- 03分析虚拟机保护的二进制
- 04识别隐藏字符串和导入项
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill code-obfuscation-deobfuscation安装后在 Claude Code 中输入/code-obfuscation-deobfuscation确认已加载。
详细介绍
技能:代码混淆与反混淆——专家分析手册
AI 加载指令:识别、分类并破解原生二进制文件中代码混淆的专家技巧。涵盖垃圾代码、不透明谓词、自修改代码(SMC)、控制流扁平化、movfuscator、虚拟机保护器(VMProtect/Themida/Code Virtualizer)、字符串加密、导入隐藏和反反汇编技巧。基础模型通常会混淆加壳与代码混淆,并忽略静态和动态反混淆策略之间的区别。
0. 相关路由
- anti-debugging-techniques:混淆后的二进制文件还包含反调试层时
- symbolic-execution-tools:使用 angr/Z3 进行自动反混淆时
- vm-and-bytecode-reverse:深入分析虚拟机保护器字节码时
快速识别指南
| IDA/Ghidra 中的症状 | 可能的混淆类型 | 从这里开始 |
|---|---|---|
| CFG 扁平化,只有一个巨型 switch | 控制流扁平化 | 使用符号执行恢复 CFG |
只有 mov 指令 | movfuscator | 反 movfuscation/基于跟踪的提升 |
| pushad/pushfd → 虚拟机入口 | 虚拟机保护器 | 提取处理程序表 |
| 执行代码前出现 XOR 循环 | SMC/字符串加密 | 动态分析,在解码后设置断点 |
| 不可能成立的条件(不透明谓词) | 插入垃圾代码 | 基于模式移除 |
| 所有字符串都不可读 | 字符串加密 | Hook 解密例程,或进行模拟 |
| IAT 中没有导入项 | 导入隐藏 | 跟踪 GetProcAddress/哈希解析 |
1. 垃圾代码与不透明谓词
1.1 插入垃圾代码
不会影响程序输出的死代码,用于增加分析所需时间。
识别方法:
- 写入寄存器/内存、但之后从未读取的指令
- 返回值被丢弃且没有副作用的函数调用
- 循环边界不变、计算结果未被使用的循环
移除策略:
- 计算定义-使用链(IDA/Ghidra 数据流分析)
- 将没有后续用途的指令标记为死代码
- 验证移除不会改变程序行为(比较跟踪结果)
1.2 不透明谓词
条件分支中的条件始终为真或始终为假,但这一点并不明显。
| 类型 | 示例 | 始终求值为 |
|---|---|---|
| 算术 | x² ≥ 0 | 真 |
| 数论 | x*(x+1) % 2 == 0 | 真(两个连续整数的乘积) |
| 基于指针 | 别名处理后 ptr == ptr | 真 |
| 基于哈希 | CRC32(constant) == known_value | 真 |
反混淆:
- 抽象解释:证明条件为常量
- 符号执行:Z3 证明
∀x: predicate(x) = True - 模式匹配:识别已知的不透明谓词类型
- 动态分析:跟踪并观察分支始终不被执行/始终被执行
import z3
x = z3.BitVec('x', 32)
s = z3.Solver()
s.add(x * (x + 1) % 2 != 0)
print(s.check()) # unsat → always true
2. 自修改代码(SMC)
运行时修补代码:加密代码会在执行前立即解密。
2.1 XOR 解密循环(最常见)
lea esi, [encrypted_code]
mov ecx, code_length
mov al, xor_key
decrypt_loop:
xor byte [esi], al
inc esi
loop decrypt_loop
jmp encrypted_code ; now decrypted
2.2 分析策略
1. Identify the decryption routine (look for XOR/ADD/SUB in loops writing to .text)
2. Set breakpoint AFTER the loop completes
3. At breakpoint: dump the decrypted memory region
4. Re-analyze the dumped code in IDA/Ghidra
5. For multi-layer: repeat for each decryption stage
2.3 通过模拟自动脱壳
from unicorn import *
from unicorn.x86_const import *
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0x400000, 0x10000)
mu.mem_write(0x400000, binary_code)
mu.emu_start(decrypt_entry, decrypt_end)
decrypted = mu.mem_read(code_start, code_length)
3. 控制流扁平化(CFF)
3.1 结构
原本顺序执行的代码块会被转换为一个分发器循环:
Original: A → B → C → D
Flattened: ┌──────────────────┐
│ dispatcher │
│ switch(state) │◄─────┐
├──────────────────┤ │
│ case 1: block A │──────┤
│ case 2: block B │──────┤
│ case 3: block C │──────┤
│ case 4: block D │──────┘
└──────────────────┘
每个代码块都会在跳回分发器之前设置 state = next_state。
3.2 恢复技术
| 技术 | 工具 | 有效性 |
|---|---|---|
| 符号执行 | angr、Triton、miasm | 高——跟踪所有状态转换 |
| 基于跟踪的恢复 | Pin/DynamoRIO 跟踪 → 重建 CFG | 中——仅覆盖已执行的路径 |
| 模式匹配 | 自定义 IDA/Ghidra 脚本 | 中——适用于已知的扁平化工具 |
| D-810(IDA 插件) | IDA Pro | 高——专为 CFF 设计 |
3.3 符号执行反扁平化(angr 方法)
import angr, claripy
proj = angr.Project('./obfuscated')
cfg = proj.analyses.CFGFast()
# Find dispatcher block (highest in-degree basic block)
dispatcher = max(cfg.graph.nodes(), key=lambda n: cfg.graph.in_degree(n))
# For each case block, symbolically determine successor
for block in case_blocks:
state = proj.factory.blank_state(addr=block.addr)
# ... solve state variable to find real successor
4. MOVFUSCATOR
4.1 概念
所有计算都被简化为仅使用 mov 指令(通过内存映射计算表实现图灵完备)。由 Christopher Domas 创建。
4.2 识别
- 函数只包含
mov指令(没有 add、sub、xor、jmp、call) - 数据段中有大型查找表
- 内存映射的标志寄存器
4.3 去混淆
| 方法 | 描述 |
|---|---|
| demovfuscator(工具) | 静态分析,根据 mov 模式还原原始操作 |
| 跟踪 + 污点分析 | 使用 Pin/DynamoRIO 运行,对输入进行污点标记并观察计算过程 |
| 符号执行 | 将整个函数视为约束系统 |
5. VM 保护(VMProtect / Themida / Code Virtualizer)
5.1 VM 架构
Protected code → bytecode compiler → custom bytecode
Runtime: VM entry (pushad/pushfd) → fetch → decode → execute → VM exit (popad/popfd)
5.2 VM 入口点识别
; Typical VMProtect entry
pushad ; save all registers
pushfd ; save flags
mov ebp, esp ; VM stack frame
sub esp, VM_LOCALS_SIZE ; allocate VM context
mov esi, bytecode_addr ; bytecode instruction pointer
jmp vm_dispatcher ; enter VM loop
5.3 处理程序表提取
1. Find dispatcher (large switch or indirect jump via table)
2. Each case/entry = one VM handler (implements one VM opcode)
3. Map handler addresses to operations by analyzing each handler:
- Handler reads operand from bytecode stream (esi)
- Performs operation on VM registers/stack
- Advances bytecode pointer
- Returns to dispatcher
5.4 去虚拟化方法
| 方法 | 描述 | 工具 |
|---|---|---|
| 手动映射处理程序 | 逆向分析每个处理程序,构建 ISA 规范 | IDA + 脚本 |
| 记录跟踪 | 记录所有处理程序的执行情况,重建程序 | REVEN、Pin |
| 符号提升 | 对处理程序进行符号执行,提升为 IR | Triton、miasm |
| 模式匹配 | 将处理程序模式与已知 VM 系列进行匹配 | 自定义脚本 |
5.5 VMProtect 特性
- 在分派器中使用不透明谓词
- 处理程序变异:相同操作码在不同构建版本中对应不同的处理程序代码
- 多个 VM 层(VM 中嵌套 VM)
- 集成反调试和完整性检查
6. 字符串加密
6.1 常见模式
| 模式 | 示例 | 恢复方法 |
|---|---|---|
| XOR 循环 | for (i=0; i<len; i++) s[i] ^= key; | Hook 或模拟 XOR 函数 |
| 栈字符串 | mov [esp+0], 'H'; mov [esp+1], 'e'; ... | 使用 IDA FLIRT / Ghidra 脚本重新组装 |
| RC4 加密 | 加密数据块 + 二进制文件中的 RC4 密钥 | 提取密钥,离线解密 |
| AES 加密 | 加密数据块 + 运行时派生的 AES 密钥 | 在解密后 Hook |
| 自定义编码 | Base64 + XOR + 反转 | 跟踪解码函数并复现 |
6.2 自动字符串解密
# Ghidra script: find XOR decryption calls, emulate them
from ghidra.program.model.symbol import SourceType
decrypt_func = getFunction("decrypt_string")
refs = getReferencesTo(decrypt_func.getEntryPoint())
for ref in refs:
call_addr = ref.getFromAddress()
# extract arguments (encrypted buffer ptr, key, length)
# emulate decryption, add comment with plaintext
7. 导入隐藏
7.1 GetProcAddress + 哈希查找
FARPROC resolve(DWORD hash) {
// Walk PEB → LDR → InMemoryOrderModuleList
// For each DLL, walk export table
// Hash each export name, compare with target hash
// Return matching function pointer
}
7.2 恢复
- 识别哈希算法(常见算法:CRC32、djb2、ROR13+ADD)
- 计算所有已知 API 名称的哈希值
- 构建哈希 → API 名称查找表
- 在 IDA/Ghidra 中标注已解析的调用
7.3 常见哈希算法
| 名称 | 算法 | 使用者 |
|---|---|---|
| ROR13 | hash = (hash >> 13 | hash << 19) + char | Metasploit shellcode |
| djb2 | hash = hash * 33 + char | 各类恶意软件 |
| CRC32 | 函数名称的标准 CRC32 | 高级加壳工具 |
| FNV-1a | hash = (hash ^ char) * 0x01000193 | 现代恶意软件 |
8. 反反汇编技巧
8.1 技术
| 技巧 | 机制 | 修复方法 |
|---|---|---|
| 指令重叠 | jmp $+2; db 0xE8(伪造的调用前缀) | 从正确偏移处手动重新分析 |
| 跳转未对齐 | 跳入多字节指令的中间位置 | 强制 IDA 从目标位置重新分析 |
| 条件跳转对 | jz $+5; jnz $+3(始终跳转,迷惑线性反汇编) | 转换为无条件 jmp |
| 返回地址操纵 | 使用 push addr; ret 代替 jmp addr | 将 push+ret 识别为跳转 |
| 基于异常的流程 | 触发异常,真正的代码位于处理程序中 | 分析异常处理程序链 |
| Call + add [esp] | call $+5; add [esp], N; ret(计算跳转) | 计算实际目标 |
8.2 IDA 修复
Right-click → Undefine (U)
Right-click → Code (C) at correct offset
Edit → Patch → Assemble (for permanent fix)
9. 决策树
Obfuscated binary — how to approach?
│
├─ Can you run it?
│ ├─ Yes → Dynamic analysis first
│ │ ├─ Set BP on interesting APIs (file, network, crypto)
│ │ ├─ Trace execution to understand real behavior
│ │ └─ Dump decrypted code/strings at runtime
│ │
│ └─ No (embedded/firmware/exotic arch) → Static only
│ └─ Identify obfuscation type from patterns below
│
├─ What does the code look like?
│ │
│ ├─ Giant flat switch/dispatcher loop?
│ │ ├─ State variable drives control flow → CFF
│ │ │ └─ Use D-810 or symbolic deflattening
│ │ └─ Bytecode fetch-decode-execute → VM protection
│ │ └─ Extract handlers, build disassembler
│ │
│ ├─ Only mov instructions?
│ │ └─ movfuscator → demovfuscator tool
│ │
│ ├─ XOR/ADD loop writing to .text section?
│ │ └─ SMC → breakpoint after decode, dump
│ │
│ ├─ Impossible conditions in branches?
│ │ └─ Opaque predicates → Z3 proving or pattern removal
│ │
│ ├─ Disassembly looks wrong / functions overlap?
│ │ └─ Anti-disassembly → manual re-analysis at correct offsets
│ │
│ ├─ No readable strings?
│ │ └─ String encryption → hook decrypt function or emulate
│ │
│ ├─ No imports in IAT?
│ │ └─ Import hiding → identify hash, build lookup table
│ │
│ └─ pushad/pushfd → complex code → popad/popfd?
│ └─ VM protector entry/exit → full VM analysis
│
└─ What tool to use?
├─ Known protector (VMProtect/Themida) → specific deprotection guide
├─ Custom obfuscation → combine: IDA scripting + Triton + manual
├─ CTF challenge → angr symbolic execution often fastest
└─ Malware analysis → dynamic (debugger + API monitor) first
10. 工具箱
| 工具 | 用途 | 最适合 |
|---|---|---|
| IDA Pro + Hex-Rays | 反汇编、反编译、脚本编写 | 全方位分析 |
| Ghidra | 支持脚本编写(Java/Python)的免费替代方案 | 预算有限的逆向工程 |
| D-810 (IDA plugin) | 自动化 CFF 去扁平化 | OLLVM 风格的混淆 |
| miasm | 基于 IR 的分析框架 | 符号化去混淆 |
| Triton | 动态符号执行 | 不透明谓词求解、CFF |
| REVEN | 全系统跟踪记录与回放 | VM 保护器分析 |
| demovfuscator | 还原 movfuscator | 仅含 mov 指令的二进制文件 |
| x64dbg + plugins | 支持脚本编写的动态分析 | Windows 逆向工程 |
| Unicorn Engine | CPU 仿真 | SMC 脱壳、shellcode |
| Capstone | 反汇编库 | 定制工具 |
| IDA FLIRT | 函数特征匹配 | 识别剥离二进制文件中的库代码 |
| Binary Ninja | 采用 MLIL/HLIL 的替代反汇编器 | 自动化分析 |
评论
支持 Markdown