bytew0lf/ELF-Inspector

GitHub: bytew0lf/ELF-Inspector

一个跨平台的 .NET ELF 二进制解析与报告生成工具,支持多架构安全特性分析与 DWARF 调试信息查询。

Stars: 0 | Forks: 0

# ELF-Inspector [![构建](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/c19496e1f9230404.svg)](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发现, 二进制分析, 云安全运维, 云资产清单, 内存映射, 动态链接库, 堆栈保护, 安全检测, 底层数据解析, 恶意软件分析, 核心转储, 漏洞分析, 编译原理, 网络安全, 请求拦截, 路径探测, 逆向工程, 隐私保护