快速准备
建议先把测试样本 QQ.exe 放到本机某个固定目录,再执行以下初始化命令。后文所有 curl 命令均基于这些变量展开,复制后即可运行。
BASE_URL="http://192.168.99.220:8080"
FILE="./QQ.exe"
OUT_DIR="./out"
mkdir -p "$OUT_DIR"
如果你使用的是 Bruno,可以在环境变量中直接创建 baseUrl,并把 URL 写成 {{baseUrl}}/api/path。如果 curl 在 Windows PowerShell 中执行,注意转义规则与 Bash 不同,建议优先在 Git Bash、WSL 或 Linux/macOS 终端运行本文命令。
Bruno Collection Setup
1. 创建 Collection 与环境
- 打开 Bruno,新建一个 Collection,例如
PE Stripper。
- 新建 Environment,例如
local-vm。
- 添加变量:
baseUrl = http://192.168.99.220:8080。
- 所有请求 URL 统一写为:
{{baseUrl}}/xxx。
2. 创建请求目录建议
01-health
02-legacy-detect
03-legacy-strip
04-legacy-info
05-trace-detect
06-trace-clear
07-trace-replace
3. Bruno 中 multipart/form-data 的配置方式
- Method 选择
POST。
- Body 类型选择
Multipart Form。
- 文件字段使用
file,类型选择文件并指向 QQ.exe。
- 文本字段直接按后文接口说明填写,例如
file_type=1、file_path=QQ.exe。
- 二进制下载接口成功后,确认 Bruno 响应面板显示为二进制或文件流;必要时将响应另存到本地,后续再回传做二次检测。
建议在 Bruno 中先完成 /api/v1/trace,从返回值里复制 basic_info.file_md5 与某几个带偏移的 trace 项,再构造 /api/v1/trace/clear 请求,这样最接近真实前端联调链路。
GET/health
用途:健康检查。用于确认后端 HTTP 服务已启动并能正常返回 JSON。
| 项 | 内容 |
| 请求方法 | GET |
| 请求 URL | {{baseUrl}}/health |
| 请求体 | 无 |
| 预期状态码 | 200 |
curl -sS "$BASE_URL/health"
{
"status": "ok"
}
POST/detect
用途:legacy 检测接口。上传 PE 文件,返回检测报告,适合快速确认样本包含哪些可疑元数据、PDB、版本信息、静态网络指标等。
| 字段 | 类型 | 必填 | 说明 |
file | file | 是 | 要检测的 PE 文件。 |
curl -sS -X POST \
-F "file=@$FILE" \
"$BASE_URL/detect"
{
"filename": "tmpxxxx.exe",
"timestamp": "2022-01-15T09:44:12+00:00",
"pdb_path": "D:\\devops\\workspace\\...\\QQ.pdb ",
"rich_header": { "raw": "...", "entries": [ ... ], "valid": true },
"has_signature": false,
"version_info": {
"CompanyName": "Tencent",
"FileDescription": "腾讯QQ",
"FileVersion": "9.5.6.28129",
"ProductName": "腾讯QQ",
"ProductVersion": "9.5.6.28129"
},
"section_names": [".text", ".rdata", ".data", ".rsrc", ".reloc"],
"static_ips": [],
"static_domains": [],
"static_urls": []
}
该接口返回的是核心检测结果原始风格;字段更“后端化”,适合做能力确认,不适合作为前端协议联调基线。
POST/strip
用途:legacy 一键清除接口。直接返回处理后的二进制文件,适合验证“全量清除”链路。
| 字段 | 类型 | 必填 | 说明 |
file | file | 是 | 要清除的 PE 文件。 |
curl -sS -X POST \
-F "file=@$FILE" \
"$BASE_URL/strip" \
-o "$OUT_DIR/QQ.cleaned.legacy.exe"
curl -sS -D - -o /dev/null -X POST \
-F "file=@$FILE" \
"$BASE_URL/strip"
HTTP/1.1 200 OK
content-disposition: attachment; filename="QQ.cleaned.exe"
content-type: application/octet-stream
这是下载型接口。Bruno 中验证时,重点查看状态码、响应头 Content-Disposition 与文件是否可保存,而不是 JSON 面板。
POST/info
用途:legacy 基本信息摘要接口。返回比 /detect 更精简的结果,适合做快速巡检。
| 字段 | 类型 | 必填 | 说明 |
file | file | 是 | 要分析的 PE 文件。 |
curl -sS -X POST \
-F "file=@$FILE" \
"$BASE_URL/info"
{
"filename": "tmpxxxx.exe",
"timestamp": "2022-01-15T09:44:12+00:00",
"sections": [".text", ".rdata", ".data", ".rsrc", ".reloc"],
"has_signature": false,
"has_rich_header": true,
"pdb_path": "D:\\devops\\workspace\\...\\QQ.pdb ",
"static_ips": 0,
"static_domains": 0,
"static_urls": 0
}
POST/api/v1/trace
用途:前端兼容检测接口。该接口是手工联调的核心入口,返回统一的 envelope,并把结果按 identity_trace、group_trace、control_trace 等分类。
| 字段 | 类型 | 必填 | 说明 |
file | file | 是 | 待检测样本。 |
file_type | text | 是 | 当前固定传 1。 |
file_path | text | 是 | 原始文件路径描述,测试时可传 QQ.exe 或客户端看到的路径。 |
curl -sS -X POST \
-F "file=@$FILE" \
-F "file_type=1" \
-F "file_path=QQ.exe" \
"$BASE_URL/api/v1/trace"
{
"code": 0,
"message": "success",
"data": {
"basic_info": {
"file_size": 73288,
"file_md5": "3a66e40ad49e7cb8ff0aa2aeffb40405",
"file_name": "QQ.exe",
"file_description": "QQ.exe",
"trace_clear_count": 7,
"file_format_name": "BinExecute/Microsoft.EXE[:X86]"
},
"trace_info": {
"identity_trace": [
{
"trace_description": "编译时间戳",
"value": "2022-01-15T09:44:12+00:00",
"offset_start": 288,
"offset_end": 292,
"size": 4
},
{
"trace_description": "PDB路径",
"value": "D:\\devops\\workspace\\...\\QQ.pdb ",
"offset_start": 14572,
"offset_end": 14650,
"size": 78
}
],
"group_trace": [
{ "trace_description": "公司信息", "value": "Tencent", "offset_start": 57952, "offset_end": 57966 },
{ "trace_description": "产品信息", "value": "腾讯QQ", "offset_start": 58008, "offset_end": 58016 },
{ "trace_description": "文件版本信息", "value": "9.5.6.28129", "offset_start": 58052, "offset_end": 58074 },
{ "trace_description": "产品版本信息", "value": "9.5.6.28129", "offset_start": 58052, "offset_end": 58074 },
{ "trace_description": "资源语言", "value": "080404b0", "offset_start": 0, "offset_end": 0 }
],
"control_trace": []
}
}
}
验证重点 1code 必须为 0,message 为 success。
验证重点 2basic_info.file_format_name 应为 BinExecute/Microsoft.EXE[:X86]。
验证重点 3记录 basic_info.file_md5,后续 /api/v1/trace/clear 要用到。
验证重点 4关注各 trace 项是否含真实偏移;只有有意义的偏移项才适合回传做 targeted clear。
如果 file_type 不是 1,预期返回 400 且 JSON 为 {"code":1,"message":"unsupported_file_type","data":null}。
POST/api/v1/trace/clear
用途:前端兼容定向清除接口。根据 clear_info 中给出的偏移与替换规则,对指定痕迹做定点清除或替换;成功返回二进制文件流。
| 字段 | 类型 | 必填 | 说明 |
file | file | 是 | 原始样本。 |
file_type | text | 是 | 固定传 1。 |
file_md5 | text | 是 | 通常取自 /api/v1/trace 返回的 basic_info.file_md5。 |
clear_info | text | 是 | 字符串化 JSON 数组,每项描述一段要清除的字节范围。 |
推荐联调步骤
- 先请求
/api/v1/trace。
- 复制一到多个带偏移的 trace 项。
- 构造
clear_info,回传给 /api/v1/trace/clear。
- 保存返回的二进制,再重新调用
/api/v1/trace 或 /detect 比对效果。
curl -sS -X POST \
-F "file=@$FILE" \
-F "file_type=1" \
-F "file_md5=3a66e40ad49e7cb8ff0aa2aeffb40405" \
-F 'clear_info=[{"checked":true,"clear_start":288,"clear_end":292,"clear_size":4,"clear_type":2,"clear_replace":"","trace_description":"编译时间戳"},{"checked":true,"clear_start":14572,"clear_end":14650,"clear_size":78,"clear_type":2,"clear_replace":"","trace_description":"PDB路径"}]' \
"$BASE_URL/api/v1/trace/clear" \
-o "$OUT_DIR/QQ.cleaned.targeted.exe"
curl -sS -D - -o /dev/null -X POST \
-F "file=@$FILE" \
-F "file_type=1" \
-F "file_md5=3a66e40ad49e7cb8ff0aa2aeffb40405" \
-F 'clear_info=[{"checked":true,"clear_start":288,"clear_end":292,"clear_size":4,"clear_type":2,"clear_replace":"","trace_description":"编译时间戳"}]' \
"$BASE_URL/api/v1/trace/clear"
HTTP/1.1 200 OK
content-disposition: attachment; filename="QQ.cleaned.exe"
content-type: application/octet-stream
{
"code": 1,
"message": "invalid_clear_info: ...",
"data": null
}
成功时是二进制文件流,失败时才是 JSON 错误 envelope。因此在 Bruno 中要同时检查状态码与响应内容类型,不要默认按 JSON 解析成功响应。
POST/api/v1/trace/replace
用途:检测并替换一体化接口。上传样本后,服务端先自动识别可替换项,再按表单字段执行 zero-fill 或定值替换,最后返回修改后的二进制文件。
| 字段 | 类型 | 必填 | 说明 |
file | file | 是 | 原始样本。 |
file_type | text | 是 | 固定传 1。 |
file_path | text | 建议传 | 可传样本路径描述,例如 QQ.exe。 |
可选 replace 字段: replace_timestamp、replace_pdb、replace_company、replace_product_name、replace_file_version、replace_product_version、replace_original_filename、replace_static_ip、replace_static_url、replace_static_domain |
替换规则:省略字段 = 跳过;字段值传 zero = 零填充;传其他值 = 按给定内容替换。replace_timestamp 支持 ISO-8601 或 Unix 时间戳字符串。
curl -sS -X POST \
-F "file=@$FILE" \
-F "file_type=1" \
-F "file_path=QQ.exe" \
-F "replace_timestamp=2024-01-02T03:04:05+00:00" \
-F "replace_pdb=zero" \
-F "replace_company=zero" \
-F "replace_product_name=PE Stripper Demo" \
-F "replace_file_version=1.0.0.0" \
-F "replace_product_version=1.0.0.0" \
-F "replace_original_filename=demo.exe" \
"$BASE_URL/api/v1/trace/replace" \
-o "$OUT_DIR/QQ.replaced.exe"
curl -sS -D - -o /dev/null -X POST \
-F "file=@$FILE" \
-F "file_type=1" \
-F "file_path=QQ.exe" \
-F "replace_timestamp=1710000000" \
-F "replace_company=zero" \
"$BASE_URL/api/v1/trace/replace"
HTTP/1.1 200 OK
content-disposition: attachment; filename="QQ.replaced.exe"
content-type: application/octet-stream
如果时间戳格式非法,预期返回 400 与 JSON 错误 envelope;如果字段未传,则对应项保持不变。
测试用例
下表可直接作为 Bruno 手工回归清单。建议至少覆盖成功路径、典型错误路径以及前端真实链路三大类。
| 编号 |
接口 |
场景 |
输入要点 |
预期结果 |
| T01 | GET /health | 健康检查成功 | 无 | 200,JSON 为 {"status":"ok"} |
| T02 | POST /detect | legacy 检测成功 | 上传 QQ.exe | 200,返回文件名、时间戳、PDB、版本信息等 |
| T03 | POST /detect | 缺少文件 | 不传 file | 4xx,返回参数错误 |
| T04 | POST /strip | legacy 清除成功 | 上传 QQ.exe | 200,返回二进制下载,文件名类似 *.cleaned.exe |
| T05 | POST /info | 信息摘要成功 | 上传 QQ.exe | 200,返回 sections、签名状态、PDB 路径、静态网络指标数量 |
| T06 | POST /api/v1/trace | 前端兼容检测成功 | file + file_type=1 + file_path=QQ.exe | 200,code=0,basic_info.file_md5 存在,trace 分组完整 |
| T07 | POST /api/v1/trace | 不支持的 file_type | file_type=2 | 400,JSON 为 unsupported_file_type |
| T08 | POST /api/v1/trace | 核对样本特征 | 同 T06 | basic_info.file_format_name = BinExecute/Microsoft.EXE[:X86] |
| T09 | POST /api/v1/trace/clear | 定向清除成功 | 使用 trace 返回的 MD5 与真实偏移构造 clear_info | 200,返回二进制下载,文件名类似 *.cleaned.exe |
| T10 | POST /api/v1/trace/clear | clear_info 非法 | 传入错误 JSON 字符串 | 400,JSON envelope,message 含 invalid_clear_info |
| T11 | POST /api/v1/trace/clear | 不支持的 file_type | file_type=2 | 400,JSON 为 unsupported_file_type |
| T12 | POST /api/v1/trace/replace | 替换成功 | 传入 1 个或多个 replace_* 字段 | 200,返回二进制下载,文件名类似 *.replaced.exe |
| T13 | POST /api/v1/trace/replace | zero-fill 逻辑 | replace_pdb=zero 或 replace_company=zero | 下载成功,后续复检对应字段应被抹零或清空 |
| T14 | POST /api/v1/trace/replace | 时间戳格式错误 | replace_timestamp=bad-value | 400,返回 JSON 错误 |
| T15 | 完整链路 | trace → clear → re-trace | 先检测,再清除编译时间戳/PDB,再对输出文件重检 | 清理项数量减少,或对应 trace 不再出现/偏移变化符合预期 |
附:建议的 Bruno 请求命名
01 Health Check
02 Detect Legacy
03 Strip Legacy Download
04 Info Summary
05 Trace Detect Frontend
06 Trace Clear Targeted
07 Trace Replace One-shot
08 Trace Invalid File Type
09 Trace Clear Invalid clear_info
10 Replace Invalid Timestamp
如果你需要把结果同步给前端或测试同学,建议在 Bruno Collection 中额外保存一个“成功样例请求”和一个“典型失败样例请求”,方便后续快速复现协议问题。