win脱壳3 -- dump程序后的IAT修复
目录Dump把内存中的原始程序导出来OEP 已找到Dump 是什么Dump 工具推荐Dump 的流程Dump 后的现象IAT 问题与修复需求先把 IAT 讲明白寻找 IAT 表的地址定位 IAT① 设置硬件执行断点在加壳的 exe 上② 运行到报错的那一行③ 拿到 004714B1 的值跨段访问④ 在 ds 段看到 GetVersion为什么要修复 Dump 下来的 IAT 表修复流程Scylla 工具链常见坑整体流程速查Dump把内存中的原始程序导出来OEP 已找到0047148B | 55 | push ebp ← OEP 0x0047148B原始程序入口Dump 是什么Dump内存转储 把进程运行时的内存镜像保存成文件。脱壳场景中的 Dump 在 OEP 处把已解压的原始代码 壳重建好的 IAT从内存导出生成一个新的 PE 文件。一句话给运行中的程序拍一张内存快照然后把快照保存成可执行文件。Dump 分两类别混用类型工具特点PE 重建式 Dump脱壳用x64dbg Scylla、ImportREC、OllyDump从内存镜像重建 PE 头、节区、导入表 → 直接产出可运行文件完整内存转储取证用Process Hacker整块内存原样保存需大量手工修复不适合脱壳Dump 工具推荐工具平台用途x64dbg Scylla 插件x86/x64首选Dump IAT 修复一站式ImportRECx86老牌 IAT 重建工具OllyDumpx86OllyDbg 插件PE 重建式 DumpLordPEx86Dump PE 头/节区修正Process Hackerx86/x64完整内存转储DIE / dumpbin任意验证脱壳结果Dump 的流程① 让程序停在 OEP0047148B—— 千万不要 F9 继续运行原始代码 ② 打开 Scylla 插件x64dbg 自带 ③ 填 OEP RVA OEP地址 − 模块基址0047148B − 00400000 0x7148B ④ IAT Autosearch → Get Imports先扫描导入为修复做准备 ⑤ Dump → 生成脱壳文件 ⑥ Fix Dump → 修复 IAT → 得到可运行文件为什么必须在 OEP 处 Dump时机选择时机状态壳入口 EP 处原始代码还是加密数据dump 了等于没脱 ❌OEP 处正确原始代码已解密 ✅、IAT 已重建 ✅、原始程序初始化未执行无副作用✅运行一段后可能触发自修改/反dump逻辑且内存带运行时脏数据 ❌Dump 后的现象1. 壳代码消失了Dump 出来的是解压后的原始代码形态壳的 stub 节区不再参与执行dump 重建的是原始节区壳代码消失是正常现象。2. 运行崩溃用插件直接 Dump 出的文件一运行就崩溃访问违例。崩溃原因IAT 未修复。这是脱壳新手的第一个必然翻车点不是 dump 工具坏了。- Dump用插件 Dump 到文件但运行崩溃因 IAT 未修复。崩溃原因链重要加壳时 IAT 被加密/混淆文件中不是真实 API 地址 → 运行时壳才重建 IAT → Dump 导出的是进程内状态导入目录(Import Directory)没有重建 → dump 文件的 IAT 条目指向壳stub地址/运行时临时地址 → 脱离调试器重新加载 → call [IAT] 跳到无效地址 → 崩溃知识点总结OEP 是原始入口PUSHAD/POPAD 标志壳边界。关键信息总结断点监控恢复现场ESP 定律在 OEP 停住再 DumpDump 后崩溃 IAT 未修复。IAT 问题与修复需求修正录音Dump 后崩溃因 IAT 被加密/混淆。原程序IAT 条目直接指向函数如 GetVersion。加壳后IAT 变成一堆无效地址/stub 地址直接执行必然失败。先把 IAT 讲明白IATImport Address Table导入地址表存放 API 函数指针的表。程序不直接写死 API 地址DLL 基址会变而是通过call [IAT条目]间接调用原始程序未加壳 call [004714B1] ← 代码中的调用指令 ↓ 004714B1IAT条目存放 → GetVersion 函数地址位于 kernel32.dll ↓ 直接跳到 GetVersion 执行加壳后 IAT 的三种保护手段手段说明IAT 加密IAT 数据在磁盘文件中是密文壳运行时才解密还原IAT 重定向Junk stubIAT 条目不再指向 API而是指向壳生成的一小段垃圾代码 stubstub 以RET结尾真正的 API 地址在栈上ESPRET弹出真地址跳过去API 动态解析不出现函数名用 GetProcAddress 哈希查找防字符串特征样本用的是第二种Junk stub RET 返回真地址运行时实际是这样加壳程序运行时 call [004714B1] ← 代码中的调用004714B1 就是 IAT 条目地址 ↓ 004714B1: 存放 → 壳stub地址不再是 GetVersion 的地址 ↓ 进入 stub一堆 junk 垃圾指令无意义操作拖慢分析 ↓ RET ← stub 以 RET 结尾RET 从 ESP 弹出真地址 ↓ 跳到 GetVersion 执行 ← 功能正常但 IAT 已被偷梁换柱样本的 IAT 情报IAT 范围0x00475080 ~ 0x00475120IAT 是一整段表不是单个条目混淆方式Junk 代码 RET 返回真地址手动跟法F7 进入 stub 函数 → 看到 RET 从 ESP 取地址规律每个 stub 函数都以 RET 结束RET 执行时 ESP 上放的就是真实 API 地址修复需求条目有几十上百个手工修不完 →需要写脚本自动化修复寻找 IAT 表的地址定位 IAT思路IAT 条目被换成了 stub 地址怎么找到 IAT 在哪——让原始代码自己告诉我们。在 OEP 下硬件断点从 OEP 开始执行原始指令代码执行到第一处call [IAT]时就会走错路报错的位置就是 IAT 条目。① 设置硬件执行断点在加壳的 exe 上在原本程序 OEP 入口点0047148B下硬件执行断点Hardware Breakpoint, Execute为什么用硬件断点硬件断点基于 CPU 调试寄存器DR0~DR3不修改代码——不会触发壳的完整性自校验壳会对比内存字节检测软件断点 0xCC也不污染代码软件断点F2会改写指令字节为 0xCC强壳一校验就发现② 运行到报错的那一行运行后代码从 OEP 开始执行原始指令走到004714B1这一行报错访问违例004714B1 就是第一处通过 IAT 的调用call [IAT条目]——它从 IAT 拿到的是错地址壳 stub / 垃圾值跳转失败在内存窗口中转到地址004714B1查看③ 拿到 004714B1 的值跨段访问读取 004714B1 处存放的值一个指针拿到这个值后转到ds 段数据段该地址上——跨段访问看它指向哪里④ 在 ds 段看到 GetVersion到了 ds 段这个地址上看到了GetVersion真实 API 函数从而判断报错的这一行004714B1就是 IAT 表的地址一个条目结论壳把 IAT 表进行了加密/混淆——磁盘文件里的 IAT 不是真地址运行时才被壳还原/替换知识点报错点 IAT 条目位置。定位 IAT 的方法论 在 OEP 下硬件断点 → 运行原始代码 → 第一个 IAT 调用报错 → 跟值确认。为什么要修复 Dump 下来的 IAT 表问题分析 dump 下来的 IAT 表发现没有有效内存地址——条目里存的地址脱离运行中的进程就不成立指向壳 stub / 运行时临时地址 / 加密值。加壳文件 → IAT 被加密/混淆文件内不是真地址 → 运行时壳才重建 IAT真实 API 地址 → Dump 导出进程镜像但导入表结构未重建 → dump 出来的程序没有有效的 IAT 内存地址 → 重新加载时 call [IAT] 跳向无效地址 → 崩溃修复的本质两件事还原每个 IAT 条目把壳 stub 地址改回真实 API 地址重建导入表让 OS 加载器能像加载正常程序一样自动解析导入函数术语修正你笔记里写的修复 IAT 导出表——严格说是修复导入表Import Table。导入表 导入目录IMAGE_IMPORT_DESCRIPTOR INT导入名称表 IAT导入地址表。IAT 只是其中的地址表部分但日常口语修 IAT就是指修导入这块。修复的两条路线路线做法适用工具全自动Scylla / ImportREC填 OEP → Autosearch → Get Imports → Fix Dump标准壳IAT 可被工具扫描手动/脚本修复逐个 stubF7 进 → 停在 RET → 读 ESP 真地址 → 写回 IAT 条目混淆壳Autosearch 扫不出来手动修复原理对每个 IAT 条目 call [IAT条目] → 进入壳 stub → 执行 junk 垃圾代码 → 停在 RET 处 → 此时 ESP 上的值 真实 API 地址 ← 规律stub 以 RET 结束ESP 持真地址 → 把真实地址写回 IAT 条目覆盖掉 stub 地址为什么要脚本化手动跟两三个条目没问题但 IAT 范围 0x00475080~0x00475120 里有几十上百个条目手动逐个 F7 记地址 回填会修到崩溃自动化方案x64dbg 脚本scriptdll/ x64dbgpyPython API/ Scylla 自动化接口脚本逻辑遍历 IAT 范围 → 对每个条目跑到 stub 的 RET → 读 ESP → 回填真实地址 → 下一个全部完成后交给 Scylla 重建导入表修复后的验证脱壳文件独立双击运行行为与原程序一致不崩溃DIE 识别不出壳能看到原始编译器特征工具查看导入表能看到 GetVersion 等真实 API 列表ump把内存中的原始程序导出来知识点总结Dump 后崩溃 IAT 未修复。修复 还原真实 API 地址 重建导入表。手动修复的抓手stub 以 RET 结尾RET 弹出 ESP 上的真地址。修复流程Scylla 工具链1. 程序停在 OEP0047148B 2. Scylla附加进程 3. OEP 填 RVA 0047148B − 00400000 0x7148B 4. IAT Autosearch → 扫描出 IAT 范围0x00475080 ~ 0x00475120 5. Get Imports → 检查导入函数列表无乱码、无无效地址 6. Dump → 生成脱壳文件 7. Fix Dump → 修复导入表/重定位表 8. 运行验证 DIE 验证壳名消失、编译器特征出现常见坑报错位置 ≠ 崩溃位置报错行004714B1是call [IAT]指令本身崩溃发生在那之后跳到的无效地址上。两个地址要区分理解。64 位差异IAT 条目 8 字节对齐64 位没有 pushad/pushfdESP 定律要换玩法对 .text 下内存访问断点。ASLR/重定位若 dump 时的运行时基址与文件默认基址不同需修复重定位表否则换机器/换加载地址就崩。Get Imports 出现未知函数/序号导入说明 IAT 范围没扫全或识别失败需手动修正范围。找到 OEP ≠ 脱壳完成OEP Dump Fix IAT 三者缺一不可。整体流程速查找到 OEP0047148Bpush ebp ↓ 下硬件执行断点 OEP → 运行 → 报错 004714B1第一个 IAT 调用 ↓ 内存跟值 → ds 段 → 看到 GetVersion → 确认 004714B1 是 IAT 条目IAT 被加密 ↓ 在 OEP 处 Dump → 运行崩溃IAT 未修复 ↓ 修复 IATAutosearch 自动 / 手动 RET-ESP 取真地址 / 脚本批量修复 ↓ Fix Dump → 独立运行成功 脱壳完成