ataoytun/revdump
GitHub: ataoytun/revdump
一款 Windows 用户态逆向工程内存转储工具,能够从加壳、镂空或手动映射的进程中重建出导入表完整、可直接加载到 IDA/Ghidra 的 PE 文件。
Stars: 1 | Forks: 0
# revdump
一款用于 Windows 的用户态逆向工程内存转储工具,属于
[Process Dump](https://github.com/glmcdona/Process-Dump)、
[PE-sieve / HollowsHunter](https://github.com/hasherezade/pe-sieve) 和
[Scylla](https://github.com/ntquery/scylla) 同类工具。
revdump 能够从加壳、混淆或被掏空(hollowed)的进程中提取出原始的未加壳代码,并将其写回为可加载到 IDA 或 Ghidra 中且具有可用导入表的 PE 文件。其核心价值在于重建而非简单的字节捕获:它会对内存转储进行内存对齐,使文件与加载器生成的布局相匹配;重建被加壳器在绑定 IAT 后擦除的导入目录;还能在原始入口点(OEP)捕获镜像。这是一个可用的工具,而非经过严格加固的产品;对于某些冷门加壳器可能会有不完善之处,在信任结果之前,请先阅读[范围与限制](#scope-and-limitations)。
## 构建
前置条件:Rust 1.77 或更高版本(2021 edition)、已安装 `x86_64-pc-windows-msvc` 和 `i686-pc-windows-msvc` 目标的 MSVC 工具链,以及 Windows 10 或 11。该工具仅限 Windows 使用;它链接了 `windows-sys` 以及一个手动维护的 NTAPI 接口。
revdump 以一个 workspace 构建,发布两个架构绑定的二进制文件。`revdump64` 用于转储 64 位目标,而 `revdump32` 用于转储 32 位目标。每个垫片(shim)在为目标宽度不匹配时拒绝构建,且都不支持 WOW64 跨位数操作,因此请运行与目标相匹配的二进制文件。按目标进行构建:
```
# 64-bit dumper
cargo build --release -p revdump64 --target x86_64-pc-windows-msvc # alias: cargo build-64
# 32-bit dumper(需要 32-bit MSVC toolchain)
cargo build --release -p revdump32 --target i686-pc-windows-msvc # alias: cargo build-32
```
所有逻辑都位于 `revdump` 库 crate 中;这两个二进制文件只是薄垫片。该 workspace 默认指向库,因此直接使用 `cargo build` 或 `cargo clippy` 只会检查库。针对特定目标的别名(`build-32`、`build-64`、`check-32`、`check-64`、`clippy-32`、`clippy-64`)位于 `.cargo/config.toml` 中。
## 用法
使用一个作用域标志选择目标;触发器和选项标志会对其进行修改。
| 标志 | 参数 | 含义 |
|------|----------|---------|
| `-pid` | `` | 通过 PID 转储进程(十进制或 `0x` 十六进制)。 |
| `-p` | `` | 转储镜像名称匹配正则表达式的所有可访问进程。 |
| `-system` | | 转储每一个可访问的进程。 |
| `-launch` | `` | 在调试器下启动可执行文件并转储。 |
| `-a` | `` | 附加,在该地址设置断点,并在执行到达时转储(需要 `-pid`)。 |
| `-oep` | | 查找原始入口点并在那里转储(需要 `-pid` 或 `-launch`)。 |
| `-closemon` | | 在目标自愿退出时进行转储(需要 `-pid`)。 |
| `-hide` | | 转储时中和常见的反调试检查(需要 `-launch`、`-a` 或 `-oep`)。 |
| `-o` | `` | 输出目录(默认:当前目录)。 |
| `-minidump` | | 在 PE 转储文件旁写入全内存 `.dmp`。 |
| `--deps` | | 同时转储已加载的依赖模块(默认关闭;排除已知正常的模块)。 |
| `-db` | `` | 管理干净哈希数据库:`gen`、`add `、`rem `、`clean`。 |
| `-v` | | 显示详细信息;重复使用以获取更多详情。 |
每个长标志都接受上面所示的单划线形式和 `--双划线` 形式(`-pid` 和 `--pid` 是等价的);`-p`、`-a`、`-o` 和 `-v` 是真正的短标志,而 `--deps` 仅限双划线。
组合会在最前面进行验证,不支持的组合会导致硬错误,而不是静默失效。`-db` 是一个独立模式,不需要指定目标。请准确选择一个作用域:`-pid`、`-p`、`-system` 或 `-launch`。`-closemon` 是 `-pid` 的修饰符,而不是作用域。`-a` 需要 `-pid`。`-oep` 需要 `-pid` 或 `-launch`。`-hide` 需要调试器引擎,因此它要求 `-launch`、`-a` 或 `-oep`。由你自己启动目标,能让反调试补丁在其第一个 TLS 回调之前生效;附加到正在运行的 PID 只能看到启动后的状态。
```
# 通过 PID dump 正在运行的进程
revdump64 -pid 0x1a4
# 在 debugger 下启动 packed binary 并在 original entry point 进行 dump
revdump64 -launch packed.exe -oep
# 在 anti-debug 被中和的情况下启动,并在退出时进行 dump
revdump64 -launch packed.exe -hide
# dump 每一个名称匹配的进程
revdump64 -p "^svchost.*\.exe$"
# 将所有可访问的进程 sweep 到一个目录中
revdump64 -system -o C:\dumps
# 在进程中的某个地址处中断并在该处进行 dump
revdump64 -pid 1234 -a 0x7ff61234abcd
# 从系统 module 目录为 clean-hash database 提供种子
revdump64 -db gen
# dump 进程及其未知的良好依赖 module
revdump64 -pid 1234 --deps
```
## 工作原理
转储作为一个流水线运行。每个阶段只会降级处理单个损坏的区域,而不是中止整个运行。
- **访问。** 获取 `SeDebugPrivilege`,打开目标,并检测 PP/PPL,以便将受保护的进程如实报告为受保护状态,而不是返回裸访问错误。读取是页粒度的:单个受保护页会被填充为零并记录,不会导致致命错误。
- **发现。** 使用 `VirtualQueryEx` 遍历地址空间,并通过直接读取 PEB 和 LDR 列表来枚举已加载的模块,因为加壳器会破坏有文档记录的加载器数据。这种遍历能揭示加载器没有记录的内容:手动映射或反射加载的镜像以及松散的可执行块。第二遍操作会将每个模块的内存镜像与其磁盘文件进行差异对比,以标记内联钩子(inline hook)和掏空操作(名称、基址、头部或入口点不匹配)。
- **重建。** 对区段进行去虚拟化,使文件与内存镜像达到字节级一致(RVA == 文件偏移量),为无头部或头部被擦除的区域修复或合成头部,在已加载模块中构建“地址到导出表”的目录(解析转发器和仅序号导出),并将导入目录重建为一个追加的 `.idata` 区段,其 Thunk 指回实时的 IAT,同时重新计算 `SizeOfImage`。
- **调试器引擎。** 触发器和反调试由外部 Win32 调试器驱动:附加,或者在 `DEBUG_PROCESS` 下调用 `CreateProcess`,然后运行带有软件断点(`0xCC`)的 `WaitForDebugEvent` 循环,断点通过单步执行重新激活。不会向目标注入任何代码。该引擎会暴露初始加载器断点,该断点在启动目标时会在 TLS 回调和入口点之前触发,并且它会跟踪 TLS 回调,以免将 EP 之前的回调误认为是 OEP。
- **反调试(`-hide`)。** 在初始加载器断点处,规范化加壳器读取的 PEB 和堆字段(`BeingDebugged`、`NtGlobalFlag`、堆标志),并通过在它们的返回处下断点来重写调试检测系统调用的结果:`NtQueryInformationProcess` 调试类和 `NtSetInformationThread(ThreadHideFromDebugger)`。仅使用断点和内存写入,不进行注入。
- **OEP 捕获(`-oep`)。** 监视 `NtProtectVirtualMemory` 以获取向可执行状态的转换,从该区域剥离执行权限,并让加壳器跳入未加壳代码时触发 DEP 错误。该错误地址即为原始入口点;revdump 恢复保护权限,进行转储,并将恢复的 OEP 写入转储的头部。
- **过滤。** 干净哈希数据库(磁盘上系统模块的 SHA-256)会排除已知正常的代码,从而只显示无法识别的区域;此外,噪声启发式方法会丢弃那些没有引用任何真实导入的松散代码块。
## 范围与限制
以下是明确的边界,在此坦诚说明。
- **每个二进制文件仅支持一种架构。** `revdump64` 转储 64 位目标,`revdump32` 转储 32 位。跨架构目标(例如在 `revdump64` 下的 32 位 WOW64 进程)会在启动前被拒绝,在 `-system` 和 `-p` 下会被跳过而不是被转储。读取外来的不同位数的 PEB/LDR 只会产生没有导入且被错误分类的输出。请运行相匹配的二进制文件。
- **仅限原生 PE。** .NET 或其他托管程序集转储出来的只是无意义的原生字节;其真正的逻辑是 JIT 编译的 IL,并不存在于原生镜像中。
- **单阶段 OEP。** 查找器会在新变为可执行内存的首次切换并执行时进行转储。多阶段或受 VM 保护的加壳器可能会停留在中间阶段,而不是最终的入口点。
- **直接指针导入。** IAT 槽位是通过将其持有的指针与已加载模块的导出项进行匹配来解析的。如果槽位是通过加壳器自身的 Stub 重定向的(而不是指向导出项),则无法解析;此外,基于地址的解析会指明导出项所在的真实宿主 DLL(例如 `kernelbase` 或 `ntdll`),而不是原始的 `api-ms-win-*` ApiSet 或转发器名称。
- **`-closemon` 仅限自愿退出。** 它在目标自身的 `NtTerminateProcess` 上设置断点。来自另一个进程的外部 `TerminateProcess` 会首先在内核中拆解地址空间,因此无法被捕获。系统范围的终止监视需要内核回调或注入,因此 `-closemon` 需要 `-pid`。
- **反调试的时机取决于你如何接触目标。** 补丁仅在 `-launch` 下才会在第一个 TLS 回调之前生效。在附加时(对正在运行的 PID 使用 `-oep` 或 `-a`),初始断点在启动后触发,因此对于已经运行过的检查,无法进行追溯性击败。
- **这不是商业保护器的脱壳器。** TLS 回调跟踪扩大了覆盖范围,但击败基于虚拟化的保护器(VMProtect、Themida)并不是我们的目标。
- **没有内核组件,也没有保护绕过。** revdump 仅限用户模式,不尝试击败反作弊、DRM、HWID 检查或 PPL。受保护的目标会被检测到并报告。
## 输出
每次运行都会在 `-o`(默认当前目录)下写入一个目录,命名为 `__`(本地时间;pid 保证了在 `-system`/`-p` 下的唯一性)。目录内包含:
- `main/` 重建的主镜像。
- `modules/` 隐藏的、手动映射的或反射加载的 PE。
- `chunks/` 无头部的松散代码。
- `deps/` 已加载的依赖模块,仅在带 `--deps` 时存在。
- `manifest.json` 位于运行目录的根目录,是描述此次运行的附属说明文件。每个产物(artifact)都记录了其文件、类型、基址和真实基址、大小、无法读取的页数、头部来源(原始或合成)、导入状态(原始、重建或无)、置信度标签、通过 `-oep` 转储时检测到的 `oep`,以及 `name_source`(恢复名称的来源)。跳过或失败的区域会在 `notes` 下列出并附上原因。
- `.dmp` 位于根目录,是一个全内存的 minidump,仅在带 `-minidump` 时存在。
只有在包含内容时才会出现子目录。默认情况下不会转储依赖模块(已知正常的库代码最好从其磁盘文件中读取);使用 `--deps` 可以捕获它们,但会排除任何磁盘文件与干净哈希数据库匹配的模块。
当存在模块名时,产物文件名会将其恢复,否则退回到使用基址:`_ _[_hollow].`,或者匿名时为 ` _[_hollow].`。该名称来自映射文件的路径,其次是内嵌的导出 Name(两者都经过了净化处理,因为它们受攻击者影响);deps 使用加载器模块名。基址始终存在以确保名称保持唯一,且清单的 `name_source` 记录了其来源(`mapped-file`、`export-name`、`loader` 或 `address`)。`arch` 为 `x64` 或 `x86`;`_hollow` 标记被掏空的主镜像;扩展名在已知的情况下使用模块自身的扩展名,否则对于镜像使用 `exe`,对于原始数据块使用 `bin`。例如,`deps/kernelbase_1e000000_x86.dll`,`modules/MMDevAPI.dll.mui_3cb0000_x86.exe`,或者一个匿名的 `modules/2b00000_x86.exe`。
## 用途
revdump 是一款外部分析工具,适用于您有权进行逆向工程的软件:您自己的二进制文件、受控实验室中的恶意软件或您获得授权进行的工作。
## 许可证
MIT。详见 [LICENSE](LICENSE)。
标签:DAST, DNS 反向解析, PE重建, Ruby on Rails, 云资产清单, 内存转储, 可视化界面, 安全意识培训, 恶意软件分析, 端点可见性, 逆向工程, 通知系统