jguida941/binary_to_assembly

GitHub: jguida941/binary_to_assembly

面向初学者的二进制逆向分析教学项目,结合 GNU binutils 工具使用指南与自动化 Python CLI,帮助用户学习拆解 x86-64 ELF 文件并阅读汇编代码。

Stars: 2 | Forks: 0

# 二进制到汇编 拆解已编译的程序:找出其中包含的函数,将机器码还原为汇编,并解释其功能。 编写这份资料是因为布置该任务的课程从未解释过具体操作机制。即该输入哪条命令、在哪里输入以及为什么这样做。 ## 从这里开始 ### **[GUIDE.md](GUIDE.md)**:从头到尾的完整指南 每一条命令、它的作用、为什么运行它、以及输出的含义。这些都是在实际操作过程中记录的,而非事后补充。**这是本仓库的核心内容。** ## 环境设置 你只需要 Docker,不需要其他任何东西。分析工具是 GNU binutils,它们存在于 Linux 上但不在 macOS 上,因此所有内容都在一个与课程环境匹配的固定版本容器中运行:Ubuntu 18.04,gcc 7.5.0,binutils 2.30。 ``` git clone https://github.com/jguida941/binary_to_assembly.git cd binary_to_assembly make build # builds the analysis image, prints its digest. Takes a few minutes once. make examples # compiles the five example programs, three ways each ``` 然后拆解一个程序: ``` make functions FILE=examples/05_functions/build/05_functions make disassemble FILE=examples/05_functions/build/05_functions FUNCTION=report make strings FILE=examples/05_functions/build/05_functions ``` `make help` 会列出所有内容,并且**每个目标在运行前都会打印出它要执行的原始命令**,因此你可以直接复制该命令,随时停止使用 `make`。 ### 如果你正在 Codio 中做作业 你不需要上述任何内容。Codio 已经安装了 `file`、`readelf`、`nm`、`objdump` 和 Bless,并且 [GUIDE.md](GUIDE.md) 正是基于此编写的。该容器是专门用于在你自己的机器上拆解自行编译的程序。 ### 不使用 make 运行 CLI ``` docker run --rm --platform linux/amd64 -v "$PWD:/work" -w /work \ -e PYTHONPATH=/work/src binary-assembly-guide:local \ python3.8 -m binary_assembly_guide.cli functions BINARY ``` 是 `python3.8`,而不是 `python3`:Ubuntu 18.04 的默认版本是 3.6.9,版本太旧,无法解析 CLI。 [`environment/README.md`](environment/README.md) 解释了为什么 image 要固定在旧版 toolchain 上,以及测量了哪些数据来证明它与 Codio 匹配。 ### 运行测试 在宿主机上运行,而不是在容器中,因为它们需要 git,而容器中没有安装。 ``` python3 -m pytest -q # everything python3 -m pytest tests/privacy -q # the guardrail that matters most ``` ## 相关工具及其用途 由四个程序来完成这项工作。每个程序读取同一个文件的不同部分,这就是为什么只用一个工具是不够的。 | 工具 | 它是什么 | 它能告诉你什么 | | --- | --- | --- | | `file` | 根据内容识别文件类型 | 这是否是一个程序,适用于什么 CPU,以及名称是否仍保留在其中 | | `readelf` | 读取 ELF 结构 | `file` 正在汇总的那些 header 字段:类型、entry point | | `nm` | 列出符号表 | 每一个名称,并用一个字母标明它是代码还是数据 | | `objdump` | 反汇编器 | 将机器码解码还原为汇编,以及原始 section 内容 | | Bless | 十六进制编辑器 | 字节本身,以及作为纯文本嵌入其中的名称 | 十六进制编辑器向你展示了函数名*作为文本切实存在于文件中*。但它无法告诉你这些名称中哪个是函数,哪个是变量,哪个是源文件名。`nm` 读取的正是旁边记录这些确切信息的表。`objdump` 读取的则是可执行代码本身。 ## CLI 包含四个命令,分别对应指南所描述工作流程的每一步。 ``` binary-assembly-guide inspect BINARY binary-assembly-guide functions BINARY [--compare OTHER ...] binary-assembly-guide disassemble BINARY FUNCTION [--resolve] binary-assembly-guide strings BINARY [--section .rodata] ``` **`inspect`** 展示文件是什么,以及它是否可以被分析。它会拒绝任何非 x86-64 ELF 的文件并说明原因,而不是盲目给出荒谬的结论。 **`functions`** 列出每一个函数,以及每个函数的编写者。如果通过 `--compare` 提供了其他不相关的二进制文件,它会根据证据而不是记忆的名称列表进行分类:在所有文件中都存在的内容,不是为其中任何一个专门编写的。 **`disassemble --resolve`** 是最值得拥有的功能。它会打印出函数的汇编代码,*并且*查找代码引用的每个地址中实际包含的内容: ``` 400556: lea 0xf7(%rip),%rdi # 400654 400562: callq 4003f0 Addresses this function references: 0x400654 "%s: %d" ``` 手动操作的话,这相当于执行 `objdump -s -j .rodata`,找到正确的行,逐个计算字节偏移,解码十六进制,并在遇到第一个 `00` 时停止。而且要针对每个地址重复此过程。跳过这一步,就会把对程序功能的解释变成干巴巴的机制描述,而永远不提程序到底做了什么。 **`strings`** 展示数据段中的字符串字面量,并进行了正确的分割。objdump 自带的 ASCII 列会将每个不可打印的字节渲染为 `.`,导致字符串连在一起且边界丢失。 [`scripts/`](scripts/) 中的 Shell wrapper 调用的是相同的命令,因此底层工具保持可见,而不是被隐藏在某个程序背后。 **[完整 CLI 指南](docs/using-the-cli.md)**:介绍每一个命令和每一个 flag,并附带各自的实际输出,包括在 stripped binary、Mach-O 文件以及不存在的名称上会发生什么。 ## 练习 五个小型的 C 程序,每个都单独剥离出一种代码结构,并且旁边配有一道书面练习。你拥有这些源代码,因此你可以用已知答案的程序来验证你的解读是否正确。 | 示例 | 结构 | | --- | --- | | [`01_simple_return`](examples/01_simple_return/exercise.md) | prologue、epilogue 和返回值 | | [`02_arithmetic`](examples/02_arithmetic/exercise.md) | 操作数存在于何处,以及哪个 register 携带结果 | | [`03_condition`](examples/03_condition/exercise.md) | `cmp` 加上条件跳转,以及为什么要反转条件 | | [`04_loop`](examples/04_loop/exercise.md) | 向后跳转,以及计数器保存在哪里 | | [`05_functions`](examples/05_functions/exercise.md) | 四个函数、参数 register 以及 call graph | 每个示例提供三种构建方式:`make` 用于生成类似于课程文件的 debug build;`make stripped` 用于查看符号表消失后会发生什么;`make optimized` 用于查看 `-O2` 会对你刚学会阅读的代码产生什么影响。 ## 其他内容 | | | | --- | --- | | [`docs/`](docs/index.md) | 五篇背景知识页面,以及 [故障排除](docs/troubleshooting.md),记录的每一个错误都是真实发生过的 | | [`images/`](images/) | 指南中使用的截图。添加截图前请阅读其 README | | [`environment/`](environment/README.md) | 测量 Codio 与固定版本容器之间的 toolchain 一致性 | | [`dev/PLAN.md`](dev/PLAN.md) | 架构说明,以及构建过程中被证明有误的假设 | ## 状态 对于其所涵盖的内容,已全部完成且可正常运行。指南演示了完整的工作流程,CLI 已针对三个构建变体中的每个示例二进制文件进行了测试,五个示例均可干净地编译,并根据捕获的输出进行了文档记录。 范围特意收窄:**仅限 x86-64 ELF**,如果未 stripped 则会直接告知无法识别任何内容。没有 JSON 输出,也没有 GUI。这里的一切都是我亲自运行并验证过的。 ## 未包含的内容 不包含任何已完成的课程作业,也不提供二进制文件。`inputs/` 和 `outputs/` 已被 gitignore 并保留在本地,且有测试套件强制执行此规则,而不是仅仅依赖 `.gitignore`。这个仓库提供的是方法论,而不是答案。 如果你正在修读这门课程:阅读别人做好的练习手册学不到任何东西,而且你的指导老师一眼就能看出来。提供这些示例是为了让你可以在拥有源代码的程序上进行练习,然后独立完成你自己的文件分析。
标签:Docker, ELF, Python, 二进制分析, 云安全运维, 安全规则引擎, 安全防御评估, 无后门, 汇编, 请求拦截, 逆向分析, 逆向工具