warpedatom/OffsetScan

GitHub: warpedatom/OffsetScan

OffsetScan 是一款 Rust 原生的大规模 PE 文件静态分析引擎,用于替代 PowerShell 工具进行高效的语料库级恶意软件样本分诊与 IOC 提取。

Stars: 1 | Forks: 0

# OffsetScan

OffsetScan — native corpus-scale static-triage engine

[![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/warpedatom/OffsetScan/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) 一个独立的、原生的、语料库规模的 [OffsetInspect](https://github.com/warpedatom/OffsetInspect) 配套工具。 OffsetInspect 的静态分流辅助工具(`Get-OffsetPEInfo`、`Get-OffsetEntropy`、`Get-OffsetString`、`Get-OffsetIOC`)是跨平台的 PowerShell,在单文件交互式分析中表现优异。OffsetScan 的存在是为了应对另一端的工作负载:**数千个文件**,在这种情况下,PowerShell 每个文件的处理开销会不断累加,而一个并行的、无 GC 的原生核心则能体现其价值。 OffsetScan 不会触碰 AMSI 或 Microsoft Defender —— 这部分仍然是 Windows 独有的功能,并保留在 OffsetInspect 中。OffsetScan 只负责只读的、跨平台的静态分析层:PE 解析、熵、字符串提取、哈希以及(可选的)YARA 匹配。 ## 设计契约 每个 OffsetScan 的输出结构体(`src/schema.rs`)都逐字段映射对应的 OffsetInspect PowerShell 对象,因此这两个工具在 JSON 层面是可以互换的: | OffsetScan (Rust) | OffsetInspect (PowerShell) 对应项 | | ------------------------------- | ---------------------------------------- | | `offsetscan pe` | `Get-OffsetPEInfo` | | `offsetscan entropy` | `Get-OffsetEntropy` | | `offsetscan strings` | `Get-OffsetString` | | `offsetscan ioc` | `Get-OffsetIOC` | | `offsetscan yara` (feature-gated) | `Invoke-OffsetYaraScan` | 结构体定义已经与权威的 `docs/OUTPUT-SCHEMA.md` 以及真实的 OffsetInspect 3.x 对象进行了逐字段验证,并在运行时进行了交叉检查:对于同一个文件,`offsetscan ioc` 和 `Get-OffsetIOC` 会生成完全相同的面板 —— **包括 imphash**。序列化的字段名称(`MD5`/`SHA1`/`SHA256`/`IsPE`/`IsPE32Plus`)已通过单元测试锁定,因此互换契约不会悄无声息地发生偏移。 ### 已验证的一致性 这两个引擎针对同一个文件会生成相同的 IOC 面板 —— 这是在运行时对同一个 Windows 系统 DLL 进行捕获的结果。 `offsetscan ioc C:\Windows\System32\kernel32.dll`: ``` [ { "File": "C:/Windows/System32/kernel32.dll", "FileSize": 836232, "MD5": "46e3ab50afcb6d871b70676f562e01ce", "SHA1": "732af3ed087e2033d7e7ccaa0f4498deb2e46e8c", "SHA256": "26410f4948e0ed66936880596e2b5a59efce481a7c97086049b385f00325c341", "OverallEntropy": 6.361191, "HighEntropyWindows": 25, "PrintableStringCount": 5665, "IsPE": true, "Machine": "x64 (AMD64)", "ImpHash": "a6c6d5a8f6e13c556e2c3fbc4a3dc407", "ImportedDllCount": 104, "HasOverlay": true, "OverlaySize": 17032 } ] ``` `Get-OffsetIOC C:\Windows\System32\kernel32.dll | ConvertTo-Json`: ``` { "File": "C:\\Windows\\System32\\kernel32.dll", "FileSize": 836232, "MD5": "46e3ab50afcb6d871b70676f562e01ce", "SHA1": "732af3ed087e2033d7e7ccaa0f4498deb2e46e8c", "SHA256": "26410f4948e0ed66936880596e2b5a59efce481a7c97086049b385f00325c341", "OverallEntropy": 6.361191, "HighEntropyWindows": 25, "PrintableStringCount": 5665, "IsPE": true, "Machine": "x64 (AMD64)", "ImpHash": "a6c6d5a8f6e13c556e2c3fbc4a3dc407", "ImportedDllCount": 104, "HasOverlay": true, "OverlaySize": 17032 } ``` 每一个字段值都匹配,包括 imphash 和精确到小数点后六位的熵。唯一的区别在于序列化的表现形式:OffsetScan 总是将结果包装在数组中(这是其 JSON 模式的约定,即使只有一个文件也是如此),并将路径分隔符统一为 `/`,而 `ConvertTo-Json` 则输出带有 Windows `\` 路径的纯粹对象。 字符串提取是作为集合进行比较的,而不仅仅是比较数量。对于 `ntdll.dll`(2,517,928 字节),`offsetscan strings` 和 `Get-OffsetString` 都返回了 **32,506** 个匹配项,并且在偏移量、编码和值上完全一致 —— 没有任何一个引擎出现独有的条目。 复现这一点时有一个注意事项:`Get-OffsetString` 默认按 1 MiB 的窗口读取数据,横跨窗口边界的字符串会被一分为二,这使得对于大于窗口的文件,PowerShell 的计数在每个受影响的边界处都会增加一。这是分窗口读取产生的副作用,而不是内容上的分歧 —— 传递一个足够大以容纳整个文件的 `-WindowSize` 即可进行同等条件下的比较。OffsetScan 会读取整个文件,因此不受影响。 ## 构建 ``` cargo build --release # 可选 YARA 支持(需要安装 YARA 引擎): cargo build --release --features yara-scan ``` ## 用法 ``` offsetscan pe ./sample.exe offsetscan pe ./sample.exe --offset 0x5F85 # map a byte offset to its PE section offsetscan entropy ./payload.bin --window 256 --high-threshold 7.2 offsetscan strings ./sample.bin --min-length 6 offsetscan ioc ./sample.exe # Corpus 模式(任意 subcommand): offsetscan ioc ./samples --recurse # 大型 corpus 的流式输出 —— 每行一个紧凑的 JSON object, # 在每个文件处理完成时输出,以保持峰值内存平稳: offsetscan ioc ./samples --recurse --ndjson # 适用于电子表格/SIEM 的 Flat CSV(仅限 ioc;列名与 JSON 字段名匹配): offsetscan ioc ./samples --recurse --csv > iocs.csv ``` 默认情况下,所有命令都会向 stdout 输出一个格式化的 JSON 数组,这与 OffsetInspect 的 JSON 模式约定一致(始终为数组,即使只有一个结果)。 添加 `--ndjson` 可输出换行符分隔的 JSON —— 这种格式非常适合管道传输,并且在处理数十万个文件时内存消耗恒定。添加 `--csv`(仅限 `ioc` 子命令,因为其他子命令会产生嵌套数据)可生成一个扁平的表头加上每个文件一行的表格,其列名与 JSON 字段名相匹配 —— 可直接用于 Excel 或导入 SIEM。 ## 从 PowerShell 中调用 OffsetInspect 3.1.0+ 可直接摄取 OffsetScan 的 IOC JSON,因此语料库报告会通过原生引擎运行,而不是在 PowerShell 中重新扫描每个文件: ``` offsetscan ioc ./samples --recurse > ./ioc.json $results | Export-OffsetThreatReport -Path ./engagement.md -IocJsonPath ./ioc.json ``` 由于 JSON 的数据结构完全匹配 `Get-OffsetIOC`,该结构的任何使用者都可以将 OffsetScan 的输出作为可直接替换的、具备大规模处理速度优势的替代方案。 ## 刻意未包含的内容 - AMSI / Microsoft Defender 扫描 —— 保留在 OffsetInspect 中(仅限 Windows,需要实际的提供程序)。 - 检测边界的二分法搜索 —— 这是一个有状态的、由提供程序驱动的工作流(`Invoke-OffsetThreatScan`),而不是无状态的语料库扫描。 - ClamAV 集成 —— 通过 `clamscan` 启动进程在 Rust 重写中并没有带来真正的并行语料库处理优势;因此保留在 PowerShell 中。 ## 状态 已针对 OffsetInspect 进行验证,并拥有覆盖(Shannon 熵向量、字符串偏移量、PE 辅助程序以及关键一致性的 schema 字段名称)的单元测试套件,该套件在 CI 的 Linux 和 Windows 环境中运行。`resource_size` 是根据 PE 资源数据目录计算得出的。 `yara-scan` 功能添加了 `offsetscan yara` 子命令,其记录(`File`/`Rule`/`StringId`/`Offset`/`OffsetHex`/`Data`)已验证与 `Invoke-OffsetYaraScan` 在相同规则和样本上的记录完全一致。它是 **受特性控制(feature-gated)且默认关闭的** —— 构建它需要 C 工具链和 `libclang`(因为 `yara` crate 会通过 bindgen 编译自带的 `libyara`),因此默认的二进制文件(以及 crates.io / 发布页面上的所有内容)都不包含它。CI 作业会在 Linux 上构建并测试该功能(为 bindgen 安装 `libclang`)。不可打印的匹配字节会被有损解码到 `Data` 中,这可能与 YARA CLI 对二进制匹配的文本呈现方式有所不同。 ``` # 需要:cargo build --release --features yara-scan offsetscan yara ./sample.bin --rules ./rules/malware.yar offsetscan yara ./corpus --recurse --rules ./a.yar --rules ./b.yar ```
标签:DAST, PE文件分析, Rust, Spyse API, 云安全监控, 可视化界面, 威胁情报, 开发者工具, 恶意软件分析, 网络流量审计, 通知系统, 静态分析