HendrikDeCoster/MLScan-Showcase

GitHub: HendrikDeCoster/MLScan-Showcase

一款静态二进制扫描器,用于在编译后的软件中检测 ML-KEM 与 ML-DSA 后量子密码学实现并生成 CycloneDX 1.6 CBOM 文档。

Stars: 0 | Forks: 0

# 后量子密码学 (PQC) 资产检测器 [![Python Version](https://img.shields.io/badge/python-3.12%2B-blue.svg)](pyproject.toml) [![CBOM Standard](https://img.shields.io/badge/CycloneDX-1.6--CBOM-green.svg)](src/mlscan/cbom.py) [![Disassembler Engine](https://img.shields.io/badge/capstone-5.0%2B-orange.svg)](src/mlscan/core/disassembler.py) [![Classifier](https://img.shields.io/badge/XGBoost-Cascade-purple.svg)](src/mlscan/analyzers/mnemonic/inference/engine.py) [![Environment](https://img.shields.io/badge/managed%20with-uv-red.svg)](https://docs.astral.sh/uv/) 这是一款静态二进制分析和密码学发现扫描器,旨在识别已编译二进制软件中的后量子密码学 (PQC) 实现。该工具专门用于在未剥离、已剥离以及向量化机器码二进制文件中,识别 **ML-KEM** (FIPS 203 / Kyber) 和 **ML-DSA** (FIPS 204 / Dilithium) 的标准和草案实现。 发现的资产会被盘点并导出为符合 **OWASP CycloneDX 1.6 密码学物料清单 (CBOM)** 标准的 JSON 文档,并附带严格的 `cryptographic-asset` 属性。 ## 核心功能 * **多引擎发现架构:** 结合了快速静态 OID/字符串扫描、即时操作数反汇编、静态 NTT 矩阵模式匹配以及基于控制流的机器学习。 * **Stripped 二进制恢复:** 对于没有符号表的 stripped 二进制文件,通过解析运行时展开结构来重建函数边界:Linux ELF 中 `.eh_frame` 内的 DWARF 调用帧信息 (CFI) FDE,以及 Windows PE 可执行文件中 `.pdata` 内的结构化异常处理 (SEH) 表。 * **全面的容器支持:** 原生支持 ELF(可重定位 `.o`、已链接二进制文件、共享对象 `.so`)、Windows COFF / BigObj (`.obj`)、Windows PE (`.exe`/`.dll`) 以及 Unix 静态库 (`.a` / `.lib`)。 * **AVX2 SIMD 和向量数学支持:** 专用的特征提取器可捕获 AVX2/AVX-512 优化二进制文件中的向量化 Montgomery 和 Barrett 归约模式,在这些文件中标量常数会消失。 * **并发安全扫描核心:** 线程隔离的 Capstone 引擎工厂、线程安全的 LRU 缓存,以及由 `ProcessPoolExecutor` 支持的归档成员并行扫描。 * **严格的 CBOM 1.6 合规性:** 生成经过验证的 CycloneDX 1.6 CBOM 输出,包含精确的参数集、量子安全级别 (1–5)、经典安全性等价物以及确切的证据位置。 * **完全可复现的环境:** `uv.lock` 和 `.python-version` 通过哈希值锁定解释器和每一个传递依赖;只需一个 `uv sync --frozen` 即可重现生成结果时的确切环境。 ## 高级架构 ``` ┌─────────────────────────────────────────────────────────┐ │ Target Binary (.a, .o, .so, COFF, PE, Executable, etc.) │ └────────────────────────────┬────────────────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ BinaryAnalysisPipeline (Core) │ └────────────────┬────────────────┘ │ ┌────────────────────────────┼────────────────────────────┐ ▼ ▼ ▼ ┌───────────────────────┐ ┌────────────────────────┐ ┌────────────────────────┐ │ String & OID Analyzer │ │ Constant Analyzer │ │ Mnemonic ML Engine │ │ (YARA + OID Tables) │ │ (NTT Tables + Immeds) │ │ (CFG + XGBoost 2-Stg) │ └───────────┬───────────┘ └────────────┬───────────┘ └────────────┬───────────┘ │ │ │ └────────────────────────────┼────────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ DetectionResult │ └────────────┬────────────┘ │ ▼ ┌─────────────────────────┐ │ CycloneDX 1.6 Emitter │ └────────────┬────────────┘ │ ▼ ┌─────────────────────────┐ │ CBOM JSON Document │ └─────────────────────────┘ ``` ### 详细架构与代码库映射 ## 安装与设置 依赖项、虚拟环境和 Python 解释器本身由 [`uv`](https://docs.astral.sh/uv/) 管理。无需手动安装任何其他内容。 ### 前置条件 | 要求 | 说明 | | :--- | :--- | | **`uv`** ≥ 0.5 | `curl -LsSf https://astral.sh/uv/install.sh \| sh` (或 `pip install uv`)。 | | **Python 3.12** | 无需提前准备 — `uv` 会根据 `.python-version` 下载并锁定确切的解释器。 | | **C/C++ 工具链** | *可选。* 仅集成测试需要,用于在运行时编译测试用二进制文件,以及重建数据集。 | ### 设置步骤 ``` # 1. Clone the repository git clone https://github.com/HendrikDeCoster/MLScan.git cd MLScan # 2. Reproduce the exact locked environment # --frozen 禁止重新解析:uv.lock 将被原样使用,否则命令失败 uv sync --frozen # 3. Verify the installation end to end uv run pytest tests/test_basic.py uv run mlscan --help ``` ### 安装配置 运行时扫描器不需要机器学习训练栈。请选择与任务匹配的配置: | 配置 | 命令 | 内容 | | :--- | :--- | :--- | | 仅运行时 | `uv sync --frozen --no-dev` | 扫描器 + CLI。占用空间最小,适用于部署。 | | 默认 | `uv sync --frozen` | 运行时 + 测试和 lint 工具 (`pytest`, `ruff`, `deptry`, `vulture`)。 | | 训练 | `uv sync --frozen --extra training` | 添加 scikit-learn, SHAP, matplotlib/seaborn, joblib, parquet 栈。 | | 性能分析 | `uv sync --frozen --group profiling` | 添加 `scalene` 和 `snakeviz`。 | | 全部 | `uv sync --frozen --all-extras --all-groups` | 完整的开发环境。 | ## CLI 用法 使用 `uv run mlscan` 运行扫描: ``` # 扫描二进制文件并输出 CBOM JSON 到标准输出 (stdout) uv run mlscan /path/to/target_binary # 扫描二进制文件并将 CBOM JSON 写入特定输出文件 uv run mlscan /path/to/libcrypto.so -o cbom.json # 运行单个检测引擎 uv run mlscan /path/to/binary -e constant # 扫描静态存档;每个成员对象都作为独立单元进行分析 uv run mlscan data/archives/static/gcc/-O2/liboqs.a -o liboqs.cbom.json ``` ### CLI 命令参数 | 参数 | 类型 | 必填 | 描述 | | :--- | :--- | :--- | :--- | | `file_path` | 位置参数 | **是** | 目标二进制文件、目标文件 (`.o`)、共享库 (`.so`)、静态库 (`.a`/`.lib`) 或 PE 可执行文件 (`.exe`/`.dll`)。 | | `-o`, `--output` | 选项 | 否 | 用于保存 CBOM JSON 文档的文件路径。如果省略,结果将直接打印到控制台 (`stdout`)。 | | `-e`, `--engine` | 选项 | 否 | 将分析限制为特定的发现引擎 (`string`、`constant` 或 `mnemonic`)。如果省略,则运行所有引擎。 | 诊断信息会写入 `stderr`,CBOM 会写入 `stdout`,因此输出可以直接通过管道传递给其他工具: ``` uv run mlscan ./build/my_app | jq -r '.components[].name' ``` 日志级别从 `ScannerSettings.log_level` 读取。由于设置基于 `pydantic-settings`,因此无需更改代码即可通过环境变量覆盖每个字段。扫描完成时进程退出代码为 `0`,如果 pipeline 抛出异常则为 `1`。 ## 特征提取与模型训练 `training/` pipeline 从已编译的归档/可执行文件中提取特征,并训练 2 阶段级联分类器。请先安装训练栈: ``` uv sync --frozen --extra training ``` ### 1. 特征提取 从位于 `data/archives/` 的二进制文件中提取结构化汇编特征: ``` uv run -m training.scripts.extract_features ``` ### 2. 训练分类器 运行 Leave-One-Group-Out (LOGO) 交叉验证,训练生产级 2 阶段级联分类器,并导出训练好的模型产物: ``` uv run -m training.scripts.train_classifier ``` ### 导出的模型产物 导出器会将四个文件写入 `src/mlscan/analyzers/mnemonic/resources/`。`MnemonicInferenceEngine.load_pipeline()` 需要全部四个文件,如果缺少任何一个,就会引发 `FileNotFoundError` 并指明缺失的文件名 —— 如果 mnemonic 引擎报告缺少资源,说明模型尚未导出,同时在此期间 `-e string` / `-e constant` 扫描仍可完全正常使用。 | 产物 | 用途 | | :--- | :--- | | `classifier.json` | 原生 JSON 格式的 XGBoost 级联,由 `XGBoostModelAdapter` 加载。 | | `model_meta.json` | 有序的 `feature_names` 和每个类别的 `best_thresholds`。 | | `scaler.json` | 特征标准化参数。 | | `calibrator.json` | 概率校准层。 | 每次预测时都会根据提取的 DataFrame 验证 `model_meta.json["feature_names"]`。如果不匹配,会引发显式的*结构特征漂移*错误,而不是在对齐错误的列上默默进行评分 —— 因此对提取器的任何更改都需要重新训练和重新导出。 ## 扩展工具 ### 添加新的发现引擎 1. 创建 `src/mlscan/analyzers//analyzer.py`,并继承 `analyzers/base.py` 中的 `BaseAnalyzer`(对于基于规则的引擎则继承 `BaseYaraAnalyzer`)。 2. 实现 `scan_units(units)` 以使用 `ScannableUnit` 对象并返回由 `Signal` 组成的 `DetectionResult` 对象。构造函数接收设置对象:`Analyzer(config=settings)`。 3. 在 `analyzers/registry.py` 中注册该类。注册表键会自动成为 CLI 的 `-e/--engine` 标志的有效值,因为其 `choices` 派生自 `ANALYZER_REGISTRY.keys()`。 4. 将任何 `rules.yar` 放在 `analyzer.py` 旁边;构建时会强制将 `analyzers/**/*.yar` 包含在 wheel 中。 5. 在 `tests/unit/analyzers/` 下添加测试,使用 `tests/fixtures/binaries.py` 中的合成构建器,而不是提交样本二进制文件。 ### 添加新算法或变体 1. `crypto_constants.py` — 在字节级别识别该算法的命名整数常量和模数。 2. `crypto_definitions.py` — 新变体的参数集、OID 和标识符。 3. `crypto_registry.py` — 通过 `CryptoRegistry` 将其公开,分析器和 `cbom.py` 在命名组件和填充 `cryptoProperties` 时都会查询它。 然后将与 `string` 和/或 `constant` 引擎匹配的 YARA 规则添加进去。 ### 扩展数据集 向数据集添加新库需要更改 **三个**地方: 1. **`src/mlscan/core/archive.py` → `_LIBRARY_PATH_KEYWORDS`** 添加一个 `关键字 → 库名称` 条目。这就是为每个提取的样本提供其 `library` 特征的方式。例如,`data/archives/static/gcc/-O0/libopenssl_crypto.a` 包含关键字 `openssl_crypto`,因此会获得值 `openssl`。 2. **`training/config/datasets.py` → `EXCLUDED_KEYWORDS`** 在此处添加关键字(或完整文件名)可在提取过程中跳过这些归档。这是在迭代过程中缩小数据集的最快方法。 3. **`training/config/datasets.py` → `TARGET_LIBS`** 添加在第 1 步中定义的库名称,以将其包含在 **Leave-One-Group-Out** 轮换中。LOGO 每折保留一个库,这就是该项目衡量对未知实现的泛化能力,而不是对单个代码库进行记忆的方式。 重建并验证数据集: ``` uv run bash scripts/download_dependencies.sh # fetch library sources uv run bash scripts/build_archives.sh # compile the -O0..-O3 archive matrix uv run python scripts/verify_optimizations.py # verify the optimization matrix is complete uv run python make_manifest.py # hash the dataset into a manifest ``` ## 测试与验证 使用 `uv` 运行完整的 pytest 套件(607 个测试,串行执行大约需要 2.5 分钟): ``` uv run pytest -n auto --dist worksteal ``` ### 定向测试执行 ``` # 环境冒烟测试:安装、entry point、打包规则、原生库 uv run pytest tests/test_basic.py # 仅 Unit tests uv run pytest tests/unit -n auto --dist worksteal # Pipeline 集成测试(要求 PATH 上有 C 工具链) uv run pytest tests/integration # 除编译器相关测试外的所有内容 uv run pytest -m "not integration" -n auto --dist worksteal # 严格的 OWASP CycloneDX 1.6 JSON Schema 验证 uv run pytest tests/test_cbom_validation.py # Coverage 报告 uv run pytest -m "not integration" --cov --cov-report=term-missing ``` 已注册的标记(`pyproject.toml`,由 `--strict-markers` 强制执行):`integration`, `slow`, `requires_dataset`, `requires_model`。 ### 静态质量门禁 ``` uv run ruff check . # lint uv run ruff format . # format uv run deptry . # unused, undeclared and transitive dependency detection uv run vulture # dead code detection uv lock --check # verify uv.lock still matches pyproject.toml ``` ## 基准测试 基准测试脚本用于衡量已编译二进制文件的扫描性能、执行持续时间和检测吞吐量: ``` uv run python benchmark/run_benchmark.py ``` ## 可复现性 本项目产生的每一个结果都可以追溯到确切的环境和确切的数据集。 | 产物 | 保证 | | :--- | :--- | | `.python-version` | 锁定解释器版本;由 `uv` 自动获取。 | | `uv.lock` | 使用哈希值锁定每个直接和传递依赖项,适用于所有受支持的平台。 | | `uv sync --frozen` | 严格按照 lockfile 安装;如果失败也不会静默重新解析。 | | `uv lock --check` | 验证 lockfile 是否仍然与 `pyproject.toml` 匹配 —— 适合作为 CI 门禁。 | | `make_manifest.py` | 对数据集进行哈希处理,以便将训练运行与确切的输入绑定。 | | `scripts/verify_optimizations.py` | 在提取之前确认 `-O0`–`-O3` 编译矩阵是否完整。 | 要在全新的机器上重现环境: ``` uv sync --frozen --all-extras # exact dependency set ``` ## Make 目标 `Makefile` 封装了上述命令。运行 `make help` 获取完整列表。 | 目标 | 操作 | | :--- | :--- | | `make install` | `uv sync --frozen` — 锁定的默认环境。 | | `make install-all` | 包含训练和性能分析栈的锁定环境。 | | `make lock` | `uv lock --check`:验证 lockfile 是否与 `pyproject.toml` 匹配。 | | `make relock` | 重新解析依赖项并更新 `uv.lock`。 | | `make test` | 完整套件,并行执行。 | | `make test-unit` | 仅运行 `tests/unit`。 | | `make test-int` | 仅运行集成测试。 | | `make test-smoke` | `tests/test_basic.py` — 确认检出正常的最快方法。 | | `make cov` | 覆盖率报告。 | | `make lint` / `make fmt` | Ruff 检查 / 自动格式化和自动修复。 | | `make audit` | `deptry` 和 `vulture`。 | | `make check` Lockfile + lint + 快速测试。提交前/交付前的门禁。 | | `make scan TARGET=` | 扫描二进制文件,CBOM 输出到 stdout。 | | `make cbom TARGET= OUT=` | 扫描二进制文件,CBOM 输出到文件。 | | `make extract` / `make train` | 特征提取 / 分类器训练。 | | `make bench` | 基准测试套件。 | | `make clean` / `make distclean` | 删除缓存和产物 / 同时删除 `.venv`。 |
标签:Apex, Python, XGBoost, 云安全监控, 云资产清单, 后量子密码学, 密码资产管理, 无后门, 机器学习, 逆向工具, 逆向工程, 静态分析