win脱壳3 -- dump程序后的IAT修复
2026/8/5 8:26:14 网站建设 项目流程

目录

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 重建式 Dump
LordPEx86Dump + PE 头/节区修正
Process Hackerx86/x64完整内存转储
DIE / dumpbin任意验证脱壳结果

Dump 的流程

① 让程序停在 OEP(0047148B)—— 千万不要 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 停住再 Dump;Dump 后崩溃 = IAT 未修复。


IAT 问题与修复需求

修正录音:Dump 后崩溃,因 IAT 被加密/混淆。原程序:IAT 条目直接指向函数(如 GetVersion)。加壳后:IAT 变成一堆无效地址/stub 地址,直接执行必然失败。

先把 IAT 讲明白

IAT(Import Address Table,导入地址表):存放 API 函数指针的表。程序不直接写死 API 地址(DLL 基址会变),而是通过call [IAT条目]间接调用:

原始程序(未加壳): call [004714B1] ← 代码中的调用指令 ↓ 004714B1(IAT条目):存放 → GetVersion 函数地址(位于 kernel32.dll) ↓ 直接跳到 GetVersion 执行

加壳后 IAT 的三种保护手段:

手段说明
IAT 加密IAT 数据在磁盘文件中是密文,壳运行时才解密还原
IAT 重定向(Junk stub)IAT 条目不再指向 API,而是指向壳生成的一小段"垃圾代码 stub";stub 以RET结尾,真正的 API 地址在栈上(ESP)RET弹出真地址跳过去
API 动态解析不出现函数名,用 GetProcAddress + 哈希查找,防字符串特征

样本用的是第二种:Junk stub + RET 返回真地址,运行时实际是这样:

加壳程序运行时: call [004714B1] ← 代码中的调用(004714B1 就是 IAT 条目地址) ↓ 004714B1: 存放 → 壳stub地址(不再是 GetVersion 的地址!) ↓ 进入 stub:一堆 junk 垃圾指令(无意义操作,拖慢分析) ↓ RET ← stub 以 RET 结尾;RET 从 ESP 弹出"真地址" ↓ 跳到 GetVersion 执行 ← 功能正常,但 IAT 已被"偷梁换柱"

样本的 IAT 情报:

  1. IAT 范围:0x00475080 ~ 0x00475120(IAT 是一整段表,不是单个条目)
  2. 混淆方式:Junk 代码 + RET 返回真地址
  3. 手动跟法:F7 进入 stub 函数 → 看到 RET 从 ESP 取地址
  4. 规律每个 stub 函数都以 RET 结束,RET 执行时 ESP 上放的就是真实 API 地址
  5. 修复需求:条目有几十上百个,手工修不完 →需要写脚本自动化修复

寻找 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] 跳向无效地址 → 崩溃

修复的本质(两件事):

  1. 还原每个 IAT 条目:把"壳 stub 地址"改回"真实 API 地址"
  2. 重建导入表:让 OS 加载器能像加载正常程序一样自动解析导入函数

术语修正:你笔记里写的"修复 IAT 导出表"——严格说是修复导入表(Import Table)。导入表 = 导入目录(IMAGE_IMPORT_DESCRIPTOR)+ INT(导入名称表)+ IAT(导入地址表)。IAT 只是其中的"地址表"部分,但日常口语"修 IAT"就是指修导入这块。

修复的两条路线:

路线做法适用
工具全自动Scylla / ImportREC:填 OEP → Autosearch → Get Imports → Fix Dump标准壳(IAT 可被工具扫描)
手动/脚本修复逐个 stub:F7 进 → 停在 RET → 读 ESP 真地址 → 写回 IAT 条目混淆壳(Autosearch 扫不出来)

手动修复原理

对每个 IAT 条目: call [IAT条目] → 进入壳 stub → 执行 junk 垃圾代码 → 停在 RET 处 → 此时 ESP 上的值 = 真实 API 地址 ← 规律:stub 以 RET 结束,ESP 持真地址 → 把真实地址写回 IAT 条目(覆盖掉 stub 地址)

为什么要脚本化:

  • 手动跟两三个条目没问题,但 IAT 范围 0x00475080~0x00475120 里有几十上百个条目,手动逐个 F7 + 记地址 + 回填会修到崩溃
  • 自动化方案:x64dbg 脚本(scriptdll)/ x64dbgpy(Python API)/ Scylla 自动化接口
  • 脚本逻辑:遍历 IAT 范围 → 对每个条目跑到 stub 的 RET → 读 ESP → 回填真实地址 → 下一个,全部完成后交给 Scylla 重建导入表

修复后的验证:

  • 脱壳文件独立双击运行,行为与原程序一致,不崩溃
  • DIE 识别不出壳,能看到原始编译器特征
  • 工具查看导入表:能看到 GetVersion 等真实 API 列表

ump:把内存中的原始程序导出来

知识点总结:Dump 后崩溃 = IAT 未修复。修复 = 还原真实 API 地址 + 重建导入表。手动修复的抓手:stub 以 RET 结尾,RET 弹出 ESP 上的真地址


修复流程(Scylla 工具链)

1. 程序停在 OEP(0047148B) 2. Scylla:附加进程 3. OEP 填 RVA = 0047148B − 00400000 = 0x7148B 4. IAT Autosearch → 扫描出 IAT 范围(0x00475080 ~ 0x00475120) 5. Get Imports → 检查导入函数列表(无乱码、无无效地址) 6. Dump → 生成脱壳文件 7. Fix Dump → 修复导入表/重定位表 8. 运行验证 + DIE 验证(壳名消失、编译器特征出现)

常见坑

  1. 报错位置 ≠ 崩溃位置:报错行(004714B1)是call [IAT]指令本身;崩溃发生在那之后跳到的无效地址上。两个地址要区分理解。
  2. 64 位差异:IAT 条目 8 字节对齐;64 位没有 pushad/pushfd,ESP 定律要换玩法(对 .text 下内存访问断点)。
  3. ASLR/重定位:若 dump 时的运行时基址与文件默认基址不同,需修复重定位表,否则换机器/换加载地址就崩。
  4. Get Imports 出现未知函数/序号导入:说明 IAT 范围没扫全或识别失败,需手动修正范围。
  5. "找到 OEP" ≠ 脱壳完成:OEP + Dump + Fix IAT 三者缺一不可。

整体流程速查

找到 OEP(0047148B,push ebp) ↓ 下硬件执行断点 @OEP → 运行 → 报错 @004714B1(第一个 IAT 调用) ↓ 内存跟值 → ds 段 → 看到 GetVersion → 确认 004714B1 是 IAT 条目,IAT 被加密 ↓ 在 OEP 处 Dump → 运行崩溃(IAT 未修复) ↓ 修复 IAT:Autosearch 自动 / 手动 RET-ESP 取真地址 / 脚本批量修复 ↓ Fix Dump → 独立运行成功 = 脱壳完成

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询