Sandler73/RE-Unpacker

GitHub: Sandler73/RE-Unpacker

递归式软件包/安装程序/归档/二进制提取器,专为逆向工程分流自动逐层解包 70+ 种格式并生成结构化清单。

Stars: 1 | Forks: 0

RE-Unpacker

RE-Unpacker

用于逆向工程分流的递归式软件包 / 安装程序 / 归档 / 二进制提取器。

CI CodeQL Release Last commit Open issues

Version Manifest schema Python Platform License Runtime deps Code style Formats

**当前发布版本:0.5.0** —— 此版本采用里程表式版本号,其中每个版本组件都是一个单数字,满位后向前进位;因此 0.4.9 之后的版本是 0.5.0。它合并了对所有 52 个模块的源码头部标准化,移除了代码和文档中的发布注释,并进行了仓库清理。提取行为没有变化。有关从 0.1.0 开始的完整历史记录,请参阅 [CHANGELOG.md](CHANGELOG.md)。清单 schema 为 **1.1.0**,并且在 Linux 和 Windows 上是字节兼容的。 给它一个文件或目录,它会递归地拆解它能识别的每一个软件包、安装程序、归档、文件系统镜像、压缩流和打包的二进制文件——直到触底——并生成一个结构化的目录树以及一个描述它发现的所有内容的清单。 专为 Linux 上修改过的 Kali Linux RE 工作流和 Windows 上由 winget 管理的 PowerShell 工作流而设计:零外部 Python 依赖,所有提取工作均通过知名的操作系统二进制程序执行。 | 概览 | 数量 | |---|---| | 支持的平台 | 2 (Linux, Windows) | | 跟踪的外部工具 | 93 | | 跟踪的外部工具 | 56 | | 具有版本探测覆盖的工具 | 93 个 Linux / 56 个 Windows (两者均完全覆盖) | | 受保护工具/软件包 | 2 / 2 | | 已知不可用的软件包 | 1 (libfsfat-utils) | | 已知不可用的软件包 | 14 (libyal 二进制文件、signtool 等) | | FileKind 枚举条目 | 78 | | 可提取的类型 | 70 (双平台对等) | | 可分发的主要类型 | 70 | | 已注册的提取器类 (主要 + 次要) | 69 (66 个主要 + 3 个次要) | | 需要 Root/管理员权限的提取器 | 11 (仅限 Linux FUSE) | | 终端分类类型 (加密,无递归) | 3 | | 验证器 | 9 (gpgv, debsigs, dpkg-sig, debsums, rpm-K, apksigner, osslsigncode, powershell-authenticode, signtool) | | 分类器 | 4 (entropy, fuzzy_hash, exif, yara) | | 跟踪的 Python 绑定 | 3 (tlsh, yara, ssdeep) | | 包管理器后端 | 2 (apt, winget) | | 内置包装器 | 3 (bash, PowerShell, cmd) | | 硬性大小上限 (分类器处理) | 256 MiB (验证器豁免) | | 默认单次充实超时 | 30 秒 | | YARA 默认规则目录 | 3 (分平台:Linux 路径或 Windows %PROGRAMDATA% / %APPDATA% 路径) | | 退出码 | 0--6 | | CLI 模式 | 7 | | CLI 标志 (argparse actions) | 37 | | FileEntry 字段 | 25 | | RunStats 计数器 | 20 | | 清单 schema 版本 | 1.1.0 (Linux / Windows 清单字节级完全一致) | **HTML 附属文档:** 格式丰富的 README 和使用指南位于 `docs/` 中: - `docs/ReUnpacker-README.html` —— 以带样式且可导航的布局镜像此 README。 - `docs/ReUnpacker-Usage-Guide.html` —— 面向步骤、以实用指南为主的手册,涵盖了所有 CLI 模式、工作流和故障排除手册。建议与 README 配套阅读。 两者均为自包含的 (无外部 CSS / JS / 字体),可在任何浏览器中渲染。在 Linux 上使用 `xdg-open docs/ReUnpacker-README.html` 打开,或者直接在浏览器中指向该文件。 ## 目录 1. [支持的格式](#supported-formats) 2. [安装说明](#install) 3. [用法](#usage) - [模式](#modes) -- `--install`, `--uninstall`, `--repair`, `--dry-run-install` 4. [输出布局](#output-layout) 5. [清单 schema](#manifest-schema) 6. [安全模型](#safety-model) 7. [退出码](#exit-codes) 8. [程序化使用](#programmatic-use) 9. [设计概述](#design-overview) 10. [文档](#documentation) 11. [贡献指南](#contributing) 12. [许可证](#license) 13. [更新日志](#changelog) ## 支持的格式 | 类别 | 格式 | 主要工具 | 备选工具 | |----------|---------|--------------|-------------| | Linux 软件包 | `.deb` `.udeb` | `dpkg-deb` | `ar` + `tar` | | | `.rpm` | `rpm2cpio` \| `cpio` | `rpm2archive` + `tar` | | Windows 安装程序 | `.msi` `.msp` | `msiextract` | `7z` | | | `.cab` | `cabextract` | `7z` | | | NSIS 安装程序 | `7z` | `binwalk` | | | InnoSetup | `innoextract` | `7z` | | | InstallShield (`setup.exe` + `data*.cab`) | `unshield` | `7z` | | | WiX Burn / 通用 PE 安装程序 | `7z` | `binwalk` | | 文件系统镜像 | `.iso` / UDF | `7z` | `bsdtar` | | | `.dmg` (未加密的 UDIF) | `7z` | -- | | | `.xar` / `.pkg` (macOS) | `7z` | -- | | | SquashFS | `unsquashfs` | -- | | | `.snap` (SquashFS) | `unsquashfs` | -- | | | AppImage | `unsquashfs` at offset | `--appimage-extract` | | 传统归档 | `.tar` / `.tar.{gz,bz2,xz,zst,lzma}` | `tar` | -- | | | `.zip` / `.jar` / `.apk` / `.whl` / `.docx` / … | `unzip` | `7z` | | | `.7z` | `7z` | -- | | | `.rar` | `unrar` | `7z` | | | `.ar` / `.a` | `ar` | -- | | | `.cpio` | `cpio` | -- | | 单流压缩 | `.gz` / `.bz2` / `.xz` / `.zst` / `.lzma` / `.lz4` / `.lzo` | 对应的 CLI | -- | | 二进制文件 | UPX 压缩的 ELF / PE / Mach-O | `upx -d` on copy | -- | | | PE 资源 (图标、清单、嵌入的二进制文件) | `wrestool` (**次要**) | -- | | | ELF 节区 (`.text`, `.rodata`, `.data`, `.note.*` …) | `objcopy` + `readelf` (**次要**) | -- | | 最后手段 | 带有嵌入签名的未知二进制文件 | `binwalk -Me` | -- | | | | | | | **扩展与旧版归档** | `.arj` | `arj` | -- | | | `.lha` / `.lzh` | `lha` (lhasa) | `unar` | | | `.lz` (lzip 单流) | `lzip -d -c` | -- | | | `.tar.lz` / `.tlz` | `lzip -d \| tar -xf -` (pipeline) | -- | | | `.lrz` (lrzip) | `lrzip -d` on copy | -- | | | `.zpaq` | `zpaq x` | -- | | | `.arc` / `.ark` (ARC/ARK MS-DOS) | `nomarch` | -- | | | `.tnef` / `winmail.dat` | `tnef -C` | -- | | | `.shar` (POSIX shell 归档) | `unshar -d` | -- | | | `.uu` / `.uue` (uuencoded) | `uudecode` | -- | | | `.sit` / `.sitx` (StuffIt) | `unar` | -- | | | `.alz` (Korean ALZ) | `unar` | -- | | | `.ace` | `unar` | -- | | | | | | | **文档、磁盘镜像与文件系统** | PDF (带附件) | `pdfdetach -saveall` | -- | | | PDF (结构 / 流) | `qpdf --qdf` | -- | | | `.apk` (Android 软件包,已解码) | `apktool d` | `unzip` (raw fallback at priority 80) | | | `.vmdk` (VMware) | `vmdkmount` (FUSE, root) | `qemu-img convert` (no root) | | | `.qcow2` / `.qcow` (QEMU) | `qcowmount` (FUSE, root) | `qemu-img convert` | | | `.vhd` / `.vhdx` (Microsoft) | `vhdimount` (FUSE, root) | `qemu-img convert` | | | NTFS (在磁盘镜像中) | `fsntfsmount` (FUSE, root) | -- | | | ext{2,3,4} (在磁盘镜像中) | `fsextmount` (FUSE, root) | -- | | | XFS (在磁盘镜像中) | `fsxfsmount` (FUSE, root) | -- | | | APFS (在磁盘镜像中) | `fsapfsmount` (FUSE, root) | -- | | | HFS+ (在磁盘镜像中) | `fshfsmount` (FUSE, root) | -- | | | FAT (在磁盘镜像中) | `fsfatmount` (FUSE, root) | `mtools` | | | VSS 卷影副本 | `vshadowmount` (FUSE, root) | -- | | | LVM2 | `vslvmmount` (FUSE, root) | -- | | | JFFS2 / UBI / MTD (固件) | `binwalk -e` (priority 80) | -- | | | `.kwaj` / `.szdd` (MS DOS 时代) | `msexpand` | -- | | | macOS 二进制 plist (BPLIST) | `plistutil -i -o -f xml` (secondary) | (terminal kind, no primary) | | | | | | | **终端分类 (无递归)** | LUKS 加密卷 | (none -- classify only, kind=LUKS_ENCRYPTED) | -- | | | 加密的 RAR/7z/DMG | (none -- classify only, kind=ENCRYPTED_GENERIC) | -- | “次要”提取器在主要提取之外(而非代替)运行,它们的输出会存放在解包目录内的同级 `_secondary_/` 目录中。 ## 安装说明 ### 前置条件 - Python 3.10+ - 带有相关提取工具的 Kali Linux / Debian / Ubuntu。请参阅 `re-unpacker --tools-check` 在首次运行时打印的安装提示——它会准确告诉你需要添加哪些 `apt` 软件包。 在全新的 Kali / Debian / Ubuntu 机器上,完整的工具集如下: ``` sudo apt-get update sudo apt-get install -y \ arj binutils binwalk bzip2 cabextract cpio dpkg file gzip icoutils \ innoextract lhasa libarchive-tools lrzip lz4 lzip lzop msitools \ nomarch p7zip-full pixz plzip rpm rpm2cpio sharutils squashfs-tools \ tar tnef unar unrar unshield unzip upx-ucl xz-utils zpaq zstd \ apktool fuse libfsapfs-utils libfsext-utils libfshfs-utils \ libfsntfs-utils libfsxfs-utils libluksde-utils libplist-utils \ libqcow-utils libsmraw-utils libvhdi-utils libvmdk-utils \ libvshadow-utils libvslvm-utils mscompress mtd-utils mtools \ poppler-utils qemu-utils qpdf ``` 在完整的 Kali 安装中,libyal 的 `lib*-utils` 软件包提供了取证文件系统提取器所需的 FUSE `*mount` 二进制程序。在 Ubuntu 和最小化的 Debian 安装中,仅提供 `*info` 配套包;基于 FUSE 挂载的提取器将被静默过滤为不可用(运行 `re-unpacker --tools-check` 查看差距)。 或者更简单的方法——让 RE-Unpacker 为你安装所有内容(参见下文[模式](/re-unpacker.git cd re-unpacker chmod +x re-unpacker ./re-unpacker --version ``` `re-unpacker` 包装器会将 `src/` 添加到 `PYTHONPATH` 中,并调用 `python3 -m re_unpacker`。如果你希望将其加入你的 `PATH`,可以在 `~/.local/bin/` 中放置一个软链接。 ### 在 Windows 上安装 同样的源码树,不同的包管理器。有两种调用方式: ``` # PowerShell wrapper(首选): .\re-unpacker.ps1 --version # Cmd.exe shim(用于受限执行策略环境): re-unpacker.cmd --version ``` **Windows 上的前置条件:** - PATH 中包含 Python 3.10 或更高版本 (`winget install Python.Python.3.12` 或任何等效的安装方式) - Windows Package Manager (`winget`) -- 作为 App Installer 系统组件的一部分,内置于 Windows 10 1809+ 和 Windows 11 中 - 用于运行 `re-unpacker.ps1` 的 PowerShell 5.1 (内置于 Windows 10+),或者仅需用于运行 `re-unpacker.cmd` 的 cmd.exe **Windows 上的工具安装。** 同样的 `--install` 模式会调用 winget 而不是 apt: ``` .\re-unpacker.ps1 --install --yes ``` 这将安装每一个由 winget 管理的工具:`7zip.7zip`, `OliverBetz.ExifTool`, `VirusTotal.YARA`, `GnuPG.GnuPG`, `QPDF.QPDF`, `Microsoft.Sysinternals.Sigcheck`, `Microsoft.PowerShell` (PowerShell 7+)。内置工具 (`expand.exe`, `msiexec.exe`, `tar.exe`, Windows PowerShell 5.1) 无需安装。 **Windows 上的手动安装工具。** 有些工具没有 winget 软件包(libyal Windows 二进制文件、来自 Windows SDK 的 `signtool`、来自 Android SDK 的 `apksigner`、通过 pip 安装的 `binwalk` 等)。`re-unpacker --tools-check` 会将这些标记为 MISSING,并且编排器的可用提取器过滤器允许在没有它们的情况下继续运行。每个缺失工具的行都会打印来自 `KNOWN_UNAVAILABLE_PACKAGES_WIN` 的手动安装提示。有关完整的各工具安装路径,请参阅使用指南中的“在 Windows 上运行”一章。 **工具清单对等性。** Windows 工具集(56 个工具)比 Linux 的(93 个)要小,因为 Windows 上的 7-Zip 处理了许多在 Linux 上需要独立工具的格式:deb(不需要 `dpkg-deb`)、rpm(不需要 `rpm2cpio`)、cab(不需要 `cabextract`)、KWAJ/SZDD(不需要 `mscompress`)、cpio + ar(不需要独立工具)、VMDK / QCOW2 / VHD / VHDX(不需要 FUSE 挂载)。这满足了输出层的对等性要求:在 Linux 上可提取的每一种类型在 Windows 上同样可提取,且具有完全相同的 FileEntry 结构和清单 schema。 ## 用法 ### 基础用法 ``` # 解包单个文件(输出至 ./.re-unpacker/) ./re-unpacker sample.deb # 显式输出根目录 ./re-unpacker sample.deb -o ./out # 递归遍历目录下的每个文件 ./re-unpacker ./samples -o ./out # 使用 4 个工作线程 ./re-unpacker ./samples -o ./out -j 4 # 增加递归深度(默认为 10) ./re-unpacker firmware.bin -o ./out -d 20 ``` ### 预检和试运行 ``` # 安装了哪些工具?缺少哪些? ./re-unpacker --tools-check # 在不提取的情况下扫描并分类目录下的每个文件 ./re-unpacker --dry-run ./samples -o ./dryrun cat ./dryrun/manifest.json | jq '.files[].kind' | sort | uniq -c ``` ### 功能开关 每个 feature-flag 默认都处于合理的开启(ON)状态。使用 `--no-*` 形式可将其关闭。 | 标志 | 默认值 | 效果 | |------|---------|--------| | `--binwalk` / `--no-binwalk` | 开启 | 在未知的二进制文件上回退到 `binwalk -Me` | | `--resources` / `--no-resources` | 开启 | 转储 PE 资源和 ELF 节区 | | `--hash` / `--no-hash` | 开启 | 为每个文件计算 SHA-256 + MD5 | | `--dedup` / `--no-dedup` | 开启 | 跳过重新处理之前已发现过相同 SHA-256 的文件 | ### 过滤 ``` # 仅处理特定的文件名模式(适用于初始 seed walk) ./re-unpacker ./samples --include '*.deb' --include '*.rpm' # 跳过您不关心的文件 ./re-unpacker ./samples --exclude '*.txt' --exclude '*.log' ``` ### 模式 RE-Unpacker 有六种顶层模式,且均为互斥关系: | 模式 | 功能描述 | 需要 Root 权限 | |------|-------------|---------------| | (默认) | 解包输入的文件或目录 | 否 | | `--dry-run` | 检测文件类型但不进行提取 | 否 | | `--tools-check` | 探测外部工具,打印状态表并退出 | 否 | | `--dry-run-install` | 打印用于安装 / 卸载 / 修复的精确 apt 命令但不执行 | 否 | | `--install` (别名 `--install-missing`) | 安装当前所有缺失的已知解包工具 | **是** (否则以状态码 5 退出) | | `--uninstall` | 从系统中移除每一个当前存在的解包工具 | **是** (否则以状态码 5 退出) | | `--repair` | 重新安装每一个当前存在的解包工具(从损坏 / 半安装状态中恢复) | **是** (否则以状态码 5 退出) | `--install` / `--uninstall` / `--repair` 模式默认会提示确认。使用 `-y` / `--yes` 可跳过提示: ``` # 安装所有缺失的内容 sudo re-unpacker --install --yes # 预览 install/uninstall/repair 将执行的操作,不实际执行 re-unpacker --dry-run-install # 重新安装当前工具集(例如在 dpkg 部分失败后) sudo re-unpacker --repair --yes # 在重复运行时跳过 apt-get update 步骤 sudo re-unpacker --install --yes --no-refresh-index ``` **包管理模式下的安全护栏:** - `apt` 和 `dpkg` 受注册表跟踪(因此 `--tools-check` 会显示它们的状态),但它们**绝不**是安装 / 卸载 / 修复的目标。`constants.py` 中的双层 `PROTECTED_TOOLS`(按工具名)和 `PROTECTED_PACKAGES`(按包名)集合强制执行了这一点。 - `--uninstall` 会跳过被 dpkg 标记为 `Essential: yes` 的软件包(`tar`, `gzip`, `dpkg` 等)。它们在输出中被列为“已排除”,以便让你知道什么没有被触及以及原因。apt 无论如何都会拒绝;我们在自己的层面进行过滤,以便用户看到清晰的摘要,而不是非零的 apt 错误。 - `--repair` 不会跳过必需包——损坏的 `tar` 正是修复功能旨在修复的那种情况,而且 apt 允许重新安装(只是不允许移除)必需包。 ### 资源 / 安全限制 ``` # 每个 extractor 的超时时间(秒) --timeout 1800 # 硬字节上限 --max-extracted-size 50000000000 # 50 GiB per single archive --max-total-size 500000000000 # 500 GiB across the whole run --max-files 1000000 # files per archive ``` 触发其中任何一项都会以 `SafetyLimitExceeded` 中止进一步的提取并返回退出码 2,但到目前为止写入的清单和日志都会被保留。 ### 充实 提取完成后,编排器会运行针对单个文件的充实阶段:签名/完整性验证器 (Subsystem B) 以及分类器处理 (Subsystem C)。验证器会不分大小地对每个文件运行;分类器则遵循 256 MiB 的硬性上限(超过上限的文件会记录 `enrichment_skipped="size_exceeds_cap"` 并跳过所有分类器处理)。 ``` # 禁用单个 classifier pass(verifiers 始终运行,无法 opt-out) --no-yara # Skip YARA rule matching pass --no-fuzzy-hash # Skip ssdeep + TLSH fuzzy hash computation --no-exif # Skip exiftool metadata extraction --no-entropy # Skip Shannon entropy computation (also disables # The encryption heuristic that depends on it) # YARA 规则加载 --yara-rules PATH # Single file or directory; bypasses default # Auto-discovery (UNION of /etc/yara/, # ~/.config/re-unpacker/yara/, YARA Forge default) # 每个 pass 每个文件的超时时间(verifiers 和 classifiers) --enrich-timeout SEC # Default: 30 seconds ``` **默认 YARA 规则自动发现(未指定 `--yara-rules` 时):** 取所有三个默认目录的并集,每个规则文件的源目录都会提供一个命名空间前缀 (`etc:` / `user:` / `forge:`),从而能够干净利落地解决不同目录间重复的规则名称。 **验证器分发:** 编排器会询问每个验证器 `applies_to(file_entry) -> bool`。验证器在 `src/re_unpacker/verifiers/` 中注册并使用 `Verifier` ABC;它们是尽力而为的,绝不会在失败时中止运行。结果会落在清单的 `file_entry.verification` 中。 | 验证器 | 工具 | 适用的文件类型 | |---|---|---| | `gpgv` | gpgv | 任何带有同级 `.sig` / `.asc` 的文件 | | `debsigs` | debsigs | DEB | | `dpkg-sig` | dpkg-sig | DEB | | `debsums` | debsums | DEB (DISABLED -- debsums operates on installed packages, not .deb files at rest. Tracked for tooling but never invoked.) | | `rpm-K` | rpm | RPM | | `apksigner` | apksigner | APK | | `osslsigncode` | osslsigncode | PE_EXECUTABLE / PE_NSIS / PE_INNOSETUP / PE_INSTALLSHIELD / PE_WIXBURN / MSI / CAB | **分类器分发:** 所有 4 个分类器都会对每个文件运行(受 256 MiB 上限和任何 `--no-*` 禁用标志的约束)。Pipeline 顺序:`entropy` -> `fuzzy_hash` -> `exif` -> `yara`(最便宜的先运行;YARA 最后运行,因为它主导了大型规则集上针对单文件的充实成本)。 | 分类器 | 工具 | 填充的字段 | |---|---|---| | `entropy` | `ent` (with pure-Python fallback) | `entropy`, `encrypted`, `encryption_scheme` | | `fuzzy_hash` | `python3-tlsh` + `python3-ssdeep` (preferred) or `ssdeep` CLI | `ssdeep`, `tlsh` | | `exif` | `exiftool` | `exif_metadata` (per-value 4096-char cap) | | `yara` | `python3-yara` | `yara_matches` (list of rule_name / namespace / tags / meta dicts) | ### 日志 ``` # Console 日志级别(文件日志始终记录 DEBUG) --log-level {DEBUG|INFO|WARNING|ERROR|CRITICAL} # 便捷的详细程度快捷方式 -v, --verbose # = --log-level INFO (default) -vv # = --log-level DEBUG -q, --quiet # = --log-level WARNING (suppress INFO) # (-v 和 -q 互斥;--log-level 会覆盖两者并发出警告) # 文件日志路径(extract 模式会将其添加在 /extraction.log 之上; # 非 extract 模式使用它代替默认的 cache-dir 路径) --log-file PATH --log-file - # disable file logging entirely ``` **默认的文件日志位置:** | 模式 | 默认文件日志路径 | |---|---| | 提取 (默认) | `/extraction.log` (always written) | | `--tools-check` | `~/.cache/re-unpacker/logs/tools-check--.log` | | `--install` | `~/.cache/re-unpacker/logs/install--.log` | | `--uninstall` | `~/.cache/re-unpacker/logs/uninstall--.log` | | `--repair` | `~/.cache/re-unpacker/logs/repair--.log` | | `--dry-run-install` | `~/.cache/re-unpacker/logs/dry-run-install--.log` | 如果设置了 `XDG_CACHE_HOME`,则会使用 `$XDG_CACHE_HOME/re-unpacker/logs/` 来代替 `~/.cache/...`。每个非提取模式都会打印一行横幅,显示解析后的日志文件路径: ``` $ sudo re-unpacker --install --yes [install] Logging to /root/.cache/re-unpacker/logs/install-20260502-143625-12345.log [apt-get update output...] ``` ## 输出布局 每次运行都会写入具有以下结构的 `/`: ``` / ├── manifest.json # consolidated final manifest ├── manifest.jsonl # streaming JSONL, line-buffered (crash-resilient) ├── extraction.log # full DEBUG log (line-buffered) ├── errors.log # warnings+ only, for quick triage ├── tree.txt # pure-Python tree-style listing of extracted/ ├── summary.txt # stats, top kinds, largest files, error summary └── extracted/ └── .unpacked/ # top-level input ├── (files from primary extraction) ├── .unpacked/ # recursive: same scheme at each depth │ └── … ├── _secondary_/ # e.g. _secondary_wrestool/ or _secondary_objcopy_ELF_sections/ │ └── … └── _quarantine/ # (only if the path-safety audit moved anything here) ``` `.unpacked` 后缀使得在 `ls` 输出中哪些目录是 RE-Unpacker 的产物一目了然。`_secondary_…` 子目录是资源 / 节区提取器(PE 资源、ELF 节区)的输出。`_quarantine` 仅在检测到并迁移了逃逸路径时才会出现。 ## 清单 schema `manifest.json` 是权威的机器可读记录。schema 版本目前为 **1.1.0** (在 `constants.SCHEMA_VERSION` 中跟踪)。除非另有说明,所有字段均为 UTF-8 字符串。 ### 顶层 ``` { "schema_version": "1.1.0", "tool": "re-unpacker", "tool_version": "0.3.2", "generated_at": "2026-04-21T17:48:30Z", "opened_at": "2026-04-21T17:48:28Z", "host": "kali-rig-01", "os": "Linux-6.6.x-…", "invocation": { "argv": ["…", "sample.deb", "-o", "out"], "cwd": "/home/re/work", "pid": 12345 }, "input_root": "/path/to/input", "output_root": "/path/to/out", "tools_detected": { /* per-tool: path, version, package_hint, available */ }, "stats": { /* see below */ }, "errors": [ /* list of ErrorEntry */ ], "files": [ /* list of FileEntry */ ] } ``` ### `stats` 对象 ``` { "inputs_scanned": 22, "files_extracted": 22, "archives_processed": 3, "archives_failed": 0, "archives_skipped_dedup": 0, "bytes_in": 0, "bytes_out": 356826, "duration_seconds": 1.38, "max_depth_reached": 4, "errors_count": 0, "quarantined_paths": 0, "symlinks_neutralized": 0 } ``` ### `FileEntry` 每个编排器检查过的文件(提取的和直接透传的)都会生成一个: ``` { "path": "/abs/path/to/file", "rel_path": "extracted/…/file", "rel_path_from_source": "inner/path/inside/archive", "source_archive": "/abs/path/to/parent.tar.gz", "source_archive_sha256": "27b4…", "size": 51234, "sha256": "…", "md5": "…", "file_magic": "ELF 64-bit LSB pie executable, x86-64, …", "mime_type": "application/x-pie-executable", "kind": "ELF", "extractor": null, "depth": 3, "mode": "0755", "mtime": "2026-04-21T17:48:28Z", "signals": ["magic:ELF", "file_desc:ELF …", "mime:…", "ext:"], // -------- schema 1.1.0 additions, all optional -------- "ssdeep": "768:abc...:xyz", // null when not computed "tlsh": "T1A2B3C4...", // null below TLSH min size / diversity "entropy": 7.823, // bits/byte, range 0.0--8.0 "encrypted": false, "encryption_scheme": null, // "luks" | "gpg" | "rar5-encrypted" | "age" | null "yara_matches": [ { "rule_name": "Suspicious_Powershell", "namespace": "etc:0:rules", "tags": ["powershell", "obfuscated"], "meta": {"author": "...", "severity": "high"} } ], "exif_metadata": { "FileType": "ELF", "MachineType": "AMD64", /* ... */ }, "enrichment_skipped": null, // "size_exceeds_cap" when > 256 MiB "verification": [ { "verifier_name": "rpm-K", "performed": true, "applicable": true, "signed": true, "valid": true, "signer": null, "error": null, "duration_seconds": 0.123 } ] } ``` ### `ErrorEntry` ``` { "timestamp": "2026-04-21T17:48:29Z", "path": "/abs/path/to/source.exe", "extractor": "innoextract", "error_class": "ExtractorFailure", "message": "Extractor 'innoextract' failed on '…' (rc=1)", "returncode": 1, "stderr_snippet": "I/O error…", "context": { /* per-error extras */ } } ``` ### `manifest.jsonl` 每行一个 JSON 记录 (`record_type` 为 `"header"`, `"file"`, `"error"` 或 `"footer"`)。行缓冲。对 Grep 和 `jq -c` 非常友好: ``` jq -c 'select(.record_type == "file" and .kind == "ELF") | .path' out/manifest.jsonl ``` ## 安全模型 RE-Unpacker 非常重视对抗性输入——投递到逆向工程设备上的归档通常是恶意的。 - **禁止使用 `shell=True`。** 每个提取器的调用都是一个 `argv` 列表。不会从文件名中构造命令字符串。 - **针对单个提取器的超时机制。** 默认 1800 秒。超时后,`SIGTERM` 会发送到进程组;如果引导进程在 5 秒后仍未退出,则紧随其后发送 `SIGKILL`。引发 `ExtractorTimeout` → 记录并尝试下一个提取器。 - **有界的子进程输出捕获。** 每个流 1 MiB;截断情况会在清单中通过 `stdout_truncated` / `stderr_truncated` 进行标记。 - **每次提取后进行路径遍历审计。** 每一个提取出的软链接都会被解析并与输出根目录进行比较。逃逸的软链接会*被替换*为一个占位符 `*.escaping_symlink.txt` 文件,其中记录了原始目标(以便分析人员仍能看到归档试图做什么)。逃逸的常规文件会被移动到 `/_quarantine/`。计数器会显示在 `stats.symlinks_neutralized` 和 `stats.quarantined_paths` 中。 - **输出大小上限 (在 POSIX 上为预防性)。** 每个提取子进程都在根据 `--max-extracted-size` 设定的 `RLIMIT_FSIZE` 下运行,因此单解压炸弹(一个可能会扩展到数百 GB 的微型 `.gz`,或是 xz/zip 炸弹)会被内核在*写入过程中*拦截,而不是只有在写入完成后才被阻止。在 Windows 上,标准库没有等效于 `RLIMIT_FSIZE` 的简洁实现,因此此上限在该平台上属于空操作,下方的提取后检查成为了安全保障。 - **配额跟踪器 (检测性,全运行范围)。** 在每次提取步骤后,会测量生成的字节计数和文件计数,并对照单个归档和全运行范围的上限 (`--max-extracted-size`, `--max-total-size`, `--max-files`) 进行检查。触发其中任何一项都会引发 `SafetyLimitExceeded` → 退出码 2,保留部分输出和清单。这为许多小文件的情况和总大小的情况提供了后盾(并且是 Windows 上的主要防线)。 - **UPX 始终对副本进行操作。** 源文件永远不会被修改。 - **AppImage 提取永远不会以安装权限执行二进制文件。** 在可能的情况下,它通过对 SquashFS 尾部使用 `unsquashfs -o ` 完全绕过执行;当它回退到 `--appimage-extract` 时,该回退操作会在一个 tempdir 中使用新复制的文件运行。 明确不包含在范围内的项目是对受密码保护的归档进行对称加密密码恢复,以及递归进入需要操作系统内核级别挂载的文件格式(通过 `mount -o loop` 进行 loop-mount ISO)。这两者带来的风险超出了它们对于 RE 分流用例的价值。 ## 退出码 | 码值 | 含义 | |------|---------| | 0 | 运行完成。任何针对单个文件的错误都会记录在清单中——**运行依然算作成功。** | | 1 | 输入路径无效或不可读;未尝试运行 | | 2 | `SafetyLimitExceeded` 在运行期间触发;保留了部分输出 | | 3 | `--tools-check` 模式:缺少一个或多个已知工具 | | 4 | 意外的致命错误 (bug)。请提交 issue。 | | 5 | 需要权限:在没有 root 的情况下调用了 `--install`, `--uninstall` 或 `--repair` | | 6 | 包管理器错误:apt 在安装 / 移除 / 重新安装期间失败 | ## 程序化使用 大多数用户会坚持使用 CLI,但该包对导入也非常友好: ``` from re_unpacker import main as cli_main rc = cli_main(["./sample.deb", "-o", "./out", "--log-level", "WARNING"]) # Rc 是与 CLI 将退出的相同整数。 ``` 如需直接使用编排器(例如将 RE-Unpacker 嵌入到更大的 pipeline 中),请参阅 `re_unpacker.cli._run_normal`——这是关于 logger → tools → manifest → quota → orchestrator 的标准构建模式。 ## 设计概述 ### 三层文件类型检测 1. 从文件头部(对于像 DMG 这样的格式,则从尾部)读取**魔数**。具备偏移量感知能力;能够处理偏移量 32769 处的 ISO-9660。 2. 通过 libmagic 使用 **`file(1)`** —— 用于 PE 子类型消歧(NSIS vs InnoSetup vs InstallShield vs WiX Burn)以及魔数表未覆盖的格式。 3. **扩展名** —— 仅用作第三级决胜条件(例如在普通的 ZIP 中消歧 `.jar`/`.apk`/`.whl`,或确认 OLE2 复合文档具体是 `.msi`)。 每次检测都会在清单中携带一个 `signals` 列表,以便你确切了解文件为何会被这样分类: ``` "signals": ["magic:GZIP", "file_desc:gzip compressed data, from Unix, …", "mime:application/gzip", "refine:tar_composite:.tar.gz", "ext:.tar.gz"] ``` ### 提取器注册表 每个提取器都继承自 `re_unpacker.extractors.base.Extractor` 并声明: - `handles_kinds: frozenset[FileKind]` -- 它能打开什么 - `required_tools: tuple[str, ...]` -- PATH 中必须存在哪些二进制文件 - `priority: int` -- 当多个提取器处理同一种类型时,值越高优先级越高 - `is_secondary: bool` -- 对于在主要提取器*之外*运行的资源 / 节区转储器,此项为 True 注册表在启动时会构建两个映射(主要、次要)。编排器为检测到的类型提取主要列表,按优先级顺序尝试每一个,直到有一个成功(或者全部引发 `ExtractorNotApplicable`),然后无论如何都会运行每一个适用的次要提取器。 ### 分发链语义 关键的区别在于 `ExtractorNotApplicable` 与 `ExtractorFailure`: - **`ExtractorNotApplicable`**:提取器查看了文件并决定它不是合适的工作对象(UPX 看不到魔数;`binwalk` 返回 rc=3 "no signatures")。编排器静默捕获并尝试下一个提取器。**不**会被记录为清单错误。 - **`ExtractorFailure`**:提取器进行了尝试但失败了(非零退出,输出格式错误)。会被记录为清单错误;编排器尝试下一个提取器。 这就是为什么在一个纯粹的 ELF 二进制文件上运行会产生 `errors=0` 的原因,即使 UPX 和 binwalk 都被尝试过并被拒绝了。 ### 递归引擎 `(path, depth, source_archive, source_archive_sha256, rel_path)` 的 BFS 工作队列。去重是根据文件内容的 SHA-256 进行的——在输入中出现两次的字节完全相同的归档只会被提取一次。工作线程 (`-j N`) 共享该队列、去重集合和清单;所有访问都受锁保护。清单写入是行缓冲的 JSONL,因此被中断的运行仍然拥有有效的部分记录。 ## 文档 完整的文档集存在于两个地方:位于 `docs/` 下的 Markdown 指南 以及镜像的[项目 wiki](https://github.com/Sandler73/RE-Unpacker/wiki)。 这些 wiki 页面与 `docs/` 指南保持同步对等。 | 文档 | 路径 | 目的 | |----------|------|---------| | 使用指南 | [`docs/USAGE_GUIDE.md`](docs/USAGE_GUIDE.md) | 涵盖了所有 CLI 模式、标志和工作流,以实用指南为主。 | | 设置指南 | [`docs/SETUP_GUIDE.md`](docs/SETUP_GUIDE.md) | 在 Linux 和 Windows 上安装、工具配置与验证。 | | 故障排除指南 | [`docs/TROUBLESHOOTING_GUIDE.md`](docs/TROUBLESHOOTING_GUIDE.md) | 从症状到修复的手册以及退出码分流。 | | FAQ | [`docs/FAQ.md`](docs/FAQ.md) | 关于范围、安全和行为的常见问题。 | | 更新日志 | [`CHANGELOG.md`](CHANGELOG.md) | 完整的版本历史 (0.1.0 起)。 | | 安全政策 | [`SECURITY.md`](SECURITY.md) | 支持的版本和私密的漏洞报告。 | | 贡献指南 | [`CONTRIBUTING.md`](CONTRIBUTING.md) | 开发设置、提取器/验证器/分类器模式、PR 检查清单。 | | 行为准则 | [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) | 社区标准。 | 格式丰富的 HTML 附属文档也包含在 `docs/` 中 (`ReUnpacker-README.html`, `ReUnpacker-Usage-Guide.html`);两者均为 自包含的,并可在任何浏览器中渲染。 ## 贡献指南 欢迎贡献。请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解开发 设置、提取器 / 验证器 / 分类器编写模式、 编码标准(包括严禁使用 em-dash 的规则和头部块 约定)以及 pull-request 检查清单。所有参与均受 [行为准则](CODE_OF_CONDUCT.md)管辖。安全问题必须按照 [SECURITY.md](SECURITY.md) 私密报告,切勿通过公开的 issues。 ## 许可证 RE-Unpacker 基于 [MIT License](LICENSE) 发布。LICENSE 文件还 包含补充条款(免责声明、责任限制、 赔偿、可接受使用、安全和合规),这些条款明确了针对在 不受信任且可能包含恶意的输入上运行的安全导向 逆向工程工具的期望。这些补充章节并没有 缩小 MIT License 授予的权利;在任何可能被解读为 冲突的地方,均以 MIT License 为准。 RE-Unpacker 不附带任何捆绑的第三方运行时代码。它调用外部的 系统二进制程序 (dpkg-deb, 7-Zip, binwalk, qpdf, yara, exiftool, gpg, libyal 工具集以及其他),这些程序均根据其各自的 条款进行独立安装和许可。 ## 更新日志 完整的版本化历史记录位于 [CHANGELOG.md](CHANGELOG.md) 中,它 遵循 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) 并采用 里程表式版本号:每个组件都是一个单数字,满位后向前进位, 因此 0.4.9 之后的版本是 0.5.0,并且没有 0.4.10。 当前版本 为 **0.4.8**;有关追溯到 0.1.0 的所有记录,请参阅更新日志。 ### 递归引擎 `(path, depth, source_archive, source_archive_sha256, rel_path)` 的 BFS 工作队列。去重是根据文件内容的 SHA-256 进行的——在输入中出现两次的字节完全相同的归档只会被提取一次。工作线程 (`-j N`) 共享该队列、去重集合和清单;所有访问都受锁保护。清单写入是行缓冲的 JSONL,因此被中断的运行仍然拥有有效的部分记录。 ## 文档 完整的文档集存在于两个地方:位于 `docs/` 下的 Markdown 指南 以及镜像的[项目 wiki](https://github.com/Sandler73/RE-Unpacker/wiki)。 这些 wiki 页面与 `docs/` 指南保持同步对等。 | 文档 | 路径 | 目的 | |----------|------|---------| | 使用指南 | [`docs/USAGE_GUIDE.md`](docs/USAGE_GUIDE.md) | 涵盖了所有 CLI 模式、标志和工作流,以实用指南为主。 | | 设置指南 | [`docs/SETUP_GUIDE.md`](docs/SETUP_GUIDE.md) | 在 Linux 和 Windows 上安装、工具配置与验证。 | | 故障排除指南 | [`docs/TROUBLESHOOTING_GUIDE.md`](docs/TROUBLESHOOTING_GUIDE.md) | 从症状到修复的手册以及退出码分流。 | | FAQ | [`docs/FAQ.md`](docs/FAQ.md) | 关于范围、安全和行为的常见问题。 | | 更新日志 | [`CHANGELOG.md`](CHANGELOG.md) | 完整的版本历史 (0.1.0 起)。 | | 安全政策 | [`SECURITY.md`](SECURITY.md) | 支持的版本和私密的漏洞报告。 | | 贡献指南 | [`CONTRIBUTING.md`](CONTRIBUTING.md) | 开发设置、提取器/验证器/分类器模式、PR 检查清单。 | | 行为准则 | [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) | 社区标准。 | 格式丰富的 HTML 附属文档也包含在 `docs/` 中 (`ReUnpacker-README.html`, `ReUnpacker-Usage-Guide.html`);两者均为 自包含的,并可在任何浏览器中渲染。 ## 贡献指南 欢迎贡献。请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解开发 设置、提取器 / 验证器 / 分类器编写模式、 编码标准(包括严禁使用 em-dash 的规则和头部块 约定)以及 pull-request 检查清单。所有参与均受 [行为准则](CODE_OF_CONDUCT.md)管辖。安全问题必须按照 [SECURITY.md](SECURITY.md) 私密报告,切勿通过公开的 issues。 ## 许可证 RE-Unpacker 基于 [MIT License](LICENSE) 发布。LICENSE 文件还 包含补充条款(免责声明、责任限制、 赔偿、可接受使用、安全和合规),这些条款明确了针对在 不受信任且可能包含恶意的输入上运行的安全导向 逆向工程工具的期望。这些补充章节并没有 缩小 MIT License 授予的权利;在任何可能被解读为 冲突的地方,均以 MIT License 为准。 RE-Unpacker 不附带任何捆绑的第三方运行时代码。它调用外部的 系统二进制程序 (dpkg-deb, 7-Zip, binwalk, qpdf, yara, exiftool, gpg, libyal 工具集以及其他),这些程序均根据其各自的 条款进行独立安装和许可。 ## 更新日志 完整的版本化历史记录位于 [CHANGELOG.md](CHANGELOG.md) 中,它 遵循 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) 并采用 里程表式版本号:每个组件都是一个单数字,满位后向前进位, 因此 0.4.9 之后的版本是 0.5.0,并且没有 0.4.10。 当前版本 为 **0.4.8**;有关追溯到 0.1.0 的所有记录,请参阅更新日志。
标签:AI合规, DAST, DNS 反向解析, Python, 云资产清单, 应用安全, 恶意软件分析, 文件提取, 无后门, 解包工具, 逆向工程