跳转至

Rust 二进制依赖元数据

inspect_rust_binary / inspect-rust-binary 用于回答 cargo-auditable 在选定的本地可执行文件或库中嵌入了哪些 crate 名称、版本、来源和依赖边。它读取文件而不运行它,并且不需要安装 Rust、活动的二进制目标、Hopper、Ghidra 或 IDA。

rea inspect-rust-binary /absolute/path/to/application --json

CLI 相对于调用方的工作目录解析相对路径。MCP 需要绝对文件系统路径,并保留该确切选择:

{
  "name": "inspect_rust_binary",
  "arguments": { "path": "/artifacts/application" }
}

观察结果

完整交付仍是默认行为。对于依赖相关问题,应在首次调用时选择所需记录,而不是返回完整图:

{
  "name": "inspect_rust_binary",
  "arguments": {
    "path": "/artifacts/application",
    "view": {
      "collection": "packages",
      "names": ["serde", "serde_derive"],
      "fields": ["name", "version", "source", "dependencies"]
    }
  }
}

detail: "summary" 返回节范围、根索引、包/边/环计数以及编译器哈希计数。view 会自动选择紧凑交付;将其与显式的 detail: "complete" 结合使用属于输入错误。完整的父 Evidence 会保留在 MCP 会话中,并保持可导出状态。后续的 inspect_analysis_view 调用可接受该 parent_evidence_id 或其可移植的 Evidence 文件,而无需重新打开二进制文件:

{
  "source": {
    "kind": "retained-evidence",
    "evidence_id": "ev_<parent digest>"
  },
  "view": {
    "kind": "rust",
    "collection": "edges",
    "from_indices": [12],
    "limit": 20
  }
}

包过滤器接受精确的 names、versions 和原始 indices;边过滤器接受原始边的 indices、from_indices 和 to_indices。过滤器取交集,空的过滤器数组不选择任何内容。offset 对匹配记录计数;limit 默认为 64。分页保留作用域于父 Evidence 的原始索引、所选字段、已检查的覆盖范围以及下一个偏移量。默认包字段省略依赖向量;显式选择 dependencies 可获得直接引用。不会遍历任何依赖路径。

CLI 使用相同的视图,并要求紧凑交付使用专用的输出包,以便完整的 Evidence 在进程退出后仍然存在:

rea inspect-rust-binary /artifacts/application --json \
  --view '{"collection":"packages","names":["serde"],"fields":["name","version"]}' \
  --evidence_output /artifacts/rust-evidence.json

紧凑结果区分完整的嵌入记录覆盖与未知的运行时依赖覆盖。缺失的节保持未知状态,而不是空的依赖集。保留的视图描述所捕获产物的摘要;它们不断言当前文件或正在运行的应用程序未发生变化。

ELF 节名称通过节头字符串表解析。Zlib 压缩的名称表在原生结构预算内解码。如果名称表使用不支持的压缩,结果会报告该限制,并将 .dep-v0 的存在性保持为未知,而不是报告该节不存在。

内联 Evidence 结果包含产物路径、SHA-256、字节长度、容器格式、架构、字长和字节序。当存在 .dep-v0 节时,auditable_metadata 包含:

  • section_name,对于 ELF 和 PE 为 .dep-v0,对于 Mach-O 为 __DATA,.dep-v0;
  • file_offset 和 section_bytes,即所选产物中依赖节的精确文件范围,包括可接受的 PE 文件对齐字节;
  • compressed_bytes,用于膨胀比限制的 zlib 流长度,以及 uncompressed_bytes;
  • format_version,嵌入的整数,字段省略时为 null;
  • packages,按节的原始顺序,包含 name、version、source、kind、dependencies、features 和 root;
  • root_package_index,标记为 root 的单个包,未标记任何包时为 null;
  • dependency_edges,按包后跟依赖顺序排列的包索引对;
  • cyclic_dependency_indices,参与环的排序后的唯一索引。

省略的 kind 保持为 null。嵌入格式将该省略视为运行时,且该默认值不存储在节中。省略的依赖列表为空数组。省略的 features 字段为 null,因为它无法确定功能列表是空的还是生产者未记录它们;显式的空数组则确立空列表。省略的 root 标志为 false。

历史上 cargo-auditable 0.4 包记录 可能包含包的 features 列表;REA 保留这些字符串。该版本在序列化时省略了空的功能列表,而 0.5 版本完全移除了该字段,如其 变更日志 所述。

rustc_commit 仅在只读数据中找到 /rustc/<40-hex>/ 路径时存在;其 evidence_kind 为 inferred。对于 ELF,只读的非可执行 PT_LOAD 文件范围会与只读节一起被搜索,因此,即使可选的节头表缺失,该搜索来源也不会被移除。空的或不可用的节名称不会抹除节的经验证的只读范围:ELF 将 节名称索引 与其类型和标志分开定义,而 字符串表索引零 表示没有名称。REA 将已知的空名称与不可用的名称分开保留;不可用的名称表仍会使 .dep-v0 的存在性保持未知。该哈希并不声称该编译器生成了此二进制文件。多个不同的哈希会使单个提交保持未知。

限制与失败

所选文件限制为 256 MiB。依赖节的 zlib 流压缩后限制为 1 MiB。膨胀后的 JSON 限制为 8 MiB 与压缩流长度 64 倍两者中的较小值。完整报告限制为 8 MiB。空节、截断的流、zlib 流之后的非填充字节、无效的 JSON、重复的对象字段、未知字段、超出包列表的依赖索引、多个根包以及压缩的依赖节都属于类型化失败。环会被报告,但不会被遍历。

对于 VirtualSize 为零的 PE 映像,原始大小回退可能包含文件对齐字节。REA 仅在原始节大小等于 zlib 流长度向上取整到声明的 FileAlignment 时才排除零后缀;非零或过大的后缀以及截断的流仍被视为失败。

缺失节返回成功,并附带 auditable_metadata: null 和一个限制。缺少 .dep-v0 并不意味着该二进制文件没有依赖项。未知的嵌入式格式修订版保留在 format_version 中,并按照 cargo-auditable 模式使用已知的最高前序修订版进行解释。输出包含一个限制,指明此回退,并注明该特定修订版尚未经过独立验证。省略的修订版保持 null,并遵循修订版 0 的语义。嵌入式名称和版本是文件内容,它们不认证包或编译器。

ELF、PE、瘦 Mach-O 以及通用 Mach-O 中选定的一个切片是受支持的容器。通用(FAT)Mach-O 需要 architecture(x86、x86_64、arm 或 arm64;CLI --architecture)。REA 读取自己的 FAT 表,无需 lipo,并根据该表验证所选切片的范围、对齐方式以及 Mach-O 头部的 CPU。结果将通用文件保留为 artifact(其 SHA-256 和大小),添加 selected_slice,其中包含切片偏移量、长度、原始 CPU 类型/子类型以及 FAT 表摘要,并将节偏移量和 rustc 路径偏移量报告为该切片内的文件偏移量。如果没有 architecture,或者文件没有此类切片或有多个切片,则请求会在 architecture 上失败,并列出现有的切片。任何其他映像上的 architecture 会被拒绝,而不是被忽略。

在分配图或克隆模式之前,会根据最低要求的 JSON 表示来检查包和依赖项计数。过大的图会报告输出字节预算;编译器路径容量以哈希数报告 maximum_rustc_hashes,独立于字节限制。

读取器的架构名称在报告中保持原样。证据主体使用已识别的规范家族:386 映射到 x86,amd64 映射到 x86_64,ppc 映射到 powerpc。未知家族(如 ppc64)保持未知,而不是从相关拼写推断出。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 rea2/rea