脱壳——pediy 加密壳
关于程序连接:
,,,火绒爆毒,就不传程序链接了,,,
寻找OEP
-
首先(PEiD)查看下链接器版本
- VC 6.0?
- 使用 OD 打开,发现 pushad/pushfd(妥妥的 ESP定律 呀)
- F9 运行后断下,再 F7 单步,发现 jmp 到远处
- 进入,发现
sub esp, 0x58
,又因为根据链接器版本,猜测是 VC6.0,所以进入第一个 call 验证
- F7 单步步入验证(果然是呢),OEP位置确认(dwOEP 0047148B),但是 IAT 被加密了
IAT 加密问题
-
所以需要在填充IAT处,下硬件写入断点
- 首先找到 IAT地址
- 下硬件写入断点
- 重新运行后
-
此处是填充 IAT 的地方,即 dwWriteAddr
-
但是观察不到明显特征;
- 按住 F7 运行,观察寄存器变化
- ESI 是要填入的字符串,可看到名称
- EDX(无规则) 应该是哈希值
- EAX 字符串单个字母的 ASCII(hex)
- 按住 F7 运行,观察寄存器变化
-
【循环】—— 省略一些 call + lea;并观察何时跳出循环
-
F2 下断,跳出查看后续,发现
cmp
,又一处跳出条件 -
继续 F7 运行
- 下断,使其运行在比较结果相等后
-
不要着急,继续F7单步运行,终于发现
Getversion
API 函数地址- dwGetAPIAddress
编写脚本(OllySubScript 编写)
脚本思路
- 先获取程序运行基址 -> (基址+偏移)算出正确的获取API函数命令的地址,填充API命令的地址 ->
// 1.初始化地址
MOV dwGetAPIAddr,00001914
MOV dwWriteAddr,00000897
MOV dwOEP,0047148B
MOV dwBase,0047A37F
// 2.设置断点
BC // 清除所有软件断点
BPHWC // 清除所有硬件断点
BPMC // 清除所有内存断点
BPHWS dwBase, "x"
BPHWS dwOEP, "x" //当执行到此地址时产生中断
LOOP1:
RUN // 相当于在OllyDbg中按 F9
CMP dwBase,eip
JNZ CASE0
ADD dwGetAPIAddr,eax // eax 保存的是程序基址
ADD dwWriteAddr,eax
BPHWS dwGetAPIAddr, "x" //当执行到此地址时产生中断
BPHWS dwWriteAddr, "x" //当执行到此地址时产生中断
BPHWC dwBase
JMP LOOP1
CASE0:
CMP dwGetAPIAddr,eip
JNZ CASE1 // 如果不是就比较下一个,如果是就可以保存函数地址了
MOV dwTemp,eax // eax 保存 API函数地址
JMP LOOP1
CASE1:
CMP dwWriteAddr,eip
JNZ CASE2
MOV [edx],dwTemp // 根据原加壳程序,填充至 edx 处
JMP LOOP1
CASE2:
CMP dwOEP,eip
JNZ LOOP1
MSG "修复完成"
解决基址问题
-
由于壳代码填充 IAT 的代码是在【申请的内存中执行】,每次申请的空间是伪随机的
- 所以采用基址+偏移的方式
-
双击栈中 VirtualAlloc 那行,返回调用它的地址
- 并在它的下行命令下断(因为返回值 eax 是程序的 加载基址)
- 所以 dwBase 0047A37F
- 脚本运行效果:录制了个动图,因为图片大小限制在5MB,只截取了一部分