尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

win脱壳6 -- windows 脱壳思路 技术总结

win脱壳6 -- windows 脱壳思路 技术总结 目录ESP 定律 IAT 去混淆脚本修复 -- 脱壳技术分析一、先对号入座这套方法适用于什么壳二、核心原理三大支柱支柱 1壳的生命周期是一段固定模式的代码序列支柱 2ESP 定律支柱 3IAT 混淆规律Junk RET三、完整流程六步闭环脱壳全程地图四、关键技术细节清单4.1 断点选择4.2 步进选择4.3 OEP 判定标准怎么确认真找到了4.4 定位 IAT 的方法论4.5 样本关键数据脱壳全程的坐标4.6 Dump 时机与工具五、脚本核心资产完整版 设计拆解六、核心公式与知识总结七、常见坑速查表八、免杀项目视角脱壳能力在免杀项目中的三个用途反向应用ESP 定律 IAT 去混淆脚本修复 -- 脱壳技术分析一、先对号入座这套方法适用于什么壳判断维度适用不适用虚拟化壳壳入口特征pushad/pushfd保存现场无 pushad入口即虚拟化分发原始代码处理内存中解压/解密可还原指令翻译成虚拟机字节码无法还原IAT 处理Junk stub RET 重定向深度虚拟化无显式 IAT代表UPX、ASPackVMProtect、Themida识别方法DIE 查壳名 观察入口指令。入口以 pushad/pushfd 开头 → 本方法可直接上。看到 0xCC 反调试、花指令堆砌、入口即巨型分发器 → 换思路。二、核心原理三大支柱支柱 1壳的生命周期是一段固定模式的代码序列pushad ; ① 保存 8 个通用寄存器现场 pushfd ; ② 保存标志位寄存器 call 壳核心函数 ; ③ 解密/解压、重定位、重建 IAT壳的正事 ... ; 中间过程不用分析 popfd / popad ; ④ 恢复现场 ← 壳寿终正寝的信号 jmp OEP ; ⑤ 跳回原始入口 ← 要抓的就是这一跳推论脱壳不需要读懂壳代码只需要识别壳的收尾点。壳的执行路径是固定模式压栈 → 干活 → 弹栈 → 跳转找到恢复现场就找到了 OEP。支柱 2ESP 定律pushad 把 8 个寄存器的值压入栈中此后只有 popad 会再次访问这些值对当前 ESP 下硬件访问断点→ 壳收尾执行 popad 时必然踩中 → 断点命中 壳运行完毕、代码已解密断点命中后向下看跳转指令的下一条或跳转目标就是 OEPpushad 执行后 → ESP 指向压栈区域 → 下硬件访问断点 ↓ popad 读取栈 → 断点命中 → 壳跑完了 ↓ 向下找 jmp / jmp eax → F7 跟进 → OEP支柱 3IAT 混淆规律Junk RETcall [IAT条目] ← 代码里的调用 ↓ IAT条目 → 壳stub地址 ← 不再是 API 地址混淆的真相 ↓ stub 内一堆 junk 垃圾指令push/pop/add esp无意义 ↓ RET ← stub 必然以 RET 收尾 ↓ RET 弹出 [ESP] 上的值 → 跳到真实 API关键认知混淆是绕路不是消失。程序要正常工作就必须真正调用 GetVersion、GetProcAddress 这些 API——真实地址必然在某处出现本样本规律RET 执行前 ESP 上就是真地址。去混淆 找到它出现的位置并抓回来。三、完整流程六步闭环脱壳全程地图Step 0 壳识别 DIE 查壳名 → 确认传统壳 → 确认入口 pushad 特征 ↓ Step 1 找 OEP (5.2) 停EP → F8过pushad → 对ESP下硬件访问断点 → F9 → 命中在popad → 找跳转 → F7跟进 → OEP ↓ Step 2 Dump验证 (5.3) OEP处Scylla Dump → 运行崩溃 → 判定IAT未修复必然翻车点不是工具坏了 ↓ Step 3 定位IAT (5.4) OEP下硬件执行断点 → 运行 → 第一处call[IAT]报错 → 内存跟值 → ds段看到GetVersion → 确认IAT位置 ↓ Step 4 分析混淆 (5.5) IAT区域全是call/jmp → 确认JunkRET模式 → 手动验证1~2条规律成立 ↓ Step 5 脚本修复 (5.6/5.7) .scr脚本批量遍历IAT → 逐条回填真实API地址 ↓ Step 6 重新Dump (5.7) Scylla → 获取导入表成功 → 独立运行成功 ✅两条暗线贯穿全程时机线壳没跑完Step 1 之前→ 内存里是密文一切无从谈起壳跑完停在 OEP → 内存状态最干净。因果线崩溃Step 2暴露 IAT 问题Step 3 定位→ 分析混淆规律Step 4→ 设计并执行修复Step 5→ 修复后重新 dump 才能得到健康文件Step 6。一次 dump 不够修复后必须重新 dump。四、关键技术细节清单4.1 断点选择断点类型用途特点 / 坑软件断点F20xCC常规断点改写代码字节强壳完整性自校验会检测到 → 脱壳慎用硬件执行断点OEP 观察、定位 IAT用 CPU 调试寄存器 DR0~DR3不修改代码最多 4 个硬件访问断点ESP 定律等 popad读栈时命中断点类型选 Access不是 Execute内存断点64 位替代方案对 .text 下访问断点等壳解压后第一次读原始代码时命中4.2 步进选择操作用在哪F7 步入call壳核心函数必须进壳的工作在里面jmp eax间接跳转必须进才能看到真实地址stub 内部F8 步过pushad、普通指令F4 运行到光标跳过解密大循环别傻傻单步4.3 OEP 判定标准怎么确认真找到了跳转目标之后是函数序言push ebp; mov ebp,esp32 位/sub rsp, xx64 位代码呈线性结构正常函数调用不再有解密循环最终验证dump 修复后DIE 能看到原始编译器特征4.4 定位 IAT 的方法论在 OEP 下硬件执行断点 → F9 让原始代码跑起来 → 代码执行到第一处 call [IAT] → 拿到的是 stub 地址 → 跳转报错 → 报错的那一行如 004714B1就是 IAT 条目 → 内存跟值 → 跨段ds→ 看到 GetVersion → 100% 确认报错行 ≠ 崩溃位置报错行是call [IAT]指令本身崩溃发生在跳转之后的无效地址。两者要分清。4.5 样本关键数据脱壳全程的坐标项值模块基址0x00400000OEP0x0047148Bpush ebp函数序言OEP RVA0x7148BOEP − 基址Scylla 里填这个IAT 首地址0x00475000存放 stub 地址 0x005E2264IAT 实际有效范围0x00475080 ~ 0x00475120IAT 结束地址0x00475120不包含条目步长4 字节32 位→ 共约 72 个条目stub 收尾标志RET0xC3RET 前 [ESP] 真实 API 地址4.6 Dump 时机与工具时机必须停在 OEP未执行原始代码此时代码已解密 ✅、IAT 已重建 ✅、无运行时副作用 ✅工具链x64dbg Scylla首选Dump 修复一站式、ImportREC老牌、OllyDump、LordPE、Process Hacker纯取证不用于脱壳五、脚本核心资产完整版 设计拆解bc ; 清所有普通断点 bpmc ; 清所有内存断点 bphc ; 清所有硬件断点 StepInto 2 ; 单步步入2次执行过 pushadESP 指向压栈区 bph esp4, r, 4 ; esp4 下读型硬件断点4字节 g ; 运行 → popad 读栈命中 → 壳运行完毕 StepInto 3 ; 再步入3次越过 popad进入跳向 OEP 区域 $dwIatBegin 0x00475000 ; IAT 遍历起点 $dwIatEnd 0x00475120 ; IAT 遍历终点 IATLOOP: mov $dwIatItemAdr, dword [$dwIatBegin] ; 读条目值stub地址 cmp $dwIatItemAdr, 0 ; 判空条目 jz IATNEXT ; 为0跳过防误改空白区 mov EIP, $dwIatItemAdr ; 模拟 call [IAT]进入 stub STEPLOOP: sti ; 单步步入F7 mov $byteCode, byte:[EIP] ; 读当前指令首字节 cmp $byteCode, 0xC3 ; 判断 RET jnz STEPLOOP ; 不是RET继续走junk mov $FindFuncAdr, dword [ESP] ; ★RET前读ESP 真实API地址 mov [$dwIatBegin], $FindFuncAdr ; ★回填IAT条目 ← 修复完成 IATNEXT: add $dwIatBegin, 4 ; 下一个条目步长4 cmp $dwIatBegin, $dwIatEnd jne IATLOOP ret脚本的三段式结构对应三大支柱段落做什么对应原理① 清场BC / BPMC / BPHC避免残留断点干扰② ESP 定位StepInto 2 → bph esp4 → g → StepInto 3ESP 定律自动化把程序带到壳跑完、代码解密、IAT 重建的状态③ IAT 遍历循环 判 0 EIP 指向 STI 到 RET 回填JunkRET 规律批量抓真地址关键设计决策范围取宽0x75000 起实际有效 0x75080 起——故意多遍历靠判 0 跳过兜底防止漏掉条目。为什么读 ESP 要在 RET 之前脚本停在 RET 指令上未执行此时 [ESP] 是 RET将要弹出的值执行完 RET 再读ESP 已移动拿不到了。STI 循环而不是直接跑junk 指令无规律只有 RET 是确定的收尾标志所以一条条单步到 RET。EIP [条目]模拟call [IAT]让 stub 自己跑起来吐出真地址无需分析 junk 内容。六、核心公式与知识总结OEP 修复的 IAT 可运行 PE脱壳的本质 找到正确的 OEP壳吐出原始代码的落点 修复被破坏的 IAT把 stub 地址还原为真实 API 地址。两者齐备文件才真正脱离壳独立运行。全部知识点浓缩对应各节总结主题一句话壳边界OEP 是原始入口pushad/popad 标志壳边界找 OEP断点监控恢复现场ESP 定律IAT 与免杀IAT 加密避检测修复填充真地址混淆形式混淆用 Junk RETstub 以 RET 收尾RET 弹出 ESP 真地址修复手段脚本自动化遍历 IAT循环 判 0 回填单步策略STI 单步RET 判断结束最终结果执行修复 IATDump 成功七、常见坑速查表#坑对策1Dump 后运行崩溃不是工具坏了是IAT 未修复——回到 Step 3~62报错行 ≠ 崩溃位置报错行是 call [IAT] 指令崩溃发生在跳转后的无效地址364 位没有 pushad/pushfdESP 定律失效改用对 .text 下内存访问断点条目步长 8DWORD→QWORD4硬件断点只有 4 个用 DR0~DR3省着用用完即清5RET 不只有 0xC3还有RET n0xC2 xx xx脚本判断要扩展6stub 里有 callSTI 会误入子函数误判子函数 RET改用 STO 或加RET 后 [ESP] 是模块内地址双重验证7脚本死循环stub 内可能一直无 RET加步数上限保护先跑 3~5 条验证8脚本修完 ≠ 完成脚本只还原条目里的值Scylla Fix Dump 负责重建导入表结构缺一不可9ASLR/重定位dump 时运行时基址 ≠ 默认基址时需修重定位表否则换机器/加载地址就崩10Get Imports 出现乱码/未知函数IAT 范围没扫全或识别失败手动修正范围11找到 OEP ≠ 脱壳完成OEP Dump Fix IAT 三者缺一不可八、免杀项目视角脱壳能力在免杀项目中的三个用途自测给自己加壳后手动脱一遍——验证壳是否达到静态不可识别的目的用攻击者的手验证防御者的眼。对抗了解杀软内存脱壳引擎的工作方式找 OEP、识别 stub 规律反推自己壳的设计。分析研究真实恶意样本的壳和混淆手法。反向应用脱壳方的抓手加壳方的反制pushad → popad 固定模式打乱保存现场方式x64 天然没有 pushadstub 统一junk RET规律stub 多样化、多层套娃、花指令RET 前 ESP 暴露真地址不在 RET 暴露用 call 直接转、混淆 ESP硬件断点不被检测用完整性自校验检测 0xCC 软件断点、反调试检测 DR 寄存器单步可控反单步时间检测、异常机制打断单步流清醒认知现代 EDR 重心已从静态扫描转向行为检测沙箱、内存扫描、API 钩子监控。加壳只能骗过静态这一层——payload 在内存解压后行为照样被看见。壳是免杀整体方案的一环不是全部。九、学习路径延伸样本pushad Junk-RET 混淆✅ 已掌握 ↓ UPX 手动脱壳单步法 / ESP 定律各脱一遍——结构标准验证基本功 ↓ ASPack / ASProtect —— 引入反调试学 ScyllaHide 绕过 ↓ 64 位样本 —— 无 pushad重学断点策略 ↓ 强壳VMProtect / Themida—— 知道脱壳在这里已升级为反虚拟化即可写壳脱壳框架的泛化方向把脚本参数化IAT 范围、步长、RET 判定、stub 模式判 0 / 判 RET / 步数上限都做成可配置壳变体越多识别规则越要灵活——规律识别找收尾模式比硬编码地址更接近框架可研究 x64dbgpyPython API写更复杂的自动化或 Scylla 自动化接口
返回列表