【作者声明】:没什么技术含量,失误之处敬请诸位大侠赐教
【软件名称】: 程序实例见附件
【调试环境】:WinXP sp 2、OD、PEiD、LordPE、ImportREC
高手就飘过吧,接触脱壳有一段时间了,对于脱壳有一些感悟,愿与大家一起分享,对于一般的加密壳,修复正确的iat一般
都是这两种方法,一是在到达oep之前就改magic jump 或者 patch code修复;二是 到达oep之后,查看加密之后的函数调用,
根据其解密的方式编写代码还原,然后IR修复。下面我以UltraProtect加壳的记事本为例,其实这个壳不用这么复杂的,我只是
借这个实例说一下这两种方法,下面实例分析一下:
第一种方法:在到达oep之后修复
这种方法主要是先到达oep,可以用两次内存断点法,最后一次异常法,等等。。。当然了有stolen code 等其他的保护方式要另当别论了,小菜我水平太烂
不忽略内存访问异常
0040D000 > 60 pushad ;加壳后程序入口
0040D001 F9 stc ;F8一下,命令行下断:hr esp 主要是找stolen code,不在本文讨论之列 F9 运行
0040D002 87D6 xchg esi,edx
0040D004 72 03 jb short UltraPro.0040D009
0040D006 73 01 jnb short UltraPro.0040D009
0040D008 7A 81 jpe short UltraPro.0040CF8B
0040D00A F7 ??? ; Unknown command
0040D00B 4A dec edx
0040D00C C49F 9DE80100 es ebx,fword ptr ds:[edi+1E89D] ; Modification of segment register
0040D012 0000 add byte ptr ds:[eax],al
0040D014 E8 83C40466 call 6645949C
0040D019 D3EA shr edx,cl
00415719 CD 01 int 1 ;到达此处
0041571B 40 inc eax ;F2下断 shift + F9 运行 断在此处 取消F2断点 F9
0041571C 40 inc eax
0041571D 0BC0 or eax,eax
0041571F 75 05 jnz short UltraPro.00415726
00415721 90 nop
00415722 90 nop
00415723 90 nop
00415724 90 nop
00415725 61 popad
00415726 33C0 xor eax,eax
00415728 64:8F00 pop dword ptr fs:[eax]
0041572B 58 pop eax
0041572C 60 pushad
0041572D E8 00000000 call UltraPro.00415732
004254C9 55 push ebp ;stolen code 1
004254CA 8BEC mov ebp,esp ;stolen code 2
004254CC 83EC 44 sub esp,44 ;stolen code 3
004254CF 60 pushad
004254D0 60 pushad
004254D1 E8 00000000 call UltraPro.004254D6
此时取消开始下好的硬件 单步F7走到004254d6 对code段下断然后F9 运行 来到这里:
004010D2 56 push esi
004010D3 FF15 E4634000 call dword ptr ds:[4063E4] ; UltraPro.0040D1BA
004010D9 8BF0 mov esi,eax
004010DB 8A00 mov al,byte ptr ds:[eax]
004010DD 3C 22 cmp al,22
004010DF 75 1B jnz short UltraPro.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; UltraPro.0040D4C6
补上stolen code 如下:
004010CC 55 push ebp ;可以在这里新建起源 再dump 不建也可以
004010CD 8BEC mov ebp,esp
004010CF 83EC 44 sub esp,44
004010D2 56 push esi
004010D3 FF15 E4634000 call dword ptr ds:[4063E4] ; UltraPro.0040D1BA
004010D9 8BF0 mov esi,eax
004010DB 8A00 mov al,byte ptr ds:[eax]
004010DD 3C 22 cmp al,22
004010DF 75 1B jnz short UltraPro.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; UltraPro.0040D4C6
LoadPE转存它
我们看到iat加密了
004010CC 55 push ebp
004010CD 8BEC mov ebp,esp
004010CF 83EC 44 sub esp,44
004010D2 56 push esi
004010D3 FF15 E4634000 call dword ptr ds:[4063E4] ; 这里enter键 跟进
004010D9 8BF0 mov esi,eax
004010DB 8A00 mov al,byte ptr ds:[eax]
004010DD 3C 22 cmp al,22
004010DF 75 1B jnz short UltraPro.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; UltraPro.0040D4C6
结果如下:
0040D1BA 68 DD43C07E push 7EC043DD ;在这里我们右键 此处新建eip
0040D1BF 813424 E06C4102 xor dword ptr ss:[esp],2416CE0
0040D1C6 C3 retn ;走到这里出现 返回到 7C812F3D (kernel32.GetCommandLineA)
说明正确的函数已被解出
同样的方法我们可以看看其它函数的解密方式,发现都是这样的,我们开始patch 代码修复吧,在patch之前我们确定一下加密函数的范围,打开IR选中进程,oep 填 10cc, 获取输入表,显示无效的
我们可以看到加密的iat有两段 635c ~63F0, 6414 ~6500,找片空地写下如下代码:
以上面的例子:
0040D1BA 68 DD43C07E push 7EC043DD
0040D1BF 813424 E06C4102 xor dword ptr ss:[esp],2416CE0
0040D1C6 C3 retn
说明一下这段代码:
00404FD4 C7C0 14644000 mov eax,UltraPro.00406414 ;加密函数开始的地址,另外一段将这里改成0040635c
00404FDA 8B18 mov ebx,dword ptr ds:[eax]
00404FDC 43 inc ebx
00404FDD 90 nop
00404FDE 8B0B mov ecx,dword ptr ds:[ebx];7EC043DD 给ecx
00404FE0 81C3 07000000 add ebx,7 ;定位到2416CE0
00404FE6 330B xor ecx,dword ptr ds:[ebx] ;解码
00404FE8 8908 mov dword ptr ds:[eax],ecx ;正确函数地址写入
00404FEA 81C0 04000000 add eax,4 ;处理下一个
00404FF0 81F8 04654000 cmp eax,UltraPro.00406504 ;比较是否处理完,另外一段将这里改成004063f4
00404FF6 ^ 72 E1 jb short UltraPro.00404FD9 ;没处理完则继续
00404FF8 90 nop ;
00404FF9 90 nop
我选在00404fd4 大家可以选在别处,然后在00404fd4处新建起源,在00404ff8处下硬件执行断点,执行这段程序,处理完成后
改一下上面说的两个地址,处理完成之后只有一个无效的,很显然这个是 MessageBoxA
填上之后 全部有效,IR修复dump的文件可以运行。
第二种方法:在到达oep之前修复iat
这种关键是定位处理iat的关键代码,常见的方法是先到达oep然后查找iat的范围,对其下硬件写入断点,基本可以定位到iat处理的地方。也可以结合getprocaddress loadlibrarya等函数来确定,但是不一定有效。
忽略所有异常
对rdata段下断,F9运行,
00418A0F 8B46 0C mov eax,dword ptr ds:[esi+C] ;来到此处 很明显了,这里是取dll的名字
00418A12 0BC0 or eax,eax
00418A14 0F84 C0010000 je UltraPro.00418BDA ;判断所有dll处理完毕
00418A1A 8366 0C 00 and dword ptr ds:[esi+C],0 ;取出之后清零
00418A1E 03C2 add eax,edx ; UltraPro.00400000 加上基址
00418A20 8BD8 mov ebx,eax
00418A22 56 push esi
00418A23 57 push edi
00418A24 50 push eax
00418A25 8BF3 mov esi,ebx ; UltraPro.00406592
00418A27 8BFB mov edi,ebx
00418A29 AC lods byte ptr ds:[esi]
00418A2A C0C0 03 rol al,3
00418A2D AA stos byte ptr es:[edi]
00418A2E 803F 00 cmp byte ptr ds:[edi],0
00418A31 ^ 75 F6 jnz short UltraPro.00418A29 ;解出dll名
00418A33 58 pop eax
00418A34 5F pop edi
00418A35 5E pop esi
00418A36 50 push eax ; UltraPro.00406592
00418A37 FF95 489C4100 call dword ptr ss:[ebp+419C48] ; kernel32.GetModuleHandleA
00418A3D 0BC0 or eax,eax
00418A3F 75 43 jnz short UltraPro.00418A84
00418A41 90 nop
00418A42 90 nop
00418A43 90 nop
00418A44 90 nop
00418A45 53 push ebx
00418A46 FF95 4C9C4100 call dword ptr ss:[ebp+419C4C] ;调用loadlibrarya
00418A4C 0BC0 or eax,eax
00418A4E 75 34 jnz short UltraPro.00418A84
00418A50 90 nop
00418A51 90 nop
00418A52 90 nop
00418A53 90 nop
00418A54 8B95 EA614000 mov edx,dword ptr ss:[ebp+4061EA]
00418A5A 0195 E41B4000 add dword ptr ss:[ebp+401BE4],edx
00418A60 0195 E81B4000 add dword ptr ss:[ebp+401BE8],edx
00418A66 6A 00 push 0
00418A68 FFB5 E41B4000 push dword ptr ss:[ebp+401BE4]
00418A6E FFB5 E81B4000 push dword ptr ss:[ebp+401BE8]
00418A74 6A 00 push 0
00418A76 FF95 549C4100 call dword ptr ss:[ebp+419C54]
00418A7C 6A 00 push 0
00418A7E FF95 509C4100 call dword ptr ss:[ebp+419C50]
00418A84 60 pushad
00418A85 2BC0 sub eax,eax
00418A87 8803 mov byte ptr ds:[ebx],al
00418A89 43 inc ebx
00418A8A 3803 cmp byte ptr ds:[ebx],al ;擦除dll名字
00418A8C ^ 75 F9 jnz short UltraPro.00418A87
00418A8E 61 popad
00418A8F 8985 E2614000 mov dword ptr ss:[ebp+4061E2],eax
00418A95 C785 E6614000 000000>mov dword ptr ss:[ebp+4061E6],0
00418A9F 8B95 EA614000 mov edx,dword ptr ss:[ebp+4061EA]
00418AA5 8B06 mov eax,dword ptr ds:[esi] ;取originalfirstthunk
00418AA7 0BC0 or eax,eax
00418AA9 75 07 jnz short UltraPro.00418AB2
00418AAB 90 nop
00418AAC 90 nop
00418AAD 90 nop
00418AAE 90 nop
00418AAF 8B46 10 mov eax,dword ptr ds:[esi+10]
00418AB2 03C2 add eax,edx
00418AB4 0385 E6614000 add eax,dword ptr ss:[ebp+4061E6]
00418ABA 8B18 mov ebx,dword ptr ds:[eax]
00418ABC 8B7E 10 mov edi,dword ptr ds:[esi+10] ;取firstthunk
00418ABF 03FA add edi,edx
00418AC1 03BD E6614000 add edi,dword ptr ss:[ebp+4061E6]
00418AC7 85DB test ebx,ebx
00418AC9 0F84 FD000000 je UltraPro.00418BCC
00418ACF F7C3 00000080 test ebx,80000000 ;判断是不是序号方式
00418AD5 75 1D jnz short UltraPro.00418AF4
00418AD7 90 nop
00418AD8 90 nop
00418AD9 90 nop
00418ADA 90 nop
00418ADB 03DA add ebx,edx
00418ADD 83C3 02 add ebx,2
00418AE0 56 push esi
00418AE1 57 push edi
00418AE2 50 push eax
00418AE3 8BF3 mov esi,ebx
00418AE5 8BFB mov edi,ebx
00418AE7 AC lods byte ptr ds:[esi]
00418AE8 C0C0 03 rol al,3
00418AEB AA stos byte ptr es:[edi]
00418AEC 803F 00 cmp byte ptr ds:[edi],0
00418AEF ^ 75 F6 jnz short UltraPro.00418AE7 ;解出函数名
00418AF1 58 pop eax
00418AF2 5F pop edi
00418AF3 5E pop esi
00418AF4 81E3 FFFFFF0F and ebx,0FFFFFFF
00418AFA 53 push ebx
00418AFB FFB5 E2614000 push dword ptr ss:[ebp+4061E2]
00418B01 FF95 449C4100 call dword ptr ss:[ebp+419C44] ;getprocaddress
00418B07 3B9D EA614000 cmp ebx,dword ptr ss:[ebp+4061EA]
00418B0D 7C 0F jl short UltraPro.00418B1E
00418B0F 90 nop
00418B10 90 nop
00418B11 90 nop
00418B12 90 nop
00418B13 60 pushad
00418B14 2BC0 sub eax,eax
00418B16 8803 mov byte ptr ds:[ebx],al
00418B18 43 inc ebx
00418B19 3803 cmp byte ptr ds:[ebx],al
00418B1B ^ 75 F9 jnz short UltraPro.00418B16 ;擦除操作
00418B1D 61 popad
00418B1E 0BC0 or eax,eax
00418B20 ^ 0F84 2EFFFFFF je UltraPro.00418A54
00418B26 3B85 549C4100 cmp eax,dword ptr ss:[ebp+419C54] ; USER32.MessageBoxA
是否是特殊的函数
00418B2C 75 0A jnz short UltraPro.00418B38
00418B2E 90 nop
00418B2F 90 nop
00418B30 90 nop
00418B31 90 nop
00418B32 8D85 8D674000 lea eax,dword ptr ss:[ebp+40678D]
00418B38 56 push esi
00418B39 FFB5 E2614000 push dword ptr ss:[ebp+4061E2]
00418B3F 5E pop esi
00418B40 39B5 C1204000 cmp dword ptr ss:[ebp+4020C1],esi ;比较是否是kernel32.dll 是则加密
00418B46 74 15 je short UltraPro.00418B5D ;nop掉 不让它加密
00418B48 90 nop
00418B49 90 nop
00418B4A 90 nop
00418B4B 90 nop
00418B4C 39B5 C5204000 cmp dword ptr ss:[ebp+4020C5],esi ; 比较是否user32.dll 是则加密
00418B52 74 09 je short UltraPro.00418B5D ;nop掉 不让它加密
00418B54 90 nop
00418B55 90 nop
00418B56 90 nop
00418B57 90 nop
00418B58 EB 63 jmp short UltraPro.00418BBD ;不加密路线
00418B5A 90 nop
00418B5B 90 nop
00418B5C 90 nop
00418B5D 80BD 6FCB4000 00 cmp byte ptr ss:[ebp+40CB6F],0
00418B64 74 57 je short UltraPro.00418BBD
00418B66 90 nop
00418B67 90 nop
00418B68 90 nop
00418B69 90 nop
00418B6A EB 07 jmp short UltraPro.00418B73 ;加密路线
00418B6C 90 nop
00418B6D 90 nop
00418B6E 90 nop
00418B6F 0100 add dword ptr ds:[eax],eax
00418B71 0000 add byte ptr ds:[eax],al
00418B73 8BB5 AF624000 mov esi,dword ptr ss:[ebp+4062AF]
00418B79 83C6 0D add esi,0D
00418B7C 81EE DF1B4000 sub esi,UltraPro.00401BDF
00418B82 2BF5 sub esi,ebp
00418B84 83FE 00 cmp esi,0
00418B87 7F 34 jg short UltraPro.00418BBD
00418B89 90 nop
00418B8A 90 nop
00418B8B 90 nop
00418B8C 90 nop
00418B8D 8BB5 AF624000 mov esi,dword ptr ss:[ebp+4062AF]
00418B93 53 push ebx
00418B94 50 push eax
00418B95 E8 A4A5FFFF call UltraPro.0041313E ;加密
00418B9A 8BD8 mov ebx,eax
00418B9C 58 pop eax
00418B9D 33C3 xor eax,ebx
00418B9F C606 68 mov byte ptr ds:[esi],68
00418BA2 8946 01 mov dword ptr ds:[esi+1],eax
00418BA5 C746 05 81342400 mov dword ptr ds:[esi+5],243481
00418BAC 895E 08 mov dword ptr ds:[esi+8],ebx
00418BAF C646 0C C3 mov byte ptr ds:[esi+C],0C3
00418BB3 5B pop ebx
00418BB4 8BC6 mov eax,esi
00418BB6 8385 AF624000 0D add dword ptr ss:[ebp+4062AF],0D
00418BBD 5E pop esi
00418BBE 8907 mov dword ptr ds:[edi],eax ;函数地址写入
00418BC0 8385 E6614000 04 add dword ptr ss:[ebp+4061E6],4 ;继续下一个函数
00418BC7 ^ E9 D3FEFFFF jmp UltraPro.00418A9F
00418BCC 83C6 14 add esi,14
00418BCF 8B95 EA614000 mov edx,dword ptr ss:[ebp+4061EA]
00418BD5 ^ E9 35FEFFFF jmp UltraPro.00418A0F ;继续下一个dll
00418BDA 60 pushad ;这里F4
00418BDB E8 00000000 call UltraPro.00418BE0
00418BE0 5E pop esi
00418BE1 83EE 06 sub esi,6
然后对code 下断,F9即可到达
004010D2 56 push esi
004010D3 FF15 E4634000 call dword ptr ds:[4063E4] ; UltraPro.0040D1BA
004010D9 8BF0 mov esi,eax
004010DB 8A00 mov al,byte ptr ds:[eax]
004010DD 3C 22 cmp al,22
004010DF 75 1B jnz short UltraPro.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; UltraPro.0040D4C6
补上stolen code LoadPE 转存程序,IR修复,同样有一个无效的,显然是MessageBoxA,填上,修复程序可以运行
总结:这是我学脱壳来对iat处理的心得体会,希望对像我一样的的菜鸟有帮助。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!