二进制代码分析是计算机科学和软件工程许多领域中的关键活动,涵盖软件安全、程序分析到逆向工程。手动二进制分析是一项困难且耗时的任务,存在一些旨在自动化或协助人类分析师的软件工具。然而,大多数这些工具具有若干技术和商业限制,限制了学术界和从业者社区大部分人的访问和使用。BARF 是一个开源二进制分析框架,旨在支持信息安全学科中常见的广泛二进制代码分析任务。它是一个可脚本化的平台,支持来自多种架构的指令提升、二进制翻译到中间表示、用于代码分析插件的可扩展框架以及与外部工具(如调试器、SMT求解器和插桩工具)的互操作。该框架主要设计用于人类辅助分析,但也可以完全自动化。
BARF项目 包括 BARF 及相关工具和包。到目前为止,项目由以下组件组成:
更多信息,请参阅:
当前状态:
| 最新版本 | v0.6.0 |
|---|---|
| URL | https://github.com/programa-stic/barf-project/releases/tag/v0.6.0 |
| 更新日志 | https://github.com/programa-stic/barf-project/blob/v0.6.0/CHANGELOG.md |
所有包已在 Ubuntu 16.04 (x86_64) 上测试。
BARF 是一个用于二进制分析和逆向工程的 Python 包。它可以:
ELF、PE 等),目前处于 开发中。
BARF 依赖于以下 SMT 求解器:
以下命令将 BARF 安装到你的系统:
$ sudo python setup.py install
你也可以本地安装:
$ sudo python setup.py install --user
sudo pip install pyasmjitsudo apt-get install graphviz这是一个非常简单的例子,演示如何打开一个二进制文件并打印每条指令及其到中间语言(REIL)的翻译。
from barf import BARF
# 打开二进制文件。
barf = BARF("examples/misc/samples/bin/branch4.x86")
# 打印汇编指令。
for addr, asm_instr, reil_instrs in barf.translate():
print("{:#x} {}".format(addr, asm_instr))
# 打印 REIL 翻译。
for reil_instr in reil_instrs:
print("\t{}".format(reil_instr))
我们还可以恢复 CFG 并将其保存到 .dot 文件中。
# 恢复 CFG。
cfg = barf.recover_cfg()
# 将 CFG 保存到 .dot 文件。
cfg.save("branch4.x86_cfg")
我们可以使用 SMT 求解器检查代码上的约束。例如,假设你有以下代码:
80483ed: 55 push ebp
80483ee: 89 e5 mov ebp,esp
80483f0: 83 ec 10 sub esp,0x10
80483f3: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8]
80483f6: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]
80483f9: 01 d0 add eax,edx
80483fb: 83 c0 05 add eax,0x5
80483fe: 89 45 fc mov DWORD PTR [ebp-0x4],eax
8048401: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
8048404: c9 leave
8048405: c3 ret
并且你想知道需要给内存位置 ebp-0x4、ebp-0x8 和 ebp-0xc 赋予什么值,才能在执行代码后在 eax 寄存器中获得特定值。
首先,我们将指令添加到分析器组件。
from barf import BARF
# 打开 ELF 文件
barf = BARF("examples/misc/samples/bin/constraint1.x86")
# 添加要分析的指令。
for addr, asm_instr, reil_instrs in barf.translate(0x80483ed, 0x8048401):
for reil_instr in reil_instrs:
barf.code_analyzer.add_instruction(reil_instr)
然后,我们为每个感兴趣的变量生成表达式,并添加所需的约束。
ebp = barf.code_analyzer.get_register_expr("ebp", mode="post")
# 前置条件:设置变量 a 和 b 的范围
a = barf.code_analyzer.get_memory_expr(ebp-0x8, 4, mode="pre")
b = barf.code_analyzer.get_memory_expr(ebp-0xc, 4, mode="pre")
for constr in [a >= 2, a <= 100, b >= 2, b <= 100]:
barf.code_analyzer.add_constraint(constr)
# 后置条件:设置结果的期望值
c = barf.code_analyzer.get_memory_expr(ebp-0x4, 4, mode="post")
for constr in [c >= 26, c <= 28]:
barf.code_analyzer.add_constraint(constr)
最后,我们检查我们建立的约束是否可解。
if barf.code_analyzer.check() == 'sat':
print("[+] 可满足!可能的赋值:")
# 获取表达式的具体值
a_val = barf.code_analyzer.get_expr_value(a)
b_val = barf.code_analyzer.get_expr_value(b)
c_val = barf.code_analyzer.get_expr_value(c)
# 打印值
print("- a: {0:#010x} ({0})".format(a_val))
print("- b: {0:#010x} ({0})".format(b_val))
print("- c: {0:#010x} ({0})".format(c_val))
assert a_val + b_val + 5 == c_val
else:
print("[-] 不可满足!")
你可以在 examples 目录中看到这些及更多例子。
该框架分为三个主要组件:core、arch 和 analysis。
此组件包含基本模块:
REIL:提供 REIL 语言的定义。同时,它还实现了 模拟器 和 解析器。SMT:提供与 Z3 和 CVC4 SMT 求解器交互的接口。此外,它还提供将 REIL 指令翻译为 SMT 表达式的功能。BI:Binary Interface 模块负责加载二进制文件以供处理(它使用 PEFile 和 PyELFTools)。每个支持的架构作为子组件提供,包含以下模块:
Architecture:描述架构,即寄存器、内存地址大小。Translator:为每个支持的指令提供到 REIL 的翻译器。Disassembler:提供反汇编功能(它使用 Capstone)。Parser:将指令从字符串形式转换为对象形式。到目前为止,此组件包含模块:控制流图、调用图 和 代码分析器。前两个分别提供 CFG 和 CG 恢复功能。后者是 SMT 求解器相关功能的高级接口。
BARFgadgets 是一个基于 BARF 构建的 Python 脚本,允许你在二进制程序中 搜索、分类 和 验证 ROP 小工具。搜索 阶段在二进制中查找所有以 ret、jmp 和 call 结尾的小工具。分类 阶段根据以下类型对先前找到的小工具进行分类:
这是通过指令模拟完成的。最后,验证 阶段使用 SMT 求解器验证第二阶段分配给每个小工具的语义。
usage: BARFgadgets [-h] [--version] [--bdepth BDEPTH] [--idepth IDEPTH] [-u]
[-c] [-v] [-o OUTPUT] [-t] [--sort {addr,depth}] [--color]
[--show-binary] [--show-classification] [--show-invalid]
[--summary SUMMARY] [-r {8,16,32,64}]
filename
用于查找、分类和验证 ROP 小工具的工具。
positional arguments:
filename 二进制文件名。
optional arguments:
-h, --help 显示此帮助信息并退出
--version 显示版本。
--bdepth BDEPTH 小工具深度(字节数)。
--idepth IDEPTH 小工具深度(指令数)。
-u, --unique 移除重复小工具(所有步骤中)。
-c, --classify 运行小工具分类。
-v, --verify 运行小工具验证(包含分类)。
-o OUTPUT, --output OUTPUT
保存输出到文件。
-t, --time 打印每个处理步骤的时间。
--sort {addr,depth} 按地址或深度(指令数)升序排序小工具。
--color 使用 ANSI 颜色序列格式化小工具,以便在256色终端或控制台输出。
--show-binary 显示每个小工具的二进制代码。
--show-classification 显示每个小工具的分类。
--show-invalid 显示无效小工具,即已分类但未通过验证过程的小工具。
--summary SUMMARY 保存摘要到文件。
-r {8,16,32,64} 按操作数寄存器大小过滤已验证的小工具。
更多信息,请参阅 README。
BARFcfg 是一个基于 BARF 构建的 Python 脚本,允许你恢复二进制程序的控制流图。
usage: BARFcfg [-h] [-s SYMBOL_FILE] [-f {txt,pdf,png,dot}] [-t]
[-d OUTPUT_DIR] [-b] [--show-reil]
[--immediate-format {hex,dec}] [-a | -r RECOVER]
filename
用于恢复二进制 CFG 的工具。
positional arguments:
filename 二进制文件名。
optional arguments:
-h, --help 显示此帮助信息并退出
-s SYMBOL_FILE, --symbol-file SYMBOL_FILE
从文件加载符号。
-f {txt,pdf,png,dot}, --format {txt,pdf,png,dot}
输出格式。
-t, --time 打印处理时间。
-d OUTPUT_DIR, --output-dir OUTPUT_DIR
输出目录。
-b, --brief 简要输出。
--show-reil 显示 REIL 翻译。
--immediate-format {hex,dec}
输出格式。
-a, --recover-all 恢复所有函数。
-r RECOVER, --recover RECOVER
按地址恢复指定函数(逗号分隔)。
BARFcg 是一个基于 BARF 构建的 Python 脚本,允许你恢复二进制程序的调用图。
usage: BARFcg [-h] [-s SYMBOL_FILE] [-f {pdf,png,dot}] [-t] [-a | -r RECOVER]
filename
用于恢复二进制 CG 的工具。
positional arguments:
filename 二进制文件名。
optional arguments:
-h, --help 显示此帮助信息并退出
-s SYMBOL_FILE, --symbol-file SYMBOL_FILE
从文件加载符号。
-f {pdf,png,dot}, --format {pdf,png,dot}
输出格式。
-t, --time 打印处理时间。
-a, --recover-all 恢复所有函数。
-r RECOVER, --recover RECOVER
按地址恢复指定函数(逗号分隔)。
PyAsmJIT 是一个用于 x86_64/ARM 汇编代码生成和执行的 Python 包。
开发此包是为了测试 BARF 从 x86_64/ARM 到 REIL 的指令翻译。主要思路是能够本地运行代码片段。然后,将相同的片段翻译为 REIL 并在 REIL VM 中执行。最后,比较两个最终上下文(通过本地执行获得的与通过模拟获得的)之间的差异。
更多信息,请参阅 PyAsmJIT。
BSD 2-Clause 许可证。更多信息,请参阅 LICENSE。