用途
本技能面向编译后二进制文件、固件和移动应用包的逆向工程。逆向工程本质上是在无法阅读源码的情况下对程序进行假设检验,工作成本主要取决于查看的代码量,因此核心方法是先分类筛选(triage),找到真正关键的少数代码,再仔细阅读。
适用场景包括:理解未知或未文档化的可执行文件行为;从二进制中恢复算法、文件格式或通信协议;在闭源目标中定位漏洞;嵌入式与 IoT 设备的固件分析;CTF 逆向挑战。
不适用场景:需要引爆的活体恶意软件应使用 analyzing-malware;无头部的原始 shellcode 应使用 analyzing-shellcode;有源码时使用 auditing-code-for-vulnerabilities;Android/iOS 应用整体评估使用 testing-mobile-applications,本技能仅处理其中的原生 .so/Mach-O 组件;框架运行时(Flutter、Unity IL2CPP、React Native)有专门技能;Go、Rust、.NET 等有自身符号恢复机制的运行时也有专门技能;加壳或受保护的可执行文件应先使用 unpacking-protected-binaries;整块固件镜像的提取应先使用 analyzing-firmware-images。
主要能力
分类筛选(Triage)
在打开反汇编器之前,先用命令收集信息:
file target && du -h target
readelf -hSd target # ELF: headers, sections, dynamic deps
rabin2 -I target # radare2's normalized summary of any format
objdump -p target # PE/ELF imports and load config
checksec --file=target # NX, canary, RELRO, PIE, Fortify
strings -n 8 -t x target | less # ASCII with offsets
strings -e l -n 8 target # UTF-16LE, essential on Windows
分类筛选应回答:由什么语言/工具链构建、是否加壳、与什么通信、关键逻辑在哪里、是否被 strip。熵扫描与解包:
binwalk -E target
upx -d target -o target.unpacked
Go 和 Rust 二进制通常不会以关键方式被 strip,应先恢复符号:
GoReSym -t -p target > syms.json
nm -C target 2>/dev/null | head
静态分析工作流
选定一个工具深入使用,中途切换会丢失注释。
analyzeHeadless /proj MyProj -import target -postScript Decompile.java
r2 -AA target
# aaa analyze everything
# afl list functions, sorted by size
# axt @ sym.f cross-references TO a function
# pdg @ main decompile with ghidra plugin (r2ghidra)
# iz / izz strings in data / whole binary
# /x deadbeef search for a byte pattern
按证据而非地址顺序导航,三个最快找到关键代码的入口:字符串→交叉引用;导入→交叉引用;熵/常量(加密常量如 AES S-box、SHA-2 轮常量、MD5 magic 可被识别)。从锚点向外阅读,并随时重命名函数和变量。
识别反编译输出中的结构
关注:带字节数组索引和 XOR 的循环(混淆或自研密码);对输入读取的小整数做 switch(命令分发,通常是协议);长度来自输入的 memcpy(内存安全审查起点);同一基址上重复的 [rax + 8*n] 访问(结构体);表加载后通过寄存器调用(vtable 或回调分发)。
动态分析
静态说明代码能做什么,动态说明它实际做什么。不可信二进制只能在隔离 VM 中运行,无主机共享,网络受控。
strace -f -e trace=network,file,process -o trace.log ./target
ltrace -f ./target
gdb -q ./target
lldb ./target
x64dbg / WinDbg
frida-trace -f ./target -i 'recv*' -i 'EVP_*'
Frida 是应对反调试、自定义加密和许可证检查的最快途径:在解密后 hook 函数,而不是破解保护它的混淆。
固件与隔离例程的模拟:
qemu-arm -L /usr/arm-linux-gnueabi ./target
# Unicorn for a single function
# angr for symbolic execution
固件
binwalk -Me firmware.bin
unsquashfs -d rootfs squashfs-root.bin
rg -n 'password|admin|BEGIN (RSA|OPENSSH) PRIVATE KEY|api[_-]?key' -i rootfs/
find rootfs -name '*.pem' -o -name 'shadow' -o -name '*.conf'
ls rootfs/etc/init.d rootfs/www rootfs/usr/sbin
对无文件系统的引导加载程序或裸机镜像,反汇编前需先确定加载地址,错误的基址会使整个列表失去意义。
反分析技术
识别后决定是破解还是绕过:加壳(高熵、stub + 一个大节);反调试(IsDebuggerPresent、ptrace(PTRACE_TRACEME)、计时检查);VM 检测(CPUID 检查、MAC OUI、注册表痕迹);字符串混淆(无可读字符串但有明显解码循环);控制流平坦化(基于状态变量的大 switch)。绕过通常比破解更省成本。
使用方式
按上述分类筛选、静态分析、动态分析的顺序推进。先做 triage 确定工具链和关键区域,再选定一个反汇编/反编译工具深入分析,用字符串和导入的交叉引用定位关键代码,必要时用 Frida 等动态插桩验证行为。固件分析先提取文件系统再处理单个二进制。
适用场景与限制
适用于未知可执行文件分析、算法/协议恢复、闭源漏洞定位、固件分析、CTF 逆向。限制:活体恶意软件、原始 shellcode、有源码目标、移动应用整体评估、框架运行时、加壳文件、整块固件镜像提取均有各自专门技能,不应使用本技能。反编译输出在调用约定和结构体附近经常出错,下结论前应检查具体指令的反汇编。被 strip 不代表符号全丢,库函数可恢复,Go/Rust 元数据通常保留。字符串只指示查看位置,攻击者可能植入误导性字符串。
交付物
逆向报告应让读者无需重复工作即可行动,包含:身份(哈希、文件类型、架构、编译器、加壳器);能力(以行为而非地址表述);关键例程(带名称和一行用途的注释地址);协议/格式(逐字段,可附解析器或 Kaitai 规范);指标(网络端点、文件路径、互斥体、密钥、常量);未解决问题及原因。
ATT&CK 覆盖
防御规避(TA0005):T1027 混淆文件或信息;T1027.002 软件加壳;T1140 去混淆/解码文件或信息;T1497 虚拟化/沙箱规避;T1622 调试器规避。引用前应针对当前 ATT&CK 版本重新核实 ID。
参考
analyzing-malware(隔离、引爆与 IOC 提取);testing-mobile-applications(原生组件周围的 APK/IPA 工作流);Ghidra、rizin/radare2、Binary Ninja、IDA(选一个深入学习);Frida、angr、Unicorn、QEMU(动态与模拟分析)。