Back to skills
SKILL.md
Re Ai Model
ASecurityAI 模型文件逆向与静态分析:ONNX/PyTorch/Safetensors/TFLite 格式解析、 网络结构还原、权重提取、文件级水印分析(权重 pattern/metadata/tensor hash/embedding 异常)。 触发词:模型文件、权重提取、ONNX解析、safetensors、pth分析、pt文件、模型结构还原、文件级水印
- 112 stars
- 0 votes
- 0 copies
- 1 view
- Added September 19, 2026
Works with
Security analysis
92/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add dslsdzc/rev-skills --skill re-ai-model --agent claude-codeAre you the author of Re Ai Model?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/dslsdzc-re-ai-model)---
name: re-ai-model
description: >
AI 模型文件逆向与静态分析:ONNX/PyTorch/Safetensors/TFLite 格式解析、
网络结构还原、权重提取、文件级水印分析(权重 pattern/metadata/tensor hash/embedding 异常)。
触发词:模型文件、权重提取、ONNX解析、safetensors、pth分析、pt文件、模型结构还原、文件级水印
capabilities: [ai-model-analysis]
---
# AI 模型逆向(ONNX / PyTorch / Safetensors)
## 何时使用 / 何时不用
- 用:拿到 .onnx / .pt / .pth / .safetensors / .tflite 等模型文件,要还原网络结构、提取权重
- 用:**文件级水印**检测(东西藏在哪里:权重 pattern / metadata / tensor hash / embedding 异常——怀疑模型是从原版复制/微调而来时先查文件侧)
- 用:模型文件本身是载荷——权重里藏数据、torch.save 打包恶意 pickle、后门/投毒模型(下载执行类样本)
- 不用:**行为级水印**(模型表现出来是什么:trigger 触发响应 / 查询响应 / 黑盒指纹)与 API 行为层攻击(走 [[re-ai-attack]])
- 不用:纯推理脚本/训练代码(那是源码,走 [[re-script-deob]])
- 不用:模型被打包进可执行文件(PyInstaller/pyarmor 等)——先 [[re-binary-core]] 拆包,拆出的模型文件再回本技能
- 边界:本技能定位 = 模型文件解析 / 结构分析 / 权重分析 / 文件级水印——恶意模型判定、投毒/后门行为侧、归属取证属取证域(未来独立 re-ai-malware 技能承接;当前此类需求暂在本技能范围,以安全边界(坑 2 pickle 隔离)处理,行为侧转 [[re-ai-attack]])
- 注意:**安全提示——不要直接 torch.load 未知 pkl 文件**(pickle 反序列化可执行任意代码,见坑 2);一切对未知 pkl 的加载默认隔离环境([[re-analyze/platform-tips]] 沙箱最高原则),先读后跑;模型解析/权重提取为静态步骤,可免沙箱
## 工具准备
参考 [[re-analyze/platform-tips]]——模型文件 GB 级常见,静态分析按「静态优先(大型样本)」思路:先格式识别与结构解析,按需提取权重,不整载内存(坑 1)。
### python3 —— 所有解析脚本基础
- Linux: `apt install python3` / `dnf install python3` / `pacman -S python`
- macOS: `brew install python3`;Windows: `choco install python`
- 验证: `python3 --version`(本技能脚本均为 Python 3)
### onnx(pip,Python 3.10+)—— ONNX 解析主力
- `pip install onnx`(官方 PyPI;当前 onnx 要求 Python 3.10+,具体版本以 PyPI Requires-Python 为准;自带 protobuf 依赖与 `onnx.proto3` 类型定义)
- 验证: `python3 -c "import onnx; print(onnx.__version__)"`
### netron(pip,Python 3)—— 模型可视化
- `pip install netron`(官方 PyPI,无 Python 版本上界);桌面独立版可选: macOS `brew install --cask netron`、Windows `winget install netron`、Linux snap `snap install netron`
- 验证: `netron --help` 有输出(`pip show netron` 查版本)
- 用法: `netron model.onnx`(本地起 http 服务并开浏览器可视化;`--no-browser` 无头模式)
### torch(pip,Python >=3.10)—— PyTorch 模型加载
- Linux/Windows: `pip install torch`(默认 PyPI 轮子为带 CUDA 全量包,数 GB;仅 CPU 分析用 `pip install torch --index-url https://download.pytorch.org/whl/cpu`)
- **Python 版本下限**:当前 torch 2.x 要求 **Python >=3.10**(PyPI `requires-python`;torchvision 同步为 >=3.10)——3.9 环境要装需 pin 到仍支持 3.9 的旧版(2.8.x 及更早)。torch / torchvision / Python 的具体组合以官方 compatibility matrix 为准,别按「3.9+」泛化
- macOS: `pip install torch`(官方 wheel 为 CPU/arm64)
- 验证: `python3 -c "import torch; print(torch.__version__)"`
- **安全注**:torch.load 底层是 pickle——不要直接 load 未知 pkl 文件;PyTorch 2.6+ 默认 `weights_only=True`,旧版本/显式 `weights_only=False` 仍有任意代码执行风险;未知模型先 `unzip -l`/`xxd` 粗查(坑 2),在隔离环境用 `weights_only=True` 加载,能转 safetensors 就转
### safetensors(pip,Python 3)—— 安全格式读取
- `pip install safetensors`;验证: `python3 -c "import safetensors; print(safetensors.__version__)"`
- 设计目的即无代码执行(纯数据 + JSON 头),是未知 pkl 的替代分析入口(坑 2 对策之一)
### protobuf / protoc(onnx 是 proto)—— 底层格式
- Python 绑定: `pip install protobuf`(当前 7.x 要求 **Python >=3.10**,6.x 起下限已在抬升;3.8/3.9 需 pin 对应旧版本。onnx 已自带依赖、通常无需单独装)
- protoc 编译工具: Debian/Ubuntu `apt install protobuf-compiler`、Fedora `dnf install protobuf-compiler`、Arch `pacman -S protobuf`、macOS `brew install protobuf`
- 验证: `protoc --version`;`python3 -c "import google.protobuf; print(google.protobuf.__version__)"`
## 操作步骤
按顺序执行,每步产物(模型哈希/结构摘要/权重清单)存档 sha256 + 路径([[re-ioc]] 证据链)。
1. **模型格式识别(onnx / safetensors / pytorch pkl / tflite)**:
```sh
file model.bin && sha256sum model.bin > model.sha256 && xxd model.bin | head -2
```
- **ONNX**:无固定魔数——protobuf 流,首字段为 ir_version(tag `0x08` + 变长值;**值随 ONNX 版本递增**:IR 8 对应 ONNX 1.10,当前发布已到 IR 13——所以第二个字节不是常量 `08`,不能拿 `08 08 12` 当识别特征);producer_name(tag `0x12`,长度前缀)按规范只 SHOULD 出现,不保证紧跟其后;`onnx.checker.check_model` 可验证合法性
- **Safetensors**:前 8 字节 = **小端** u64 头长度(`struct.unpack("<Q", data[:8])`),随后是 JSON 头(张量名/形状/dtype/偏移)
- **PyTorch**:`file` 显示 Zip archive(`PK\x03\x04` 头)——`unzip -l model.pt` 看条目(state_dict 含 `data.pkl`;torch.jit.script 含 `data.pkl`/`constants.pkl`/`bytecode.pkl`);老式纯 pkl 是裸 pickle 流(无 PK 头)——**不直接 load**,先 xxd/strings 粗看(坑 2)
- **TFLite**:flatbuffers 流——无固定魔数,但字节 4–7 为文件标识符 `TFL3`(对应 schema 的 `__model_identifier` 字段),xxd/strings 可见;结构解析可用 Netron(支持 .tflite 可视化),权重提取分支思路同 onnx(flatbuffers 解析,超出本技能深度时标注"结构化 dump 为准")
- 判定后按格式走对应分支;拿不准先 [[re-triage]] 初勘(熵/strings 特征)
2. **结构解析(图/层/算子)**:
```sh
netron model.onnx --no-browser # 可视化(有图形界面再开浏览器)
python3 - <<'PY'
import onnx
m = onnx.load("model.onnx")
print("producer:", m.producer_name, m.producer_version) # 框架/优化器指纹(见坑 3)
g = m.graph
print("inputs:", [(i.name, [d.dim_value for d in i.type.tensor_type.shape.dim]) for i in g.input])
print("nodes:", len(g.node), "initializers:", len(g.initializer), "outputs:", [o.name for o in g.output])
for n in g.node[:20]:
print(n.op_type, n.name, list(n.input), "->", list(n.output))
PY
```
- PyTorch 侧:`torch.jit.load` 得 ScriptModule 可打印 `model.graph`(TorchScript 结构);`torch.load` 的 state_dict 只有张量**没有网络结构**——结构在训练/推理脚本里,需配合源码还原(见跨域 [[re-script-deob]])
- 关注点:算子序列(卷积/注意力等结构指纹)、输入输出张量形状、常量节点位置(权重藏在哪)
3. **权重提取(张量 dump)**:
```sh
mkdir -p weights
# ONNX:逐 tensor 惰性落地(大模型见坑 1)
# 注意:这不是"流式"——to_array() 对使用 external data 的 tensor 会先把该张量【完整】读进 ndarray,
# 只是"一次一个张量"而不是"一次整个模型";显存/内存峰值取决于最大的那个张量
python3 - <<'PY'
import onnx, numpy as np
m = onnx.load("model.onnx", load_external_data=False) # 只载图结构,不载外部权重
for init in m.graph.initializer:
# base_dir 默认为空字符串——外部权重不在 CWD 时必须显式指定其所在目录
arr = onnx.numpy_helper.to_array(init, base_dir=".") # 该张量在此处被完整 materialize
np.save(f"weights/{init.name.replace('/', '_')}.npy", arr)
print(init.name, arr.shape, arr.dtype)
del arr # 及时释放,为下一张量让出内存
PY
# Safetensors:惰性按张量读取(不整载内存)
python3 - <<'PY'
from safetensors import safe_open
with safe_open("model.safetensors", framework="numpy") as f:
print(len(f.keys()), "tensors")
for k in list(f.keys())[:10]:
t = f.get_tensor(k); print(k, t.shape, t.dtype)
PY
# PyTorch state_dict(weights_only 安全加载,见坑 2)
python3 - <<'PY'
import torch
sd = torch.load("model.pth", weights_only=True)
for k, v in list(sd.items())[:10]:
print(k, tuple(v.shape) if hasattr(v, "shape") else type(v))
PY
```
- 产出:权重清单(张量名/形状/dtype/数值摘要)+ npy 存档——这是水印检测与窃取判定的原料
4. **模型水印/指纹检测(嵌入权重)**:
- 权重级:逐张量统计(min/max/mean/std、直方图分桶)与疑似原版模型比对;水印常嵌在特定层(首层卷积 bias、归一化 scale、embedding 矩阵行),多为低比特位扰动——检查关键张量的低比特位模式与数值分布异常,而非精确相等(坑 4)
- 指纹级:全权重 sha256 摘要、逐层张量 hash 序列;与候选原版逐层距离(L2/余弦)比对,输出"每层距离热点图"
- 行为级:同一测试输入集跑两模型推理,比较 logits 与激活分布——重训练/蒸馏窃取者权重不同但行为接近
- 产出:相似度矩阵 + 热点图,结论注明判定依据与阈值
5. **模型窃取判定(架构相似度)**:
```sh
python3 - <<'PY'
import onnx
from difflib import SequenceMatcher
m1 = onnx.load("suspect.onnx"); m2 = onnx.load("original.onnx")
s1 = [n.op_type for n in m1.graph.node]; s2 = [n.op_type for n in m2.graph.node]
print("op-seq similarity:", SequenceMatcher(None, s1, s2).ratio()) # 算子序列相似度
# 层对齐后逐层权重余弦/L2 距离:见步骤 4 的每层距离矩阵
PY
```
- 维度:算子序列(SequenceMatcher)、输入/输出形状、逐层权重余弦/L2、输出 logits 距离
- 判定纪律:单一维度是弱证据(同架构不同训练=正常);多维度一致且权重分布高度接近(如逐层余弦 >0.99)才可主张窃取,结论标注各维度数值
- 隐藏载荷检查:`m.metadata_props`(ONNX metadata 藏字符串/代码)、zip 条目中多余文件(坑 2 相关)、权重中形状/数值分布特异的异常张量
## 跨域联合
- [[re-managed]]:本网关「识别运行时」识别到 AI 模型文件后固定调用本技能(模型是"代码在数据里"的托管域分支)
- [[re-binary-core]]:模型内嵌代码、模型被打包进可执行文件(PyInstaller/pyarmor 打包的推理程序)——先二进制域拆解(格式解析/反编译),拆出的模型文件回本技能
- [[re-sandbox]]:一切未知 pkl 的 load 默认隔离环境([[re-analyze/platform-tips]] 最高原则)
- [[re-malware]]:恶意模型载荷(pickle 恶意代码、后门权重、投毒模型分发)的行为与情报侧
- [[re-ioc]]:模型指纹(sha256/张量 hash/水印模式)进 IOC;[[re-triage]]:模型文件初勘入口与哈希存档
- [[re-script-deob]]:PyTorch 推理/训练脚本还原(state_dict 无结构时的补全路径)
- 引用 [[re-analyze/platform-tips]] 静态优先(大型样本)与沙箱最高原则分支
- [[re-ai-attack]]:**文件级证据 → 行为级验证**(单向数据流)——本技能产出的文件侧结论(结构 / 权重 / 文件级 fingerprint)作为 re-ai-attack 行为一致性验证的输入。示例:拿到 suspect.pt → 本技能提取结构+权重生成 fingerprint → 转 re-ai-attack 做行为一致性验证(API 侧比对)
- 只有 API(无文件)的评估直接进 [[re-ai-attack]],不经本技能
## 常见坑与陷阱
- **大模型文件巨大(GB 级)**:现象——`onnx.load`/`torch.load` 吃满内存卡死,netron 打开超时,`np.save` 批量写盘满;原因——权重数 GB,一次性整体加载到内存;对策——分析前先 `du -sh`/`sha256sum` 存档;ONNX 用 `onnx.load(..., load_external_data=False)` 只载图结构,再**逐 tensor** 取值——注意 `numpy_helper.to_array()` 对该 tensor **是完整读出**(不是流式),所以峰值取决于最大的张量,且用 external data 时要**显式给 `base_dir`**(默认空字符串,权重不在 CWD 时直接失败);Safetensors 用 `safe_open` 惰性按张量读;PyTorch 大模型 `torch.load(..., mmap=True)`;处理对象是"结构摘要 + 定向张量",不是整个文件
- **pkl 反序列化风险(不要直接 torch.load 未知 pkl)**:现象——load 后进程反弹 shell/文件被删,或报诡异 `AttributeError`/`ModuleNotFoundError`;原因——pickle 协议可注入任意代码(`__reduce__`/`__setstate__`),torch.load 底层就是 pickle,恶意模型是投毒载荷载体;对策——**安全提示:未知模型绝不直接 `torch.load`**;先 `unzip -l`/`xxd`/`strings` 粗查(zip 头 PK vs 裸 pickle、条目有无可疑模块名),用 `weights_only=True`(PyTorch 2.6+ 默认)加载,需要全功能加载时在隔离环境([[re-sandbox]])执行;可转 safetensors 的样本直接转(纯数据无代码执行)
- **图优化混淆层结构**:现象——onnx-simplifier/TensorRT/onnxruntime 优化后的模型算子序列与训练态对不上(Conv+BN 融合成一个 Conv、常量折叠、名字全改),结构相似度误判;原因——优化器做算子融合/常量折叠,图结构与训练态不同,producer 字段会变;对策——先读 `m.producer_name`/`m.producer_version` 识别优化器与版本(融合 ConvBN 的特征:BN 层消失且 scale 并入 conv 权重);架构比较前先规范化算子序列(按算子类别抽象,忽略名字与常量差异);可用 onnx-simplifier/onnxruntime `graph_optimization_level` 对比优化前后 diff 还原原始层
- **水印鲁棒性(剪枝后仍存)**:现象——精确值比对未命中就下"无水印"结论,或两个无关模型在个别层数值巧合相似被误判"窃取";原因——鲁棒水印经剪枝/量化/重训练后仍存活(设计目标),精确匹配必漏;正常模型同架构同数据权重分布相似,单层巧合是假阳性;对策——水印检测用"统计异常"(低比特位扰动/数值分布特异层)而非"精确相等",窃取判定用多维度证据 + 阈值(步骤 5 纪律),结论标注置信度与证据强度
Attribution
Comments
Loading comments…