不能只用C++标准库写脱壳工具,因其缺乏进程内存读写、断点设置、PE解析、IAT修复等系统级能力;脱壳必须结合Windows API、PE解析库和调试器逻辑,在运行时捕获解密代码并修复关键结构。

逆向工程中编写“脱壳工具”不是标准 C++ 编程任务,而是高度依赖目标可执行文件格式(如 PE/ELF)、壳的行为特征、内存操作权限和调试接口的系统级工作;纯 C++ 无法直接完成脱壳,必须结合 Windows API(VirtualAlloc、ReadProcessMemory、WriteProcessMemory)、PE 解析库(如 pe-parse 或手写解析)、以及调试器逻辑(WaitForDebugEvent)。
为什么不能只用 C++ 标准库写脱壳工具
C++ 标准库不提供进程内存读写、断点设置、PE 头解析、重定位修正等能力。脱壳本质是:在目标进程运行时捕获其解密后的原始代码段,再修复导入表(IAT)、重定位表(relocation)、OEP(Original Entry Point),最后 dump 内存并生成合法可执行文件。这些全在操作系统内核/用户态调试边界上操作。
常见错误现象包括:Access is denied(权限不足)、ERROR_PARTIAL_COPY(读取失败)、dump 后程序崩溃(IAT 未修复)、无法执行(重定位未应用、TLS 回调损坏)。
- 仅用
fstream读取加壳的 .exe 文件,得到的是加密/混淆后的磁盘镜像,不是运行时解密体 - 没调用
DebugActiveProcess或CreateProcess+DEBUG_PROCESS标志,就无法在关键位置下断点 - 忽略 PE 的
IMAGE_DIRECTORY_ENTRY_BASERELOC和IMAGE_DIRECTORY_ENTRY_IMPORT,dump 出来的文件一定加载失败
Windows 下实现基础内存 dump 的关键步骤
以手动脱 UPX 为例(UPX 是公开算法、适合练手),核心是让目标停在 OEP,然后读取内存中已解密的映像区。
立即学习“C++免费学习笔记(深入)”;
- 用
CreateProcess启动目标,并传入DEBUG_PROCESS标志,获得调试权限 - 循环调用
WaitForDebugEvent,监听EXCEPTION_DEBUG_EVENT;当遇到EXCEPTION_BREAKPOINT且 EIP 指向疑似 OEP 时暂停 - 用
VirtualQueryEx扫描目标进程内存,找出MEM_IMAGE+PAGE_EXECUTE_READWRITE的区域(通常是解密后的代码段) - 用
ReadProcessMemory把该区域完整读出到本地缓冲区 - 用
pe-parse或手写代码解析源 PE 的OptionalHeader.ImageBase和节对齐(SectionAlignment),按原结构重建 PE 头与节表
示例片段(简化):
BYTE* pMem = (BYTE*)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); ReadProcessMemory(hTarget, (LPCVOID)baseAddr, pMem, size, &bytesRead); // 此时 pMem 是 raw 内存镜像,但缺少合法 PE 头 → 必须补头 + 修复 IAT
修复导入表(IAT)是最容易翻车的环节
加壳程序通常会清空或覆盖原始 IMAGE_IMPORT_DESCRIPTOR 数组,并在运行时动态填充 IAT。dump 后若不还原,程序一调用 MessageBoxA 就崩。
- 不能直接复制内存里的 IAT 地址——它们是运行时 VA,dump 后需转为文件偏移(FOA)并填回 PE 的 .idata 节
- 必须遍历每个 DLL 的导入函数名(
IMAGE_THUNK_DATA指向的IMAGE_IMPORT_BY_NAME),重建IMAGE_IMPORT_DESCRIPTOR数组 - 若壳用了延迟导入(Delay Import),还要处理
IMAGE_DELAYLOAD_DESCRIPTOR,否则LoadLibrary/GetProcAddress调用会失败 - 推荐用
pe-tools库辅助解析,或参考scylla开源项目的 IAT 搜索策略(基于内存扫描 + 函数地址反查)
别碰没有符号/文档的商业壳,也别指望“通用脱壳器”
所谓“通用脱壳”只是营销话术。每个壳(VMProtect、Themida、Enigma、Armadillo)都有独特虚拟机层、反调试逻辑、花指令、堆栈校验。C++ 可以写一个调试框架,但具体脱哪一款壳,必须针对其行为定制:比如 VMProtect 需要识别其虚拟机入口指令序列(push ebp; mov ebp, esp; pushad 等),并在虚拟机退出后抓取真实代码。
真正实用的路径是:先用 x64dbg 动态分析确定 OEP 和关键解密位置 → 写 C++ 调试器复现该流程 → 用 pe-tools 或 MinGW 自带的 objdump 辅助验证 dump 结果。试图绕过分析、直接写“全自动脱壳器”,只会卡在第一个 IsDebuggerPresent 检测上。


















