Binary Analysis Patterns 是一套面向编译后二进制文件的分析模式与技巧集合,目标是在反汇编、反编译、控制流分析与代码模式识别等环节提供可复用的参考。其内容适合逆向未知可执行文件、分析恶意或混淆样本,以及在 Ghidra、IDA Pro、Binary Ninja 等工具中识别编译器生成的常见惯用法。
适用场景
- 逆向未知可执行文件,理解其行为;
- 在 Ghidra、IDA Pro、Binary Ninja 中分析恶意或混淆二进制;
- 识别常见汇编惯用法,如函数序言、跳转表、虚表分发;
- 从编译代码重建高层控制流;
- 识别编译器引入的模式,如栈金丝雀、PIC 跳板。
反汇编基础
资料给出了 x86-64 与 ARM 两类指令模式。
x86-64 指令模式
函数序言与尾声:
; 标准序言
push rbp
mov rbp, rsp
sub rsp, 0x20
; 叶函数(无调用)可能跳过帧指针设置
sub rsp, 0x18
; 标准尾声
mov rsp, rbp
pop rbp
ret
; leave 指令等价形式
leave
ret
调用约定:
- System V AMD64(Linux、macOS):参数依次使用 RDI、RSI、RDX、RCX、R8、R9,之后入栈;返回值在 RAX(128 位时另用 RDX);调用者保存寄存器为 RAX、RCX、RDX、RSI、RDI、R8-R11;被调用者保存寄存器为 RBX、RBP、R12-R15。
- Microsoft x64(Windows):参数依次使用 RCX、RDX、R8、R9,之后入栈;栈上保留 32 字节影子空间;返回值在 RAX。
资料给出了两种约定下多参数调用的示例写法。
ARM 汇编模式
- ARM64(AArch64):参数使用 X0-X7;返回值在 X0(128 位时另用 X1);帧指针 X29;链接寄存器 X30。资料给出使用
stp x29, x30, [sp, #-16]!、mov x29, sp的序言,以及ldp x29, x30, [sp], #16、ret的尾声。 - ARM32:参数使用 R0-R3,之后入栈;返回值在 R0(64 位时另用 R1);链接寄存器为 LR(R14)。序言示例为
push {fp, lr}、add fp, sp, #4;尾声示例为pop {fp, pc}。
控制流模式
资料涵盖条件分支、循环与 switch 三类模式。
条件分支示例包括相等比较 cmp eax, ebx 配合 jne,有符号小于比较配合 jge,无符号小于比较配合 jae。
循环模式给出 for、while 与 do-while 三种写法:for 循环以 xor ecx, ecx 初始化、cmp ecx, [n] 与 jge 判断、inc ecx 递增;while 循环采用先跳转到条件检查的结构;do-while 则在循环体之后判断并回跳。
switch 模式给出跳转表与顺序比较两种形式:跳转表使用 cmp eax, max_case、ja default_case 与 jmp [jump_table + eax*8];小型 switch 使用连续的 cmp 与 je。
数据结构模式
资料给出数组访问、结构体访问与链表遍历三种模式。
数组访问示例包括 4 字节元素 mov eax, [rbx + rcx*4]、8 字节元素 mov rax, [rbx + rcx*8],以及多维数组按 base + (i * cols + j) * element_size 计算的写法。
结构体访问以一个示例结构体说明字段偏移:int a 在偏移 0,char b 在偏移 4,随后是偏移 5-7 的填充,long c 在偏移 8,short d 在偏移 16;并给出各字段的读取指令示例。
链表遍历示例使用 test rdi, rdi 判断节点是否为空,jz list_done 结束循环,并以 mov rdi, [rdi+8] 取下一节点。
常见代码模式
资料包含字符串操作、算术模式与位操作。
字符串操作给出 strlen、strcpy 的循环写法,以及使用 rep movsb 的 memcpy 写法。
算术模式给出乘常数优化示例:x * 3 使用 lea eax, [rax + rax*2],x * 5 使用 lea eax, [rax + rax*4],x * 10 则先算 x * 5 再 add eax, eax。有符号除 2 的幂给出 cdq、and、add、sar 的组合;取模 2 的幂给出 and eax, 7。
位操作给出测试位 test eax, 0x80、置位 or eax, 0x10、清位 and eax, ~0x10、翻转位 xor eax, 0x10,以及计算前导零的 bsr 加 xor eax, 31 和统计置位的 popcnt eax, ecx。
反编译模式
资料给出变量恢复、函数签名恢复与类型恢复三类模式。
变量恢复示例展示栈上局部变量(如 [rbp-8])与栈分配数组(如 lea rax, [rbp-0x40])的读写写法。
函数签名恢复示例说明如何依据寄存器使用判断参数,例如 System V 下 rdi 作第一个参数、rsi 作第二个参数,并以结尾处的 RAX 判断返回值。
类型恢复示例按操作宽度推断类型:1 字节操作配合 movzx/movsx 提示 char 或 bool;2 字节操作提示 short;4 字节操作提示 int 或 float(movss);8 字节操作提示 long、double 或指针(movsd)。
Ghidra 分析技巧
资料给出改善反编译的脚本示例:通过 getFunctionAt(toAddr(0x401000)) 取函数并调用 setReturnType 修正返回类型;用 StructureDataType 创建结构体类型并添加字段,再通过 createData(toAddr(0x601000), struct) 应用到内存。模式匹配脚本示例遍历函数与引用,打印对 strcpy、sprintf、gets 等危险函数的调用地址。
IDA Pro 模式
资料给出 IDAPython 分析示例:引入 idaapi、idautils、idc,通过遍历函数与指令查找指定函数名 call 的位置并打印地址;还给出基于字符串交叉引用辅助重命名函数的思路框架。
最佳实践与常见陷阱
分析工作流被整理为:初始分类(文件类型、架构、导入导出)、字符串分析、函数识别(入口点、导出、交叉引用)、控制流映射、数据结构恢复、算法识别(加密、哈希、压缩)、文档化(注释、重命名符号、类型定义)。
常见陷阱包括:优化器产物可能与源码结构不符;内联函数可能被展开;尾调用优化可能以 jmp 代替 call 加 ret;优化产生的死代码;位置无关代码使用 RIP 相对寻址。
限制
资料未提供该技能的具体安装方式、运行环境要求、支持的二进制格式范围以及收费或授权信息,暂未提供。