aziz-haddadi/packdetect
GitHub: aziz-haddadi/packdetect
一款Python实现的PE文件加壳检测与自动脱壳命令行工具,通过熵分析、签名扫描和启发式算法识别已知及未知加壳器。
Stars: 0 | Forks: 0
# PackDetect
一款用于 Windows PE 二进制文件(`.exe`、`.dll`、`.sys`)的命令行加壳检测与脱壳工具。专为逆向工程师和恶意软件分析师打造。
```
____ _ ____ _ _
| _ \ __ _ ___| | _| _ \ ___| |_ ___ ___| |_
| |_) / _` |/ __| |/ / | | |/ _ \ __/ _ \/ __| __|
| __/ (_| | (__| <| |_| | __/ || __/ (__| |_
|_| \__,_|\___|_|\_\____/ \___|\__\___|\___|\__|
```
## 功能特性
- **Shannon 熵分析** —— 针对每个节区和整个文件的熵分析,带有彩色输出
- **签名数据库** —— 支持 UPX, MPRESS, ASPack, PECompact, Themida/WinLicense, VMProtect, FSG, Petite, NSIS
- **未知加壳检测** —— 结构化启发式算法,无需已知签名即可捕获自定义/混淆加壳器
- **自动脱壳** —— 通过 subprocess 调用 `upx -d` 或 `mpress -decompress` 以支持已知的加壳器
- **批处理模式** —— 扫描整个目录并获取摘要表
- **JSON 导出** —— 机器可读输出,便于集成到管道中
- **Rich UI + 纯文本回退** —— 使用 `rich` 库输出漂亮的彩色内容;在 `--plain` 模式下优雅降级为纯 ASCII
- **零 PE 库依赖** —— PE 解析器使用纯标准库 `struct` 实现;仅有 `rich` 是可选依赖
## 工作原理
检测运行在三个层级,每一层都计入加权置信度评分:
```
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────────┐
│ Layer 1 │ │ Layer 2 │ │ Layer 3 │
│ Entropy │──▶│ Signature scan │──▶│ Heuristics │
│ Shannon H(x) │ │ magic bytes + │ │ EP location, import │
│ per section │ │ section names │ │ count, size ratios │
└─────────────────┘ └──────────────────┘ └──────────────────────┘
│
Verdict + confidence%
```
**第 1 层 —— 熵 (Entropy):**
Shannon 熵(0–8 位/字节)。加壳/加密节区的得分通常在 7.0 以上。正常编译的代码位于 4.5–6.5 之间。
**第 2 层 —— 签名:**
搜索特定加壳器的魔数(例如 `UPX!`)和已知节区名称(例如 `.MPRESS1`)。贡献高达 95% 的基础置信度。
**第 3 层 —— 启发式特征(未知加壳检测):**
即使在签名不匹配时也能触发的结构异常:
- 仅存在于虚拟内存的节区 (raw_size ≈ 0, virtual_size >> 0) —— 加壳器解压缩的占位符
- 入口点位于 `.text` 之外
- 无导入表 —— 加壳二进制文件会动态重建其 IAT
- 所有节区的原始/虚拟大小比率偏低
- 非标准节区名称
## 安装说明
```
# Clone
git clone https://github.com/you/packdetect
cd packdetect
# 创建并激活 virtual environment
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # Mac / Linux
# 安装(editable mode —— 代码更改立即生效)
pip install -e .
# 或不使用 Rich(仅 plain ASCII mode)
pip install -e . --no-deps
```
**环境要求:**
- Python 3.12+
- `rich >= 13.0`(可选 —— 安装后可获得彩色输出)
- `upx` 位于 PATH 中(可选 —— 自动脱壳 UPX 二进制文件所需)
- `mpress` 位于 PATH 中(可选 —— 自动脱壳 MPRESS 二进制文件所需)
## 快速入门 —— 使用内置的真实恶意软件样本进行测试
本仓库在 `malware-lab/` 目录下包含一个 **真实的 UPX 加壳恶意软件样本**,以便您可以立即使用真实的加壳二进制文件测试该工具。
### Rich 输出的完整扫描
```
packdetect scan ..\..\malware-lab\7d7655e9446fd41dc1ae859435f39c250964532bc604c9bf6d737992430d645e.exe
```
### 纯 ASCII 输出(无颜色)
```
packdetect scan ..\..\malware-lab\7d7655e9446fd41dc1ae859435f39c250964532bc604c9bf6d737992430d645e.exe --plain
```
### 保存 JSON 报告
```
packdetect scan ..\..\malware-lab\7d7655e9446fd41dc1ae859435f39c250964532bc604c9bf6d737992430d645e.exe --save-json
```
这将在样本旁边生成一份 `.packdetect.json` 报告,包含完整的分析内容 —— 各节区熵、签名匹配、启发式发现以及判定结果。
### 尝试自动脱壳
请先确保已安装 `upx` 并位于您的 PATH 中([在此下载](https://upx.github.io)),然后运行:
```
packdetect unpack ..\..\malware-lab\7d7655e9446fd41dc1ae859435f39c250964532bc604c9bf6d737992430d645e.exe
```
这会在后台调用 `upx -d`,并在原始文件旁生成一个 `_unpacked.exe`。重新扫描解包后的文件以确认熵已回落到正常范围(约 5.x):
```
packdetect scan ..\..\malware-lab\7d7655e9446fd41dc1ae859435f39c250964532bc604c9bf6d737992430d645e_unpacked.exe
```
### 预期输出
```
╭──────────────────────── Verdict ─────────────────────────╮
│ ⚠ PACKED │
│ │
│ Confidence : ██████████ 97% │
│ Risk level : HIGH │
│ Packer : UPX │
╰────────────────────────────────────────────────────────────╯
Section Entropy Bar Flag
───────── ───────── ───────────────────────── ──────────
UPX0 0.0000 ░░░░░░░░░░░░░░░░░░░░░░░░ NORMAL
UPX1 7.88xx ████████████████████████ HIGH
.rsrc 3.4xxx ██████████░░░░░░░░░░░░░░ NORMAL
[HIT] UPX — magic bytes "UPX!" found in stub header
```
## 使用方法
### 扫描单个二进制文件
```
packdetect scan malware.exe
```
输出包括:
- 文件信息(大小、MD5、SHA-256、架构、入口点)
- 带有置信度评分和风险等级的判定面板
- 带有彩色条形图的各节区熵表
- 签名扫描结果(命中 / 未检测到)
- 带有独立评分的启发式发现
- 如果检测到支持的加壳器,会显示脱壳提示
### 纯 ASCII 输出(无 Rich)
```
packdetect scan malware.exe --plain
```
### JSON 输出(适合管道传输)
```
packdetect scan malware.exe --json
packdetect scan malware.exe --json | jq .verdict
```
### 将 JSON 报告保存在文件旁
```
packdetect scan malware.exe --save-json
# 写入 malware.packdetect.json
```
### 自动脱壳
```
packdetect unpack upx_packed.exe
# 调用:upx -d upx_packed.exe -o upx_packed_unpacked.exe
```
### 批量扫描目录
```
packdetect batch ./samples/
packdetect batch ./samples/ --all # include non-PE extensions
packdetect batch ./samples/ --json # JSON array to stdout
packdetect batch ./samples/ --save-json # saves packdetect_batch.json
```
## 运行测试套件
本项目包含 **26 个单元测试**,覆盖了整个引擎 —— 熵计算、PE 解析、签名检测、启发式逻辑、判定计算以及端到端分析。
它们仅使用通过 `struct` 构建的 **合成内存 PE 二进制文件** —— 不需要真实的恶意软件。
### 安装 pytest 并运行
```
pip install pytest
pytest tests/ -v
```
### 预期输出
```
tests/test_engine.py::TestShannonEntropy::test_all_zeros PASSED
tests/test_engine.py::TestShannonEntropy::test_all_same_byte PASSED
tests/test_engine.py::TestShannonEntropy::test_two_equal_bytes PASSED
tests/test_engine.py::TestShannonEntropy::test_uniform_distribution PASSED
tests/test_engine.py::TestShannonEntropy::test_random_like_data PASSED
tests/test_engine.py::TestShannonEntropy::test_empty PASSED
tests/test_engine.py::TestPEParser::test_parses_minimal_pe PASSED
tests/test_engine.py::TestPEParser::test_rejects_non_pe PASSED
tests/test_engine.py::TestPEParser::test_rejects_too_short PASSED
tests/test_engine.py::TestPEParser::test_upx_section_names PASSED
tests/test_engine.py::TestSignatureScanner::test_upx_magic_detected PASSED
tests/test_engine.py::TestSignatureScanner::test_upx_section_name_detected PASSED
tests/test_engine.py::TestSignatureScanner::test_mpress_section_name_detected PASSED
tests/test_engine.py::TestSignatureScanner::test_clean_binary_no_matches PASSED
tests/test_engine.py::TestSignatureScanner::test_confidence_is_positive PASSED
tests/test_engine.py::TestHeuristics::test_clean_no_heuristics PASSED
tests/test_engine.py::TestHeuristics::test_high_entropy_flagged PASSED
tests/test_engine.py::TestHeuristics::test_virtual_only_section_flagged PASSED
tests/test_engine.py::TestHeuristics::test_high_entropy_exec_section_flagged PASSED
tests/test_engine.py::TestVerdictComputation::test_signature_hit_gives_packed PASSED
tests/test_engine.py::TestVerdictComputation::test_no_sig_high_heuristic_gives_unknown PASSED
tests/test_engine.py::TestVerdictComputation::test_clean_binary_verdict PASSED
tests/test_engine.py::TestVerdictComputation::test_suspicious_medium_score PASSED
tests/test_engine.py::TestAnalyseIntegration::test_clean_binary PASSED
tests/test_engine.py::TestAnalyseIntegration::test_upx_magic_in_file PASSED
tests/test_engine.py::TestAnalyseIntegration::test_result_fields_populated PASSED
26 passed in 0.22s
```
### 运行覆盖率报告
```
pip install pytest-cov
pytest tests/ -v --cov=packdetect --cov-report=term-missing
```
### 各测试类覆盖的内容
| 类名 | 测试内容 |
|-------|--------------|
| `TestShannonEntropy` | 熵计算边缘情况 —— 全零、均匀分布、随机数据 |
| `TestPEParser` | PE 头解析 —— 有效的 PE32、ELF 拒绝、节区名称解码 |
| `TestSignatureScanner` | UPX 魔数、MPRESS 节区名称、干净文件返回空列表 |
| `TestHeuristics` | 仅虚拟内存节区、高熵可执行节区、干净二进制文件基线 |
| `TestVerdictComputation` | 已知签名 → 已加壳、仅启发式 → 未知加壳器、干净基线 |
| `TestAnalyseIntegration` | 对合成 PE 二进制文件的完整 `analyse()` 管道端到端测试 |
## 退出码
| 代码 | 含义 |
|------|---------|
| 0 | 干净 / 成功 |
| 2 | 检测到加壳二进制文件 |
| 3 | 可疑(非结论性) |
| 4 | 不支持脱壳 |
| 5 | 尝试脱壳但失败 |
在脚本中使用退出码:
```
packdetect scan "$file" --plain
if [ $? -eq 2 ]; then
echo "Packed! Attempting unpack..."
packdetect unpack "$file"
fi
```
## JSON 输出格式
```
{
"file": {
"path": "malware.exe",
"size": 45056,
"md5": "...",
"sha256": "...",
"arch": "x86",
"is_pe": true,
"entry_point": "0x00001000",
"entry_point_section": "UPX1",
"elapsed_seconds": 0.012
},
"entropy": {
"overall": 7.621,
"sections": [
{ "name": "UPX0", "entropy": 0.12, "raw_size": 0, "virtual_size": 65536, "flag": "NORMAL" },
{ "name": "UPX1", "entropy": 7.89, "raw_size": 40960, "virtual_size": 40960, "flag": "HIGH" }
]
},
"signatures": [
{ "name": "UPX", "version": "3.x", "offset": "0x00000050", "confidence": 95, "description": "..." }
],
"heuristics": [
{ "name": "Virtual-only section", "description": "...", "score": 30 }
],
"verdict": {
"verdict": "packed",
"packer": "UPX",
"confidence": 97,
"risk": "HIGH",
"unpack_supported": true,
"unpack_command": "upx -d malware.exe -o malware_unpacked.exe"
}
}
```
## 项目结构
```
packdetect/
├── packdetect/
│ ├── __init__.py version string
│ ├── __main__.py CLI — argparse, commands: scan / unpack / batch
│ ├── engine.py analysis engine — PE parser, entropy, signatures, heuristics
│ └── output.py display — Rich renderer, plain renderer, JSON serialiser
├── malware-lab/
│ └── 7d7655e9...exe real UPX-packed malware sample for testing
├── tests/
│ ├── __init__.py
│ └── test_engine.py 26 unit tests (no real binaries needed)
├── .gitignore
├── LICENSE
├── pyproject.toml
├── requirements.txt
└── README.md
```
## 扩展签名数据库
打开 `packdetect/engine.py` 并在 `SIGNATURE_DB` 中添加条目:
```
{
"name": "MyPacker",
"version": "1.0",
"magic": [b"\xDE\xAD\xBE\xEF"], # bytes to search anywhere in file
"section_names": [".mypkr"], # section name substrings
"ep_stub": bytes([0x60, 0xE8, 0x00]), # bytes at start of first exec section
"description": "MyPacker v1.0 signature",
"confidence": 85,
"unpack_cmd": None, # or "mytool -d {input} -o {output}"
},
```
## 涵盖的概念(作品集要点)
| 概念 | 位置 |
|---------|-------|
| PE 格式 (DOS/COFF/Optional headers, sections) | `engine.py` → `PEParser` |
| Shannon 熵 | `engine.py` → `shannon_entropy()` |
| 加壳器签名 / YARA 风格匹配 | `engine.py` → `SIGNATURE_DB`, `scan_signatures()` |
| 未知加壳器启发式特征 | `engine.py` → `run_heuristics()` |
| Subprocess 编排 | `engine.py` → `attempt_unpack()` |
| 使用 argparse 进行 CLI 设计 | `__main__.py` |
| Rich 终端 UI 及纯文本回退 | `output.py` |
| 结构化 JSON 报告 | `output.py` → `to_json()` |
| 用于脚本集成的退出码 | `__main__.py` |
| 无外部二进制文件的单元测试 | `tests/test_engine.py` |
## 免责声明
本工具及内置样本仅用于**教育和合法的安全研究目的**。
`malware-lab/` 中的恶意软件样本获取自 [MalwareBazaar](https://bazaar.abuse.ch) —— 一个由 abuse.ch 为安全研究社区维护的公开存储库。
请勿在隔离环境之外执行该样本。作者不对滥用行为承担责任。
标签:Conpot, DAST, DeepSeek, PE文件分析, Python安全工具, UPX, VMProtect, Windows安全, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 加壳检测, 可执行文件, 启发式扫描, 恶意软件分析, 无依赖PE解析, 无服务器架构, 熵值分析, 特征码检测, 端点检测与响应, 脱壳工具, 逆向工程, 静态分析