danielplohmann/smda
GitHub: danielplohmann/smda
SMDA 是一个基于 Capstone 的极简递归反汇编库,专为从内存转储和原始二进制文件中精确恢复控制流图而设计。
Stars: 259 | Forks: 40
# SMDA
SMDA 是一个极简的递归反汇编库,专为从内存转储(memory dump)中精确恢复控制流图(CFG)而优化。
它基于 [Capstone](http://www.capstone-engine.org/) 构建,目前支持 x86/x64 Intel 机器码、实验性的 CIL (.NET) 反汇编,以及来自原始 DEX 文件的 Dalvik 字节码。
作为输入,它可以处理任意内存转储(最好具有已知的基地址),并且可以直接分析原始 DEX 文件。
其输出是函数、基本块和指令的集合,以及它们之间(块与函数、入/出)各自的边。
可选地,可以使用 ApiScout 方法推断对 Windows API 的引用。
## 安装说明
从 1.2.0 版本开始,我们终于通过迁移到 [PyPI](https://pypi.org/project/smda/) 简化了操作!
所以现在的安装非常简单:
```
$ pip install smda
```
## 使用说明
使用 SMDA 的典型工作流如下所示:
```
>>> from smda.Disassembler import Disassembler
>>> disassembler = Disassembler()
>>> report = disassembler.disassembleFile("/bin/cat")
>>> print(report)
0.777s -> (architecture: intel.64bit, base_addr: 0x00000000): 143 functions
>>> for fn in report.getFunctions():
... print(fn)
... for ins in fn.getInstructions():
... print(ins)
...
0x00001720: (-> 1, 1->) 3 blocks, 7 instructions.
0x00001720: ( 4883ec08) - sub rsp, 8
0x00001724: (488b05bd682000) - mov rax, qword ptr [rip + 0x2068bd]
0x0000172b: ( 4885c0) - test rax, rax
0x0000172e: ( 7402) - je 0x1732
0x00001730: ( ffd0) - call rax
0x00001732: ( 4883c408) - add rsp, 8
0x00001736: ( c3) - ret
0x00001ad0: (-> 1, 4->) 1 blocks, 12 instructions.
[...]
>>> json_report = report.toDict()
```
这里还有一个演示脚本:
* analyze.py -- 示例用法:对文件或内存转储执行反汇编,并可选择将结果以 JSON 格式存储到给定的输出路径。
对于 Dalvik,目前的范围是原始的单个 DEX 输入。APK、multi-dex 容器处理以及 ODEX/VDEX/CDEX 运行时工件分析尚未成为 SMDA 的一等公民工作流。
该代码应该与 Python 3.8+ 完全兼容。
关于内部工作原理的进一步解释将在后续的出版物中给出,并会在此处引用。
为了充分利用 SMDA 的功能,请确保(可选)安装:
* lief
* pdbparse(目前作为 https://github.com/VPaulV/pdbparse 的分支,以支持 Python3)
## 开发说明
### 代码质量
本项目使用 [Ruff](https://docs.astral.sh/ruff/) 进行 lint 和代码格式化。要设置开发环境:
```
# 安装开发依赖
python3 -m pip install --upgrade pip "setuptools>=64.0.0,<82.1.0" "wheel>=0.47.0"
python3 -m pip install -e ".[dev]"
# 安装 pre-commit hooks(可选但推荐)
make init
# 运行 linting
make lint
# 或
ruff check .
# 运行 formatting
make format
# 或
ruff format .
# 修复可自动修复的问题
make ruff-fix
# 或
ruff check . --fix
```
### Pre-commit Hooks
Pre-commit Hooks 配置为在提交时自动运行 ruff。使用以下命令安装它们:
```
pre-commit install
```
### 测试
运行测试:
```
make test
```
## 版本历史
* 2026-06-12: v4.0.0 - 支持 Aarch64!(感谢:@r0ny123)
* 2026-06-12: v3.4.2 - 修复了关于边缘情况偏移提取和计算的小错误。(感谢:@r0ny123)
* 2026-06-12: v3.4.1 - 为各种其他架构添加了测试负载。(感谢:@r0ny123)
* 2026-06-12: v3.4.0 - 现在可以基于 ELF 头正确推断架构和字长。像符号等信息源得到了妥善处理。(感谢:@r0ny123)
* 2026-06-12: v3.3.2 - 添加了使用 MCRIT 的 deflate+base85 方法存储二进制输入文件/缓冲区的能力。(感谢:@r0ny123)
* 2026-06-12: v3.3.1 - 添加了旨在限制处理时间和堆消耗激增的防护措施。(感谢:@r0ny123)
* 2026-06-12: v3.3.0 - 引入了带有执行和内存性能分析器的基准测试套件,以验证和指导改进。(感谢:@r0ny123)
* 2026-06-10: v3.2.1 - 小修复,依赖项版本升级。
* 2026-05-26: v3.2.0 - 几项旨在减少处理时间的性能优化。(感谢:@r0ny123)
* 2026-05-26: v3.1.0 - 仓库结构更改为 src 风格,整体包和 CI 流程现代化。(感谢:@r0ny123)
* 2026-05-20: v3.0.1 - 通过减少类型转换提高了字符串提取的性能。(感谢:@r0ny123)
* 2026-05-20: v3.0.0 - 支持 Android Dalvik 反汇编。(感谢:@r0ny123)
* 2026-05-20: v2.6.0 - 使用 Pythia 作为当前 Delphi VMT 解析器的直接替代品。(感谢:@r0ny123)
* 2026-05-20: v2.5.4 - 通过预编译正则表达式、执行额外的前缀提取以及覆盖更多 GAP 序列的 NOP 来提高性能。(感谢:@r0ny123)
* 2026-03-23: v2.5.3 - 在 SmdaReport 信息中添加了 ELF ABI,升级了 DelphiReSym 以处理 Delphi 13,通过移除冗余的标签提取略微提升了性能。(感谢:@r0ny123)
* 2026-01-16: v2.5.2 - 修复了 IdaInterface 中未能正确提取二进制数据的 bug。
* 2026-01-16: v2.5.1 - 通过缓存对象减少了对 lief 的调用。(感谢:@r0ny123)
* 2026-01-16: v2.5.0 - 引入了 Rust 符号提取和名称解码(demangling)。(感谢:@r0ny123)
* 2026-01-16: v2.4.7 - 提高了异常处理程序候选提取的可靠性。(感谢:@r0ny123)
* 2026-01-07: v2.4.6 - 修复了用于决定 IDA 兼容性的版本检查
* 2025-12-17: v2.4.5 - 提高了多个位置的安全性和可靠性。(感谢:@r0ny123)
* 2025-12-15: v2.4.4 - 扩展了默认函数序言(prologue)集合,以覆盖额外的 64 位 GCC 风格字节组合。添加了 exit syscall 检查以改善函数结尾识别。(感谢:@N0fix)
* 2025-12-10: v2.4.3 - 修复了 IDA 导出的兼容性问题,API 在 8.5 版本中已经发生了变化,因此调整了版本检查。
* 2025-11-28: v2.4.2 - 修复了从节表(section table)提取和合并代码区域时的一个 bug。(感谢:@r0ny123)
* 2025-11-28: v2.4.1 - 通过同时构建 wheel 实现了打包现代化。(感谢:@dimbleby)
* 2025-11-21: v2.4.0 - 集成了由 @WenzWenzWenz 开发的 DelphiReSym 用于 Delphi VMT 解析,感谢 @r0ny123 对其进行适配!!
* 2025-10-21: v2.3.1 - 修复了导致文件加载崩溃的 ELF 文件中节/段标志的 lief 错误。现在能够正确解析并提供 PE 自身 xmetadata 节中的符号信息。
* 2025-10-21: v2.3.0 - 主要的代码重构和清理,非常感谢 @r0ny123 的贡献!!
* 2025-07-25: v2.2.3 - 小错误修复。
* 2025-07-23: v2.2.1 - 在 SmdaReport 中添加了 xmetadata 字段,包含有关导入和导出的信息。改进了从 Go 二进制文件中提取字符串的功能。
* 2025-06-13: v2.1.0 - 支持从 IDA 9.0+ 导出(感谢 @jershmagersh 的更新!)。
* 2025-02-26: v2.0.2 - 调整了相对导入,添加了 init 文件。
* 2025-02-25: v2.0.0 - 初步实验性支持 CIL (.NET) 反汇编。
* 2025-01-29: v1.14.0 - 升级至 LIEF 0.16.0+(感谢 @huettenhain 的提醒!)。将测试迁移至 `pytest`,修复了 UTC 日期时间处理。
* 2023-11-21: v1.13.0 - 对 PicHashing 进行了破坏性调整(现在在函数中对过程内跳转使用通配符,如果在地址空间内则包含更多立即数)。引入了 OpcodeHash (OpcHash),它对除了前缀和操作码字节以外的所有内容使用通配符。
* 2023-03-24: v1.12.0 - SMDA 现在会解析 PE 导出目录以获取符号,以及 MinGW DWARF 信息(如果可用)。
* 2023-02-06: v1.11.0 - SmdaReport 现在具有通过给定偏移量查找包含它的函数/块的功能(感谢 @cccs-ay!)。
* 2023-02-06: v1.10.0 - 适配了用于二进制解析的 LIEF 0.12.3 API(感谢 @lainswork!)。
* 2022-08-12: v1.9.1 - 添加了对解析 intel MachO 文件的支持,包括 Go 解析。
* 2022-08-01: v1.8.0 - 添加了对解析 Go 函数信息的支持(感谢 @danielenders1!)。
* 2022-01-27: v1.7.0 - SmdaReports 现在包含一个 `oep` 字段;SmdaFunctions 现在会指示 `is_exported`,并可通过 `getCodeInrefs()` 和 `getCodeOutrefs()` 提供 CodeXrefs。(感谢 @mr-tz 提供的想法)
* 2021-08-20: v1.6.0 - 修复了二进制映射对齐计算的 bug。(感谢:@williballenthin)
* 2021-08-19: v1.6.0 - 修复了在加载 ELF 段/节期间发生的截断 bug。现在也能解析 ELF 文件中的 API 用法了!(感谢:@williballenthin)
* 2020-10-30: v1.5.0 - PE 节表现在已包含在 SmdaReport 中,并添加了 `SmdaReport.getSection(offset)`。
* 2020-10-26: v1.4.0 - 添加 SmdaBasicBlock。一些旨在简化与 capa 集成的便捷代码。(GeekWeek 版!)
* 2020-06-22: v1.3.0 - 添加了 DominatorTree(由 Armin Rigo 实现)以计算函数嵌套深度,将 PIC 哈希缩短为 8 字节,为 InstructionEscaper 添加了一些缺失的指令,IdaInterface 现在会对名称进行解码(demangle)。
* 2020-04-29: v1.2.0 - 将 config.py 重构为 smda/SmdaConfig.py 以简化使用,现已可通过 PyPI 获取!smda/Disassembler.py 现在会发出一个报告对象 (smda.common.SmdaReport),允许直接(以 Python 风格)与结果交互 - 通过在报告上使用 toDict() 仍然可以轻松生成 JSON。
* 2020-04-28: v1.1.0 - 几项改进,包括:x64 跳转表处理,改进了对使用寄存器和尾调用的数据流处理,基于更多真实数据(groundtruth)扩展了常见函数序言(prologue)列表,扩展了用于间隙函数发现的填充指令列表,调整了候选优先级评分中的权重,基于节表过滤了代码区域,将导出的符号用作候选,添加了新的函数输出元数据:基于指令助记符直方图的置信度分数,基于转义后的二进制指令序列的 PIC 哈希
* 2018-07-01: v1.0.0 - 初始发布版本。
如需了解完整的早期历史,请查看 `version_history.md`。
## 致谢
感谢 Steffen Enders 对本项目做出的巨大贡献!
感谢 Paul Hordiienko 添加了符号解析支持(ELF+PDB)!
感谢 Jonathan Crussell 帮助我极大地增强了 SMDA,使其成为 capa 中的反汇编后端!
感谢 Willi Ballenthin 改进了对 ELF 文件的处理,包括正确处理 API 用法!
感谢 Daniel Enders 对解析 Golang 函数注册表和标签信息做出的贡献!
本项目使用了由 Bas Westerbaan 编写的 Tarjan 算法实现,以及由 Armin Rigo 编写的用于 DominatorTree 的 Lengauer-Tarjan 算法实现。
感谢 r0ny123 通过 ruff 对代码质量的重大改进,以及对本项目多个方面做出的各种贡献!
欢迎提交 Pull request!:)
标签:Capstone, DAST, 二进制分析, 云安全运维, 云资产清单, 反汇编器, 安全规则引擎, 恶意软件分析, 控制流图, 逆向工具, 逆向工程