bytew0lf/ELF-Inspector
GitHub: bytew0lf/ELF-Inspector
一个跨平台的 .NET ELF 二进制解析与报告生成工具,支持多架构安全特性分析与 DWARF 调试信息查询。
Stars: 0 | Forks: 0
# ELF-Inspector
[](https://github.com/bytewolf/ELF-Inspector/actions/workflows/ci.yml)
用于 ELF32 和 ELF64 二进制文件(.so、可执行文件等)的 ELF 解析器和报告生成器。
## 环境要求
* .NET SDK 9.0
* `bash`
* `rg` (ripgrep) 是可选的:如果 `rg` 不可用,所有的 CI/测试/覆盖率脚本都会回退到 `grep`
## 功能特性
* ELF32 和 ELF64(大/小端序)
* 数据源解析:InMemory、Stream、MemoryMapped (mmap)
* 针对大文件的核心逻辑使用 `ulong` 偏移量寻址(支持无全局 `int` 缓冲区的 >2GB 偏移量)
* 节和程序头
* 包含版本控制的符号表
* 重定位 (REL/RELA/RELR)
* 动态节以及导入/导出
* GNU/SYSV 哈希表
* Notes
* 强化的 CFI/unwind 解码(未知的/被截断的 CFA 指令会被保留,而不会导致硬中止)
* ET_CORE 线程/寄存器解码,带有评分机制的 `NT_PRSTATUS` 布局选择以及通用的 Linux 回退
* 扩展的 DWARF 语义提示(包括布尔属性),同时保留未知的形式
* 具备 函数→类型→范围 链接并保留未解析类型引用的 DWARF 查询模型
* ET_CORE unwind 策略指标(`CFI`、帧指针、链接寄存器、栈扫描 比例)
* 针对架构特定值的扩展映射覆盖(包括 MIPS REGINFO 节/段名称)
* 报告中的安全/加载器特性(PIE、RELRO、NX、BIND_NOW、canary/FORTIFY 提示)
## 当前覆盖率映射(自动生成)
状态图例:
* `full`:已实现,并被单元/矩阵测试覆盖
* `partial`:已实现,但仅被测试部分覆盖
* `open`:尚未实现
### 解析器/报告覆盖率
| 区域 | 状态 | 当前覆盖率 |
|---|---|---|
| ELF Header | full | ELF32/ELF64, 字节序, 类型, 机器, 入口点 |
| Section Headers | full | 标准 + 扩展编号, 节名称解析 |
| 节特殊情况 | full | `SHF_COMPRESSED` (ZLIB + ZSTD), GNU `.zdebug*` (ZLIB + ZSTD), `SHT_GROUP`/COMDAT |
| Program Headers | full | PT_LOAD/PT_DYNAMIC/PT_INTERP/PT_NOTE 包括解释器解析 |
| Dynamic | full | DT_NEEDED, SONAME, RPATH/RUNPATH, FLAGS/FLAGS_1, REL/RELA/RELR 标签, GNU 版本标签 |
| 符号表 | full | `.symtab`/`.dynsym`, 无节头表时的回退处理, 导入/导出分类 |
| 符号版本控制 | full | `DT_VERSYM`, `DT_VERNEED`, `DT_VERDEF` 包括库/版本映射 |
| 重定位 | full | 来自节和动态标签的 REL/RELA/RELR, 报告中的符号/节映射 |
| 每种架构的重定位类型名称 | full | i386, x86_64, ARM, AArch64, MIPS, PPC/PPC64, S390x, SPARC, RISC-V 及扩展的类型名称映射 |
| 哈希表 | full | `DT_HASH` 和 `DT_GNU_HASH` (桶/链/布隆过滤器), 可配置的查找路径评估 |
| Notes | full | `SHT_NOTE`/`PT_NOTE`, GNU/FDO/Go/FreeBSD/NetBSD/OpenBSD/Android/Linux 命名空间及基础解码 |
| Unwind | full | `.eh_frame`/`.eh_frame_hdr`, CIE/FDE 解析, CFA 规则, 容错处理未知/被截断的操作码, CFI 优先的核心栈回溯 + 策略指标 |
| DWARF/调试 | full | 针对 `.debug_info/.abbrev/.line/.str/.ranges/.addr/.str_offsets/.rnglists/.loclists` 的索引 + 部分语义,包括 enum/bool 提示,可查询的 函数→类型→范围 链接,以及稳健的未知项保留 |
| ET_CORE | full | 基于 `PT_NOTE` 的 进程/线程/寄存器/信号 评估,带有评分机制的 `NT_PRSTATUS` 布局选择,线程 unwind 分支,以及 unwind 比例指标 |
| 安全/加载器特性 | full | PIE, RELRO (partial/full), NX (GNU_STACK), BIND_NOW, canary/FORTIFY 提示 |
| 文本报告 | full | 确定性输出, 包括 hash/security 在内的结构化节 |
更新覆盖率映射:
```
scripts/generate_coverage_map.sh --write-readme
```
从黄金报告生成回退/GAP 指标:
```
scripts/generate_gap_metrics.sh
```
GAP 指标包括用于映射、动态标签/值解码以及 note 类型/描述符解码的通用回退计数器。
验证 CI 使用的回退/GAP 阈值:
```
scripts/verify_gap_metrics.sh
```
### 架构样本覆盖 (`samples/`)
| 架构 | 样本 |
|---|---|
| x86_64 | `hello_x86_64` |
| i386 | `hello_i686` |
| ARM64 | `hello_arm64`, `nano` |
| ARM32 | `hello_armhf` |
| MIPS 家族 | `hello_mips`, `hello_mipsel`, `hello_mips64`, `hello_mips64el`, `hello_mipsisa32r6el`, `hello_mipsisa32r6`, `hello_mipsisa64r6`, `hello_mipsisa64r6el` |
| PowerPC | `hello_ppc`, `hello_ppc64le` |
| S390x | `hello_s390x` |
| SPARC64 | `hello_sparc64` |
| RISC-V | `hello_riscv64` |
| 其他真实环境二进制文件 | `busybox`, `nano` |
### 测试覆盖率
| 级别 | 状态 | 执行 |
|---|---|---|
| 单元测试 | full | `scripts/run_unit_tests.sh` |
| 负面解析器测试 | full | 包含在单元测试中 + `scripts/run_p3_test_matrix.sh` |
| 黄金报告回归 | full | `scripts/verify_golden_reports.sh` |
| 特性矩阵 (RELR/flags/mapping) | full | `scripts/run_p4_test_matrix.sh` |
| 针对参考工具的差异检查 | full | `scripts/run_differential_checks.sh` (如果不存在 `readelf`/`eu-readelf`/`llvm-readelf` 则跳过) |
| 本地 CI 门禁 | full | `scripts/run_ci_gate.sh` |
### 刻意在当前范围之外的内容
* 不包含反汇编/指令分析
* 不包含对所有架构特定重定位子类型的完整覆盖
* 不包含像真正的动态加载器那样的符号化运行时绑定
* 不包含完整的 DWARF 语义评估(所有 DIE 类型/属性,完整的查询引擎)
* 不包含针对任意 CFI 指令集的完整跨架构 unwind 模拟
## 使用 Docker 构建样本
`build-samples_with_docker.sh` 脚本会在 `samples/` 目录下构建架构样本,并额外提取 `nano` (Debian) 和 `busybox` (Alpine)。
默认调用方式:
```
./build-samples_with_docker.sh
```
可选的环境变量:
* `SAMPLES_DIR`:生成样本的目标目录(默认:`/samples`)
* `DEBIAN_IMAGE`:用于交叉编译器 + `nano` 的 Debian 镜像(默认:`debian:trixie`)
* `ALPINE_IMAGE`:用于 `busybox` 的 Alpine 镜像(默认:`alpine:latest`)
使用自定义镜像的示例:
```
SAMPLES_DIR="$PWD/samples" \
DEBIAN_IMAGE="debian:latest" \
ALPINE_IMAGE="alpine:latest" \
./build-samples_with_docker.sh
```
## 使用方法
如果缺少 `samples/nano` 或其他样本二进制文件,请先运行 `./build-samples_with_docker.sh`(参见 `使用 Docker 构建样本` 章节)。
```
dotnet run --project ELF-Inspector.csproj -- \
--file samples/nano \
--output report.txt \
--output-path samples
```
可选参数,用于生成可复现的输出:
```
dotnet run --project ELF-Inspector.csproj -- \
--file samples/nano \
--output report.txt \
--output-path samples \
--deterministic
```
可选参数,用于宽松的头验证(针对遗留/不符合规范的 ELF 头):
```
dotnet run --project ELF-Inspector.csproj -- \
--file samples/nano \
--output report.txt \
--output-path samples \
--compat-header-validation
```
## 安全强化默认设置
最近的解析器强化更改影响了压缩节的解码:
* 外部 `zstd` 进程回退现在默认被禁用。
* 如果启用了外部回退,`ExternalZstdToolPath` 必须是绝对路径(不进行 `PATH` 查找)。
* 原生 `libzstd` 加载现在仅使用绝对候选路径(不使用非限定库名称加载)。
* ZLIB 和 external-ZSTD 解压输出现在通过带有硬性安全上限的流式传输,以防止无限增长的内存消耗。
P1 强化更新:
* 解析器条目计数安全门现在将在 节头、程序头、动态表、符号/版本表、重定位表和节组 中遵循 `ElfParseOptions.MaxParserEntryCount`。
* 输入大小安全门现在将在 文件、流、span 以及内部数据源解析入口点 中遵循 `ElfParseOptions.MaxInputBytes`。
* NOTE 解析现在会强制执行 `ElfParseOptions.MaxNoteCount`,并在超出限制时以受控的解析错误失败。
* NOTE 去重现在通过 SHA-256 指纹而不是完整的描述符十六进制负载来作为键,以降低内存放大风险。
额外的解析器安全限制可以在 `ElfParseOptions` 中配置:
* `MaxInputBytes`(默认 `4 GiB`,设为 `0` 禁用)
* `MaxParserEntryCount`(默认 `1,000,000`,设为 `0` 禁用)
* `MaxNoteCount`(默认 `100,000`,设为 `0` 禁用)
* `MaxStringTableStringBytes`(默认 `65,536`,设为 `0` 禁用)
P2 强化更新:
* 字符串表条目解码现在会将每次条目的读取截断在 `MaxStringTableStringBytes` 范围内。
* 内存映射读取会在进行指针运算之前,根据平台指针范围验证 `offset`。
当达到限制时,解析将抛出 `InvalidDataException` 中止,并且不会在部分可信状态下继续执行。
示例:
```
var options = new ElfParseOptions
{
EnableExternalZstdToolFallback = true,
ExternalZstdToolPath = "/usr/bin/zstd",
MaxInputBytes = 4UL * 1024UL * 1024UL * 1024UL,
MaxParserEntryCount = 1_000_000UL,
MaxNoteCount = 100_000,
MaxStringTableStringBytes = 65_536UL
};
var elf = ElfReader.Parse("samples/nano", options);
```
## 黄金报告 (P0)
生成基线报告:
```
scripts/generate_golden_reports.sh
```
该脚本会自动发现 `samples/` 中的 ELF 二进制文件,并将 `report-.txt` 文件写入 `samples/golden/`。
根据基线验证生成的输出:
```
scripts/verify_golden_reports.sh
```
验证器在执行差异比较之前,会规范化特定于环境的元数据(例如绝对 `File:` 路径),因此 CI 运行和本地运行的结果仍然具有可比性。
## P3 测试矩阵
运行正面/负面的解析器强化检查:
```
scripts/run_p3_test_matrix.sh
```
## P4 测试矩阵
运行高级特性检查(RELR、重定位映射、动态标志解码):
```
scripts/run_p4_test_matrix.sh
```
## 差异检查
针对可用的参考工具(`readelf`、`eu-readelf`、`llvm-readelf` 或 `greadelf`)运行解析器输出对比,检查选定的确定性字段:
```
scripts/run_differential_checks.sh
```
在 macOS/Homebrew 上的可选步骤:
```
READELF_TOOL=/opt/homebrew/opt/binutils/bin/greadelf scripts/run_differential_checks.sh
```
## P0 一致性矩阵
运行严格/兼容的头一致性和确定性变异冒烟测试:
```
scripts/run_p0_conformance_matrix.sh
```
## 单元测试
运行解析器单元测试(正样例扫描 + 基于负样例的变异):
```
scripts/run_unit_tests.sh
```
## 构建说明
* 公共 API 现已包含 XML 文档注释,并且项目在生成 XML 文档时不会产生 `CS1591` 警告。
* 项目配置中启用了可空注释(`annotations `),这消除了可空引用注释的 `CS8632` 警告。
## CI 门禁
在本地运行完整的质量门禁(单元测试 + P0/P2/P3/P4 矩阵 + 差异检查 + 覆盖率/GAP 漂移检查):
```
scripts/run_ci_gate.sh
```
## 手动发布工作流
一个手动 GitHub 工作流会在构建和测试成功后发布一个版本:
* 工作流文件:`.github/workflows/release-manual.yml`
* 触发方式:`Actions` -> `Manual Release` -> `Run workflow`
* 必填输入:`tag`(例如 `v1.5.0`)
* 可选输入:`release_name`、`draft`、`prerelease`
* 已发布的产物:附加到 GitHub Release 的 `linux-x64`、`osx-arm64`、`win-x64` 压包
标签:DAST, DWARF, ELF, ELF解析器, Hakrawler, NX, PIE, RELRO, URL发现, 二进制分析, 云安全运维, 云资产清单, 内存映射, 动态链接库, 堆栈保护, 安全检测, 底层数据解析, 恶意软件分析, 核心转储, 漏洞分析, 编译原理, 网络安全, 请求拦截, 路径探测, 逆向工程, 隐私保护