{
  "info": {
    "name": "PE Stripper API",
    "description": "PE 文件溯源信息检测与清除工具 API 测试集合。支持在 http://192.168.99.220:8080 部署的 PE Stripper 后端上进行手工联调与回归测试。",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_exporter_id": "pe-stripper-bruno"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://192.168.99.220:8080",
      "type": "string"
    },
    {
      "key": "sampleFile",
      "value": "QQ.exe",
      "type": "string"
    },
    {
      "key": "sampleMd5",
      "value": "3a66e40ad49e7cb8ff0aa2aeffb40405",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "基础接口",
      "description": "Legacy 检测与清除接口，返回 JSON 结果或二进制下载。",
      "item": [
        {
          "name": "01 Health Check",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Response has status ok\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData.status).to.eql(\"ok\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/health",
              "host": ["{{baseUrl}}"],
              "path": ["health"]
            },
            "description": "健康检查接口。确认后端 HTTP 服务已启动并能正常返回 JSON。\n\n预期：200 OK，{ \"status\": \"ok\" }"
          },
          "response": [
            {
              "name": "Success",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"status\": \"ok\"\n}"
            }
          ]
        },
        {
          "name": "02 Detect Legacy (Success)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Response has filename and timestamp\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData).to.have.property(\"filename\");",
                  "    pm.expect(jsonData).to.have.property(\"timestamp\");",
                  "    pm.expect(jsonData).to.have.property(\"pdb_path\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/detect",
              "host": ["{{baseUrl}}"],
              "path": ["detect"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                }
              ]
            },
            "description": "Legacy 检测接口。上传 PE 文件，返回完整的检测报告。\n\n预期：200 OK，JSON 包含 filename、timestamp、pdb_path、rich_header、version_info 等。"
          },
          "response": [
            {
              "name": "Success Response",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"filename\": \"tmpxxxx.exe\",\n  \"timestamp\": \"2022-01-15T09:44:12+00:00\",\n  \"pdb_path\": \"D:\\\\devops\\\\workspace\\\\...\\\\QQ.pdb\",\n  \"rich_header\": { \"raw\": \"...\", \"entries\": [], \"valid\": true },\n  \"has_signature\": false,\n  \"version_info\": {\n    \"CompanyName\": \"Tencent\",\n    \"FileDescription\": \"腾讯QQ\",\n    \"FileVersion\": \"9.5.6.28129\",\n    \"ProductName\": \"腾讯QQ\",\n    \"ProductVersion\": \"9.5.6.28129\"\n  },\n  \"section_names\": [\".text\", \".rdata\", \".data\", \".rsrc\", \".reloc\"],\n  \"static_ips\": [],\n  \"static_domains\": [],\n  \"static_urls\": []\n}"
            }
          ]
        },
        {
          "name": "03 Detect Legacy (Missing File - Error)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 4xx\", function () {",
                  "    pm.expect(pm.response.code).to.be.oneOf([400, 422, 500]);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/detect",
              "host": ["{{baseUrl}}"],
              "path": ["detect"]
            },
            "body": {
              "mode": "formdata",
              "formdata": []
            },
            "description": "错误路径：不传 file 字段，验证服务端参数校验。\n\n预期：4xx 错误。"
          }
        },
        {
          "name": "04 Strip Legacy Download",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Content-Disposition header is present\", function () {",
                  "    pm.expect(pm.response.headers.get(\"Content-Disposition\")).to.include(\"attachment\");",
                  "});",
                  "pm.test(\"Content-Type is octet-stream\", function () {",
                  "    pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"octet-stream\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/strip",
              "host": ["{{baseUrl}}"],
              "path": ["strip"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                }
              ]
            },
            "description": "Legacy 一键清除接口。上传 PE 文件，返回处理后二进制文件。\n\n预期：200 OK，Content-Disposition: attachment，Content-Type: application/octet-stream。\n注意：这是二进制下载接口，不是 JSON 响应。"
          },
          "response": [
            {
              "name": "Success Response Headers",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Disposition", "value": "attachment; filename=\"QQ.cleaned.exe\"" },
                { "key": "Content-Type", "value": "application/octet-stream" }
              ],
              "body": "<binary>"
            }
          ]
        },
        {
          "name": "05 Info Summary",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Response has expected fields\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData).to.have.property(\"filename\");",
                  "    pm.expect(jsonData).to.have.property(\"sections\");",
                  "    pm.expect(jsonData.sections).to.be.an(\"array\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/info",
              "host": ["{{baseUrl}}"],
              "path": ["info"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                }
              ]
            },
            "description": "Legacy 基本信息摘要接口。返回比 /detect 更精简的摘要信息。\n\n预期：200 OK，JSON 包含 filename、timestamp、sections、has_signature、pdb_path、static_ips/domains/urls 计数。"
          },
          "response": [
            {
              "name": "Success Response",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"filename\": \"tmpxxxx.exe\",\n  \"timestamp\": \"2022-01-15T09:44:12+00:00\",\n  \"sections\": [\".text\", \".rdata\", \".data\", \".rsrc\", \".reloc\"],\n  \"has_signature\": false,\n  \"has_rich_header\": true,\n  \"pdb_path\": \"D:\\\\devops\\\\workspace\\\\...\\\\QQ.pdb\",\n  \"static_ips\": 0,\n  \"static_domains\": 0,\n  \"static_urls\": 0\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "前端兼容接口",
      "description": "面向前端 trace 协议的兼容接口，返回统一 envelope 格式。",
      "item": [
        {
          "name": "06 Trace Detect Frontend",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Code is 0 and message is success\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData.code).to.eql(0);",
                  "    pm.expect(jsonData.message).to.eql(\"success\");",
                  "});",
                  "pm.test(\"basic_info has file_md5\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData.data.basic_info).to.have.property(\"file_md5\");",
                  "    pm.expect(jsonData.data.basic_info.file_md5).to.eql(\"{{sampleMd5}}\");",
                  "});",
                  "pm.test(\"trace_info has identity_trace\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData.data.trace_info.identity_trace).to.be.an(\"array\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/trace",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "trace"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                },
                {
                  "key": "file_type",
                  "type": "text",
                  "value": "1"
                },
                {
                  "key": "file_path",
                  "type": "text",
                  "value": "QQ.exe"
                }
              ]
            },
            "description": "前端兼容检测接口（核心入口）。上传 PE 文件进行溯源检测，返回统一 envelope。\n\n预期：200 OK，code=0，message=\"success\"，data.basic_info.file_md5 存在，trace_info 按 identity/group/control 分组。"
          },
          "response": [
            {
              "name": "Success Response",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"code\": 0,\n  \"message\": \"success\",\n  \"data\": {\n    \"basic_info\": {\n      \"file_size\": 73288,\n      \"file_md5\": \"3a66e40ad49e7cb8ff0aa2aeffb40405\",\n      \"file_name\": \"QQ.exe\",\n      \"file_description\": \"QQ.exe\",\n      \"trace_clear_count\": 7,\n      \"file_format_name\": \"BinExecute/Microsoft.EXE[:X86]\"\n    },\n    \"trace_info\": {\n      \"identity_trace\": [\n        { \"trace_description\": \"编译时间戳\", \"value\": \"2022-01-15T09:44:12+00:00\", \"offset_start\": 288, \"offset_end\": 292, \"size\": 4 },\n        { \"trace_description\": \"PDB路径\", \"value\": \"D:\\\\devops\\\\workspace\\\\...\\\\QQ.pdb\", \"offset_start\": 14572, \"offset_end\": 14650, \"size\": 78 }\n      ],\n      \"group_trace\": [\n        { \"trace_description\": \"公司信息\", \"value\": \"Tencent\", \"offset_start\": 57952, \"offset_end\": 57966 },\n        { \"trace_description\": \"产品信息\", \"value\": \"腾讯QQ\", \"offset_start\": 58008, \"offset_end\": 58016 },\n        { \"trace_description\": \"文件版本信息\", \"value\": \"9.5.6.28129\", \"offset_start\": 58052, \"offset_end\": 58074 },\n        { \"trace_description\": \"产品版本信息\", \"value\": \"9.5.6.28129\", \"offset_start\": 58052, \"offset_end\": 58074 },\n        { \"trace_description\": \"资源语言\", \"value\": \"080404b0\", \"offset_start\": 0, \"offset_end\": 0 }\n      ],\n      \"control_trace\": []\n    }\n  }\n}"
            }
          ]
        },
        {
          "name": "07 Trace Detect (Unsupported file_type - Error)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 400\", function () {",
                  "    pm.expect(pm.response.code).to.eql(400);",
                  "});",
                  "pm.test(\"Code is 1 and message is unsupported_file_type\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData.code).to.eql(1);",
                  "    pm.expect(jsonData.message).to.eql(\"unsupported_file_type\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/trace",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "trace"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                },
                {
                  "key": "file_type",
                  "type": "text",
                  "value": "2"
                },
                {
                  "key": "file_path",
                  "type": "text",
                  "value": "QQ.exe"
                }
              ]
            },
            "description": "错误路径：传入不支持的 file_type=2。\n\n预期：400 Bad Request，{ \"code\": 1, \"message\": \"unsupported_file_type\", \"data\": null }"
          },
          "response": [
            {
              "name": "Error Response",
              "status": "Bad Request",
              "code": 400,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"code\": 1,\n  \"message\": \"unsupported_file_type\",\n  \"data\": null\n}"
            }
          ]
        },
        {
          "name": "08 Trace Clear Targeted",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Content-Disposition header is present\", function () {",
                  "    pm.expect(pm.response.headers.get(\"Content-Disposition\")).to.include(\"attachment\");",
                  "});",
                  "pm.test(\"Content-Type is octet-stream\", function () {",
                  "    pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"octet-stream\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/trace/clear",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "trace", "clear"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                },
                {
                  "key": "file_type",
                  "type": "text",
                  "value": "1"
                },
                {
                  "key": "file_md5",
                  "type": "text",
                  "value": "{{sampleMd5}}"
                },
                {
                  "key": "clear_info",
                  "type": "text",
                  "value": "[{\"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路径\"}]"
                }
              ]
            },
            "description": "前端兼容定向清除接口。根据 clear_info 中指定的偏移和替换规则，对选定痕迹做定点清除。\n\n预期：200 OK，返回二进制文件流。\n注意：这是二进制下载接口，成功时不是 JSON；失败时才返回 JSON envelope。"
          },
          "response": [
            {
              "name": "Success Response Headers",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Disposition", "value": "attachment; filename=\"QQ.cleaned.exe\"" },
                { "key": "Content-Type", "value": "application/octet-stream" }
              ],
              "body": "<binary>"
            },
            {
              "name": "Error Response (Invalid clear_info)",
              "status": "Bad Request",
              "code": 400,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"code\": 1,\n  \"message\": \"invalid_clear_info: ...\",\n  \"data\": null\n}"
            }
          ]
        },
        {
          "name": "09 Trace Clear (Invalid clear_info - Error)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 400\", function () {",
                  "    pm.expect(pm.response.code).to.eql(400);",
                  "});",
                  "pm.test(\"Message contains invalid_clear_info\", function () {",
                  "    var jsonData = pm.response.json();",
                  "    pm.expect(jsonData.message).to.include(\"invalid_clear_info\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/trace/clear",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "trace", "clear"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                },
                {
                  "key": "file_type",
                  "type": "text",
                  "value": "1"
                },
                {
                  "key": "file_md5",
                  "type": "text",
                  "value": "{{sampleMd5}}"
                },
                {
                  "key": "clear_info",
                  "type": "text",
                  "value": "this is not valid json"
                }
              ]
            },
            "description": "错误路径：传入不合法的 clear_info JSON 字符串。\n\n预期：400 Bad Request，JSON envelope 中 message 包含 \"invalid_clear_info\"。"
          },
          "response": [
            {
              "name": "Error Response",
              "status": "Bad Request",
              "code": 400,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"code\": 1,\n  \"message\": \"invalid_clear_info: ...\",\n  \"data\": null\n}"
            }
          ]
        },
        {
          "name": "10 Trace Replace One-shot",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "pm.test(\"Content-Disposition header is present\", function () {",
                  "    pm.expect(pm.response.headers.get(\"Content-Disposition\")).to.include(\"attachment\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/trace/replace",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "trace", "replace"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                },
                {
                  "key": "file_type",
                  "type": "text",
                  "value": "1"
                },
                {
                  "key": "file_path",
                  "type": "text",
                  "value": "QQ.exe"
                },
                {
                  "key": "replace_timestamp",
                  "type": "text",
                  "value": "2024-01-02T03:04:05+00:00"
                },
                {
                  "key": "replace_pdb",
                  "type": "text",
                  "value": "zero"
                },
                {
                  "key": "replace_company",
                  "type": "text",
                  "value": "zero"
                },
                {
                  "key": "replace_product_name",
                  "type": "text",
                  "value": "PE Stripper Demo"
                },
                {
                  "key": "replace_file_version",
                  "type": "text",
                  "value": "1.0.0.0"
                },
                {
                  "key": "replace_product_version",
                  "type": "text",
                  "value": "1.0.0.0"
                },
                {
                  "key": "replace_original_filename",
                  "type": "text",
                  "value": "demo.exe"
                }
              ]
            },
            "description": "检测并替换一体化接口。上传样本后服务端自动识别可替换项，按字段执行零填充或定值替换。\n\n规则：省略字段=跳过；传 \"zero\"=零填充；传其他值=按给定内容替换。\n\n预期：200 OK，返回二进制文件流，Content-Disposition: attachment。"
          },
          "response": [
            {
              "name": "Success Response Headers",
              "status": "OK",
              "code": 200,
              "header": [
                { "key": "Content-Disposition", "value": "attachment; filename=\"QQ.replaced.exe\"" },
                { "key": "Content-Type", "value": "application/octet-stream" }
              ],
              "body": "<binary>"
            }
          ]
        },
        {
          "name": "11 Trace Replace (Invalid Timestamp - Error)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 400\", function () {",
                  "    pm.expect(pm.response.code).to.eql(400);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/trace/replace",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "trace", "replace"]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": "{{sampleFile}}"
                },
                {
                  "key": "file_type",
                  "type": "text",
                  "value": "1"
                },
                {
                  "key": "file_path",
                  "type": "text",
                  "value": "QQ.exe"
                },
                {
                  "key": "replace_timestamp",
                  "type": "text",
                  "value": "bad-value"
                }
              ]
            },
            "description": "错误路径：传入非法的时间戳格式。\n\n预期：400 Bad Request，返回 JSON 错误 envelope。"
          },
          "response": [
            {
              "name": "Error Response",
              "status": "Bad Request",
              "code": 400,
              "header": [
                { "key": "Content-Type", "value": "application/json" }
              ],
              "body": "{\n  \"code\": 1,\n  \"message\": \"...\",\n  \"data\": null\n}"
            }
          ]
        }
      ]
    }
  ]
}
