内嵌补丁(洞穴代码)
测试文件:https://www.lanzous.com/i5o5fhg
1.准备
典型的运行时压缩(或者加密代码),是EP代码先将加密的OEP代码解密,再跳转到OEP处。而若要修改被加密的内容,可以在EP解密代码之后,JMP跳转目标改为“洞穴代码”(此时的代码已被解密),再跳转到OEP。
打开测试文件
2.OD调试
查找所有字符串之后,未找到所需要的字符串。进入
00401001 |. E8 E3000000 call 004010E9
继续进入
004010EF |. E8 A7FFFFFF call 0040109B
2.1 解密地址
通过上图我们可以看到,4010F5区域被解密的两次,即被加密的两次。目前我们还不清楚,被加密的内容是是什么,但我们可以写出解密的结构
解密区域 | 解密起始地址 | 长度 | XOR值 |
B | 4010F5 | 0x154 | 0x44 |
A | 401007 | 0x7f | 0x7 |
B | 4010F5 | 0x154 | 0x11 |
2.2 原OEP跳转
进入
004010B6 |. E8 7EFFFFFF call 00401039
跳转OEP
CTRL + A分析代码
方框内为DialogBoxParamA() API的五个参数,第四个参数用来指出Dialog Box Procedure的地址,入栈顺序和传参顺序相反,因此第四个参数值为DlgProc=004010F5,进入API内(转到4010F5),有我们需要修改的字符串。
3. 制作补丁
3.1 空区域查找
这时候,找到文件的空白区域,打入我们的补丁代码,将解密后jmp地址跳转到补丁地址,再跳转到OEP地址。
使用PEView打开测试文件,查看第一个节区
得到,第一个节区虽然文件大小为400,但是加载到内存的大小只有280,因此我们可以归纳在文件中使用的区域有400~67f,未使用区域680~800;内存中使用区域401000~40127f,未使用区域401280~401FFF
(虽然内存大小为280,但并不意味实际节区的内存大小为280,而要以Section Alignment的倍数扩展(此处为1000),所以内存地址VA范围在401000~401FFF)
转到OD内存中地址
3.2 制作补丁代码
将补丁代码写入到空白区域,并将我们修改的字符写入到ds:[si]中
00401280 > \B9 13000000 mov ecx,0x15 00401285 . BE A8124000 mov esi,unpa4.004012A8 ; ASCII "successful unpackme!" 0040128A . BF 23114000 mov edi,unpa4.00401123 ; ASCII "You must patch this NAG !!!" 0040128F . F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[> 00401291 . B9 10000000 mov ecx,0x12 00401296 . BE C8124000 mov esi,unpa4.004012C8 ; ASCII "I unpack!hkmayfly" 0040129B . BF 0A114000 mov edi,unpa4.0040110A ; ASCII "You must unpack me !!!" 004012A0 . F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[> 004012A2 .^ E9 77FFFFFF jmp unpa4.0040121E
这实际上就是两段将ds:[si]的字符存入es:[si]的代码
4. 解密文件数据
4.1 修改原跳转EOP地址
之后我们再到原来跳转OEP的地方,将jmp地址改为401280
从内存地址401083看,这里是XOR 0x7 A区域的加密区域。因此修改命令之后,我们还需要到文件地址400+83=483处,对483~485进行解密保存
E9 XOR 7 = EE
F8 XOR 7 = FF
01 XOR 7 = 06
E9 F8 01 --> EE FF 06
5.完成补丁
这样就完成了对整个程序的内嵌补丁。