akn-cybersec/binja

GitHub: akn-cybersec/binja

一款轻量级的纯命令行 ELF 二进制分析与 patch 工具,内置反汇编、交叉引用、ROP 查找和保护机制检测,专为逆向工程和 CTF 场景设计。

Stars: 5 | Forks: 1

# binja — ELF 文件分析工具 ``` ██████╗ ██╗███╗ ██╗ ██╗ █████╗ ██╔══██╗██║████╗ ██║ ██║██╔══██╗ ██████╔╝██║██╔██╗ ██║ ██║███████║ ██╔══██╗██║██║╚██╗██║██ ██║██╔══██║ ██████╔╝██║██║ ╚████║╚█████╔╝██║ ██║ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚════╝ ╚═╝ ╚═╝ ELF Binary Analysis & Patching Tool ``` 这是一款专为逆向工程师、二进制漏洞利用开发者和 CTF 选手打造的轻量级、纯粹 ELF 分析工具。没有臃肿的代码,没有 GUI,也不依赖 libelf —— 只有原生的 ELF 解析、基于 Capstone 的反汇编,以及一个简洁的交互式 REPL。 ## 目录 - [快速开始](#quick-start) - [功能](#features) - [安装与构建](#installation--build) - [用法](#usage) - [交互模式](#interactive-mode) - [命令行模式](#command-line-mode) - [命令参考](#command-reference) - [示例与工作流](#examples--workflows) - [架构与内部机制](#architecture--internals) - [项目结构](#project-structure) - [局限性](#limitations) - [故障排除](#troubleshooting) - [与其他工具的对比](#comparison-to-other-tools) - [贡献](#contributing) - [安全声明](#security-notice) - [许可证](#license) ## 快速开始 ``` # Build git clone https://github.com/akn-cybersec/binja cd binja && sudo make # 进入交互式 REPL ./binja ./target_binary # 一次性命令 ./binja ./target_binary info ./binja ./target_binary disas main ./binja ./target_binary strings 6 ``` CTF 二进制文件的常见工作流: ``` binja> info binja> functions binja> disas vuln_func binja> xrefs 0x401234 binja> patch 0x401200 9090 binja> rop find --ret ``` ## 功能 | 功能 | 描述 | |---|---| | 🔍 **ELF 解析** | 手动解析 header、section、segment 和符号表 —— 零 libelf 依赖 | | 📝 **反汇编** | 通过 Capstone 引擎进行 x86/x86-64 反汇编 | | 🔗 **交叉引用查找** | 扫描 `.text`,查找操作数匹配目标地址的 `call`/`jmp`/`mov`/`j*` 指令 | | 💾 **二进制 Patch** | 支持内存和磁盘 Patch,并自动创建 `.bak` 备份 | | 📊 **保护机制分析** | 检测 NX、PIE、Stack Canary(基于符号)和 RELRO(none/full) | | 📜 **字符串提取** | 从 `.rodata` 和 `.data` 中提取可打印字符串 | | 🎮 **交互式 REPL** | 持久化的命令历史记录(在磁盘上的历史文件中包含时间戳),保存至 `.binja_history` | | 🎮 **ROP Gadgets 查找器** | 扫描可执行 section 以查找以 `ret` 或 `syscall` 结尾的 gadgets;支持按类型过滤(`--pop`、`--mov`、`--syscall`),自动构建链,并导出 Python exploit | | 🔲 **十六进制转储** | 以十六进制 + ASCII 格式转储任意 section,支持可选的 offset 和 length | | 📋 **Section/Segment 列表** | 显示所有 ELF section 和程序头及其标志和权限 | ## 安装与构建 ### 依赖 - Linux x86-64 - 支持 C++17 的 GCC 或 Clang - [Capstone](http://www.capstone-engine.org/) 反汇编框架 - GNU Make ### 安装 Capstone **Arch Linux:** ``` sudo pacman -S capstone ``` **Ubuntu / Debian:** ``` sudo apt-get install libcapstone-dev ``` **从源码构建:** ``` git clone https://github.com/capstone-engine/capstone cd capstone && ./make.sh && sudo make install ``` ### 构建 binja ``` # 优化的 release build (-O2) make # Debug build (-g -O0 -DDEBUG,然后进行一次 clean rebuild) make debug # 清理 build artifacts make clean # 列出可用的 Makefile targets make help ``` 生成的二进制文件是 `./binja`。无需安装步骤 —— 在项目目录中直接运行它,或将其复制到您的 `$PATH` 中。 ## 用法 binja 有两种操作模式:**交互式**和**命令行**。 ### 交互模式 通过传入二进制文件路径来启动并进入 REPL: ``` ./binja ./target_binary ``` ``` ╔════════════════════════╗ ║ BINJA ║ ╚════════════════════════╝ Binary: ./target_binary Type 'help' for available commands, 'exit' to quit binja> _ ``` REPL 会将每条命令追加到当前工作目录下的 `.binja_history` 文件中,每条记录都带有时间戳,并在下次启动时重新加载该文件,以便历史扩展(`!!`、`!5`)在跨会话时仍然有效。`history` 命令本身仅按索引列出当前会话中的命令 —— 它不会打印时间戳(时间戳仅存在于磁盘上的 `.binja_history` 文件中)。 **历史扩展:** | 简写 | 操作 | |---|---| | `!!` | 重复上一条命令 | | `!5` | 重复执行历史记录中的第 5 条命令 | | `history` | 显示当前会话的命令历史记录(无时间戳) | **信号处理:** `Ctrl+C` **不会**退出程序 —— 它只会打印 `Type 'exit' to quit` 并重新绘制提示符。请使用 `exit` 或 `quit`(或 Ctrl+D / 空行)来退出程序。 ### 命令行模式 以非交互方式运行单个命令 —— 这对于脚本编写和管道输出非常有用: ``` ./binja ./binary info ./binja ./binary functions ./binja ./binary disas main ./binja ./binary strings 6 ./binja ./binary xrefs 0x401234 ``` ### 命令参考 #### `info` 显示 ELF 元数据:入口点、架构、字节序、已知 section 名称列表,以及检测到的二进制保护机制。 ``` binja> info Entry point: 0x401080 Architecture: x86-64 Endianness: little Sections: .text, .rodata, .data, .bss, .symtab, .strtab, .shstrtab, .comment, .note.gnu.build-id, .eh_frame... Protections: NX: yes, PIE: no, Canary: no, RELRO: none ``` #### `functions` 列出所有函数符号及其虚拟地址和大小,并按地址排序。 ``` binja> functions 0x00401080 _start 0x004010b0 __libc_csu_init (size: 101) 0x00401156 main (size: 78) 0x004011a4 vuln (size: 63) 0x004011e3 win (size: 31) ``` 如果二进制文件中没有 `.symtab`/`.dynsym` FUNC 条目,它将打印 `No functions found (binary may be stripped)`。在这种情况下,请使用 `disas 0x
` 直接通过地址进行反汇编。 #### `strings [min_len]` 仅从 `.rodata` 和 `.data` 中提取可打印字符串。默认的最小长度为 4。输出仅为原始字符串,每行一个 —— 没有地址或 section 标签。 ``` binja> strings 6 Enter your name: Hello, %s! cat /flag /bin/sh ``` #### `disas ` 通过函数名(在符号表中查找)或十六进制地址对函数进行反汇编。在内部,这总是会定位包含它的 `.text` section,因此对于不在 `.text` 中的函数(例如在 `.init`/`.plt` 中)目前无法正确反汇编。 ``` binja> disas vuln 0x004011a4: push rbp 0x004011a5: mov rbp, rsp 0x004011a8: sub rsp, 0x40 0x004011ac: lea rax, [rbp - 0x40] 0x004011b0: mov rsi, rax 0x004011b3: lea rdi, [rip + 0x84e] 0x004011ba: mov eax, 0 0x004011bf: call 0x401060 0x004011c4: nop 0x004011c5: leave 0x004011c6: ret ``` ``` # 按 address ./binja ./binary disas 0x4011a4 ``` 如果未找到该名称,binja 会将所有已知的函数名称/地址作为建议列表打印出来。 #### `xrefs
` 扫描已反汇编的 `.text` section,查找操作数字符串中包含目标十六进制地址的 `call`、`jmp`、`mov` 或任何 `j*` 助记符指令。地址必须以十六进制格式(`0x...`)给出。 ``` binja> xrefs 0x4011e3 0x401200: call 0x4011e3 0x40123a: jmp 0x4011e3 ``` 如果没有匹配项,binja 会打印 `No cross-references found to 0x...`。请注意,这是针对反汇编后的操作数字符串进行的文本匹配,而不是真正的数据流/重定位分析 —— 它无法捕捉跨多条指令构建的引用(例如 `lea`+`mov` 地址计算)或 `.text` 之外的引用。 #### `patch
` 使用提供的十六进制字节字符串,在内存和磁盘中对给定地址处的二进制文件进行 patch。在首次写入之前,会自动创建原始文件的 `.bak` 备份(交互模式和 CLI 模式都强制开启了备份)。 ``` binja> patch 0x4011bf 9090 Patching at offset 0x11bf (2 bytes) Backed up original to ./vuln.bak Patched 2 bytes at 0x4011bf ``` ``` # 将一条 call 指令 NOP 掉(5 字节) binja> patch 0x4011bf 9090909090 # 覆盖一个 jump condition binja> patch 0x401200 eb0e ``` #### `hexdump
[offset] [length]` — *仅限交互模式* 以十六进制 + ASCII 格式转储 section 数据。offset 和 length 是可选的(默认值:offset `0`,length `256`)。 ``` binja> hexdump .rodata 0 64 0x00000000: 45 6e 74 65 72 20 79 6f 75 72 20 6e 61 6d 65 3a |Enter your name:| 0x00000010: 20 00 48 65 6c 6c 6f 2c 20 25 73 21 0a 00 63 61 | .Hello, %s!..ca| 0x00000020: 74 20 2f 66 6c 61 67 00 2f 62 69 6e 2f 73 68 00 |t /flag./bin/sh.| 0x00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ``` #### `sections` — *仅限交互模式* 列出 binja 已知的所有 ELF section(来自其内部名称映射),包括地址、大小、偏移量和标志。 ``` binja> sections Sections in binary: .text addr=0x0000000000401080 size=0x1a3 offset=0x1080 [EXEC] .rodata addr=0x0000000000402000 size=0x60 offset=0x2000 .data addr=0x0000000000404000 size=0x10 offset=0x3e00 [WRITE] .bss addr=0x0000000000404010 size=0x8 offset=0x3e10 [WRITE] .symtab addr=0x0000000000000000 size=0x240 offset=0x4000 .strtab addr=0x0000000000000000 size=0xe1 offset=0x4240 ``` #### `segments` — *仅限交互模式* 列出程序头及其偏移量、虚拟/物理地址、大小和权限标志。类型名称在打印时不带 `PT_` 前缀(`LOAD`、`DYNAMIC`、`GNU_STACK`、`GNU_RELRO`、`INTERP` 或 `UNKNOWN`)。 ``` binja> segments Program segments: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x000000 0x00400000 0x00400000 0x0002e8 0x0002e8 R 0x1000 LOAD 0x001000 0x00401000 0x00401000 0x0001a3 0x0001a3 R E 0x1000 LOAD 0x002000 0x00402000 0x00402000 0x0000c4 0x0000c4 R 0x1000 LOAD 0x003e00 0x00403e00 0x00403e00 0x00022c 0x00023c RW 0x1000 GNU_STACK 0x000000 0x00000000 0x00000000 0x000000 0x000000 RW 0x10 ``` #### `history` — *仅限交互模式* 按索引显示当前会话的命令历史记录(无时间戳 —— 时间戳仅记录在磁盘上的 `.binja_history` 文件中)。 ``` binja> history Command history: 1 info 2 functions 3 disas vuln 4 xrefs 0x4011e3 5 patch 0x4011bf 9090 ``` #### `help` — *仅限交互模式* 在 REPL 中显示命令参考和用法提示。 #### `exit` / `quit` 正常退出交互模式。 ## 示例与工作流 ### 1. 完整的二进制侦察 ``` ./binja ./challenge binja> info # Entry point, protections binja> sections # Identify interesting sections binja> segments # Check NX (PT_GNU_STACK flags) binja> functions # What's in the symbol table? binja> strings 5 # Any juicy strings? /bin/sh? flag paths? binja> rop find --ret # Any gadgets having ret ``` ### 2. 识别易受攻击的函数及其调用者 ``` binja> functions # 在 0x4011a4 处发现 'vuln' binja> disas vuln # 查看带有固定 buffer 的 scanf —— 典型的 overflow binja> xrefs 0x4011a4 # 查找谁调用了 vuln,追踪执行路径 ``` ### 3. Patch 掉安全检查 ``` binja> disas check_auth # 0x401320: test eax, eax # 0x401322: jne 0x401380 <-- 如果 auth 失败则跳转 # 将 jne (75 XX) patch 为 jmp (eb XX) 以始终执行该分支 binja> patch 0x401322 eb5c binja> disas check_auth # 验证 patch 是否正确应用 ``` ### 4. 为 ret2win 定位 win 函数 ``` binja> functions # 0x4011e3 win (大小: 31) binja> disas win # 确认它调用了 system("/bin/sh") 或类似函数 binja> xrefs 0x4011e3 # 验证它从未被合法调用 —— 纯粹的 overflow 目标 ``` ### 5. 从 crackme 中提取隐藏字符串 ``` binja> strings 8 # 寻找长字符串 —— flags、密码、keys binja> hexdump .rodata # 当你需要 string 周围的原始 bytes 时 ``` ### 6. 使用历史扩展 ``` binja> disas main binja> disas vuln binja> !! # re-runs: disas vuln binja> !1 # re-runs: disas main binja> history # review in-session history ``` ## 架构与内部机制 binja 由四个协作模块构建而成: ``` ┌─────────────────────────────────────────────────────┐ │ main.cpp │ │ CLI dispatch / Interactive REPL │ │ Command history / Signal handling │ └────────────┬──────────────────────┬────────────────┘ │ │ ┌────────▼────────┐ ┌────────▼────────┐ │ elf_parser.cpp │ │ disassembler.cpp │ │ │ │ │ │ ELF64/32 hdr │ │ Capstone init │ │ Section table │ │ x86/x86-64 dis │ │ Program hdrs │ │ xref scanner │ │ .symtab │ └─────────────────┘ │ .dynsym │ │ .strtab │ ┌─────────────────┐ │ String extract │ │ patcher.cpp │ │ Protection det.│ │ │ └─────────────────┘ │ .bak creation │ │ In-memory patch│ │ On-disk write │ └─────────────────┘ ``` **ELF 解析** 完全由手动完成 —— 直接从 `mmap` 映射的文件中读取 `Elf64_Ehdr`、`Elf64_Shdr`、`Elf64_Phdr`、`Elf64_Sym` 结构体(以及 32 位等效结构体,并向上转换为 64 位结构体)。不使用 libelf,不使用 BFD,也没有任何外部解析库。 **反汇编** 通过一个轻量级的 C++ 类封装了 Capstone C API。`cs_open`、`cs_disasm` 和 `cs_close` 负责处理生命周期;xref 扫描器会预先对整个 `.text` section 进行反汇编,然后将每条解码后指令的操作数文本与十六进制的目标地址进行字符串匹配。 **Patch** 使用标准的 `std::fstream` seek/write(`patch_file` 以 `ios::binary | ios::in | ios::out` 方式打开目标文件,`seekp` 到计算出的偏移量,并写入新字节),以在对应于给定虚拟地址的文件偏移量处覆盖字节。该偏移量由 `virtual_to_offset` 计算,它会遍历 `PT_LOAD` segment 以找到匹配的 `p_offset + (vaddr - p_vaddr)` 转换 —— 它不使用 `mmap` 进行写入。 ## 项目结构 ``` binja/ ├── main.cpp # CLI entry point, REPL, command dispatch, history ├── elf_parser.cpp # Manual ELF parsing: headers, sections, symbols, strings, protections ├── disassembler.cpp # Capstone wrapper: disassembly engine, xref scanning ├── patcher.cpp # Binary patching with .bak backup creation ├── elf_parser.h # ElfParser class definition ├── disassembler.h # Disassembler class definition ├── patcher.h # Patcher class definition ├── Makefile # Build system: release / debug / clean / help targets └── README.md ``` ## 局限性 - **仅支持 ELF** —— 不支持 PE (Windows) 或 Mach-O (macOS) - **仅限 x86 / x86-64** —— Capstone 支持其他架构,但 binja 的 section 逻辑目前仅适配了这两种;其他架构会优雅地失败 - **32 位测试有限** —— 已经实现了 32 位 ELF 解析(内部将结构体向上转换为 64 位),但相较于 64 位,其经受的实战测试较少 - **RELRO 检测是二元的** —— `check_protections()` 目前仅报告 `"none"` 或 `"full"`(只要存在 `PT_GNU_RELRO` segment 就会设置为 `full`);目前还没有部分 RELRO 的区分 - **Stack canary 检测基于符号** —— 它会在 `.symtab`/`.dynsym` 中查找 `__stack_chk_fail` 符号,因此对于受 canary 保护但被完全 strip 的二进制文件,可能会出现漏报 - **未暴露 ASLR/exec-stack 字段** —— `ProtectionInfo` 包含 `aslr`/`execstack` 成员,但目前没有任何代码填充或打印它们 - **`xrefs` 是文本匹配,而非真正的数据流分析** —— 它只能捕捉到 `.text` 内 `call`/`jmp`/`mov`/`j*` 指令中作为字面十六进制操作数出现的引用 - **`disas` 被硬编码为 `.text`** —— 未处理 `.text` 之外的函数(PLT 桩、`.init` 等) - **`hexdump`、`sections` 和 `segments` 仅限交互模式** —— 它们尚未接入命令行(单次执行)模式 - **Dynamic section 解析只是个占位符** —— `get_dynamic_entry()` 和 `get_plt_addresses()` 是尚未实现的占位符,总是返回空/零;`get_imported_symbols()`/`get_exported_symbols()` 虽然存在,但尚未通过任何 CLI 命令暴露出来 - **不支持 DWARF 解析** —— 不读取调试信息(文件/行映射);被 strip 的二进制文件仅显示地址 - **无动态分析** —— 仅支持静态分析;无追踪,无模拟 ## 故障排除 | 错误 | 原因 | 解决方法 | |---|---|---| | `Cannot resolve address 0x...` | 地址不在任何 PT_LOAD segment 中 | 使用 `segments` 验证地址;确保二进制文件不是处于 ASLR 激活状态的 PIE | | 未找到函数,打印建议列表 | 二进制文件被 strip,没有 `.symtab`/`.dynsym` FUNC 条目 | 直接使用 `disas 0x
` | | `Capstone init failed` | Capstone 安装缺失或不正确 | 运行 `ldd ./binja` 并检查 `libcapstone.so` 是否解析成功| Patch 时提示 `Permission denied` | 文件是只读的 | 在 patch 前执行 `chmod u+w ./target` | | `.binja_history` 不更新 | 目录不可写 | 从您拥有写权限的目录运行 binja | ## 与其他工具的对比 binja 并不是为了取代 radare2、Ghidra 或 Binary Ninja(商业产品)。它是一款**专注且轻量的 CLI 工具**,专为二进制漏洞利用和 CTF 工作中最常见的特定工作流而设计。 | 功能 | binja | readelf | objdump | radare2 | |---|:---:|:---:|:---:|:---:| | ELF section/segment 列表 | ✅ | ✅ | ✅ | ✅ | | 反汇编 | ✅ | ❌ | ✅ | ✅ | | 符号表列表 | ✅ | ✅ | ✅ | ✅ | | 交叉引用查找器 | ✅ (文本匹配) | ❌ | ❌ | ✅ | | 二进制 Patch(带备份) | ✅ | ❌ | ❌ | ✅ | | 保护机制分析 | ✅ (NX/PIE/Canary/RELRO) | 部分 | ❌ | ✅ | | 带历史记录的交互式 REPL | ✅ | ❌ | ❌ | ✅ | | 字符串提取 | ✅ | ❌ | ✅ | ✅ | | 脚本 / API | ❌ | ❌ | ❌ | ✅ | | 依赖项数量 | 1 (capstone) | 0 | 0 | 许多 | **在以下情况使用 binja:** 您希望在 CTF 中快速获得答案;您正在编写 exploit 脚本并需要快速的单行命令;或者您只是不想等待 radare2 加载。 **在以下情况使用 radare2/Ghidra/Binary Ninja:** 您需要反编译、高级脚本、图形视图、支持部分 RELRO/ASLR 的保护报告,或者需要分析非 ELF 格式。 ## 逆向工程工作流提示 ``` 1. Start with `info` — know your protections before anything else. Remember RELRO here is only ever "none" or "full" right now. 2. `strings` before `disas` — a /bin/sh or a flag path tells you immediately what the intended vector is. 3. Use `xrefs` to trace data flow backward — but remember it's a text match on .text operands, so double-check anything subtle (e.g. address built via lea + separate mov) by hand. 4. Keep patches surgical — NOP the minimum number of bytes, verify with `disas` after every patch. 5. .bak files are sacred — never delete them until the patched binary is confirmed working. ``` ## 贡献 欢迎提交 Bug 报告、功能请求和 Pull Request。 **在提交 PR 之前:** - 确保干净地运行 `make` 和 `make debug` - 至少针对一个真实的 ELF 二进制文件(静态链接和动态链接)进行测试 - 将新增内容保持在相关源文件中自包含 - 符合现有的代码风格(C++17,在不可避免的情况下,避免在 hot path 中使用 STL 容器) **计划的 / 适合作为首个贡献的功能:** - 部分 RELRO 检测(目前简化为了 none/full) - GOT/PLT 表显示(目前的 `get_plt_addresses`/`get_dynamic_entry` 只是占位符) - 将 `hexdump`/`sections`/`segments` 接入命令行(非交互)模式 - 32 位 ELF 测试套件 - DWARF 行信息解析(基础版) - 用于脚本集成的 JSON 输出模式 ## 安全声明 binja 是一款**静态分析和 patch 工具**,其用途仅限于: - 对您拥有或获得明确书面授权的软件进行安全研究 - CTF 挑战 - 在适用法律下为互操作性和漏洞研究进行的逆向工程 未经授权,请勿使用 binja 分析或 patch 二进制文件。对于滥用行为,作者不承担任何责任。 ## Author ## 许可证 MIT 许可证 ``` Copyright (c) 2026 kaizen_dragon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ```
标签:CTF工具, ELF文件, Wayback Machine, 二进制分析, 云安全运维, 云资产清单, 反汇编, 漏洞搜索, 逆向工程