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, 二进制分析, 云安全运维, 云资产清单, 反汇编器, 安全规则引擎, 恶意软件分析, 控制流图, 逆向工具, 逆向工程