首页
社区
课程
招聘
脱壳学习日记
发表于: 2006-11-20 13:23 12180

脱壳学习日记

2006-11-20 13:23
12180

最近对一句话认识很深,知识就象一个圆,你知道得越少,那么你不懂的就越少。

前阵子想着开发一个变形代码还原的工具,找了很多资料,学得越多,新的问题就越多,而且一个比一个难,终于到了我无法解决的程度。只好先放下,继续好好学习逆向了。

开一个帖,写上现在和以后脱壳的学习过程,希望有一天可以不需要参考高手们相同壳的分析,写出自己的原创分析。

假如你也准备或者正在学习脱壳,那么我在每篇脱文最前面的心得体会或者对你有帮助。

11月20日

2楼MSLRHv0.31a主程序
3楼MSLRHv0.32a主程序
6楼pe-armor0.74


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (20)
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
2
这东西比较适合练耐性还有就是复习一下各种ANTI DEBUG,还有就是测试一下你OD的抗ANTI能力,假如过不了某写ANTI,就得去找插件或者自己动手了。这里涉及的ANTI有时间校验、ISDEBUG标记、检测Drx、检测INT3、ZwQueryInformationProcess、OUTPUTDEBUGSTRING文件自校验和通过CREATEFILE ANTI DUMP,最后是一个压缩壳。

原程序可在下面连接下载:
http://www.pediy.com/tools/PACK/Protectors/MSLRH/MSLRHv0.31a.rar

这里是已脱壳的程序
http://www.nxer.cn/709394/attachment/1163338396_0.rar

由于有大量时间检查,于是便找来ULTRAEDIT把RDTSC直接替换成XOR EAX,EAX了。运行程序发现出错,有自校验,只好细心跟了,跟了大半天,终于到了自校验的位置,由于不是简单的对比加跳转,必须还原改动过的值。只好去论坛找文章看看有没有更好的方法对付RDTSC。查到前辈写的脱这个的文章,知道了DEJUNK插件,学习了一下,写了下面脚本:

ActivePatList1  = _mslrh01

[CODE_mslrh01]

S = 0f31

R = 33c0

后面有2种解码,分别是XOR 11和XOR 15,所以对应3种情况,替换了825处。

看了前辈的文章之后,对一些之前不明白的ANTI也较为清楚了,下面按流程一步一步列出来。

00456AA0    810424 6F130000 add dword ptr ss:[esp],136F
00456AA7    64:FF35 0000000>push dword ptr fs:[0]
00456AAE    64:8925 0000000>mov dword ptr fs:[0],esp
00456AB5    EB 05           jmp short [MSLRH].00456ABC

装了SEH之后便是

0045745C    33C0            xor eax,eax
0045745E    0FB600          movzx eax,byte ptr ds:[eax]

内存访问错误,进入SEH后继续。大量相同规律的花指令,程序没有乱序,方向总是向下,有意义的代码没怎么花,时间校验的cmp eax,0fff也没花。这是第一次跟这个壳的时候总结的经验,所以可以向下寻找没有花的地方,然后在最接近的cmp eax,0fff直接跳过去,这是第一次跟这个程序时总结出来的经验。

004587B6    8B4424 0C       mov eax,dword ptr ss:[esp+C]
004587BA    33C9            xor ecx,ecx
004587BC    3348 04         xor ecx,dword ptr ds:[eax+4]
004587BF    3348 08         xor ecx,dword ptr ds:[eax+8]
004587C2    3348 0C         xor ecx,dword ptr ds:[eax+C]
004587C5    3348 10         xor ecx,dword ptr ds:[eax+10]
004587C8    8B6424 08       mov esp,dword ptr ss:[esp+8]
004587CC    64:8F05 0000000>pop dword ptr fs:[0]

这里检查dr0到dr3是否为0,没有下硬断,则ecx为0

00459191    51              push ecx
00459192    33C9            xor ecx,ecx
00459194    E8 00000000     call [MSLRH].00459199
00459199    5F              pop edi
0045919A    81C7 C4090000   add edi,9C4
004591A0    5A              pop edx
004591A1    83C2 15         add edx,15
004591A4    0FB60439        movzx eax,byte ptr ds:[ecx+edi]
004591A8    33C2            xor eax,edx
004591AA    880439          mov byte ptr ds:[ecx+edi],al
004591AD    41              inc ecx
004591AE    81F9 93000000   cmp ecx,93
004591B4  ^ 72 EE           jb short [MSLRH].004591A4
004591B6    EB 05           jmp short [MSLRH].004591BD

这段是对00459b5d-00459bf0进行解码(简单的XOR)。假如曾经下过硬断,那么这里的KEY就不对了。正确的是15。解码前要恢复为清除时间校验而覆盖的数据,解码之后再此清除时间校验,后同。

00459B5D    8B5C24 20       mov ebx,dword ptr ss:[esp+20]
00459B61    66:BB 0000      mov bx,0
00459B65    0FB703          movzx eax,word ptr ds:[ebx]
00459B68    2D 4D5A0000     sub eax,5A4D
00459B6D    74 08           je short 复件_[MS.00459B77     
00459B6F    81EB 00000100   sub ebx,10000                              
00459B75  ^ EB EE           jmp short 复件_[MS.00459B65

通过在堆栈中返回系统的地址找KERNEL32的基址。Billy Belceb病毒编写教程里有提到过这种方法。现在EBX是KERNEL32的基址

00459B77    8BFB            mov edi,ebx
00459B79    037B 3C         add edi,dword ptr ds:[ebx+3C]
00459B7C    83C7 78         add edi,78
00459B7F    8B3F            mov edi,dword ptr ds:[edi]
00459B81    03FB            add edi,ebx
00459B83    57              push edi

EDI输出表地址

00459B84    83C7 20         add edi,20
00459B87    8B3F            mov edi,dword ptr ds:[edi]
00459B89    03FB            add edi,ebx
00459B8B    33C0            xor eax,eax
00459B8B    33C0            xor eax,eax
00459B8D    40              inc eax
00459B8E    8B0F            mov ecx,dword ptr ds:[edi]
00459B90    03CB            add ecx,ebx
00459B92    83C7 04         add edi,4
00459B95    8139 47657450   cmp dword ptr ds:[ecx],50746547
00459B9B  ^ 75 F0           jnz short 复件_[MS.00459B8D
00459B9D    8179 04 726F634>cmp dword ptr ds:[ecx+4],41636F72
00459BA4  ^ 75 E7           jnz short 复件_[MS.00459B8D

历遍输出表的AddressOfNames,对比头8个字符识别出GetProcAddress

00459BA6    6BC0 02         imul eax,eax,2
00459BA9    5F              pop edi
00459BAA    57              push edi
00459BAB    83C7 24         add edi,24
00459BAE    8B3F            mov edi,dword ptr ds:[edi]
00459BB0    03FB            add edi,ebx
00459BB2    03F8            add edi,eax
00459BB4    66:8B07         mov ax,word ptr ds:[edi]
00459BB7    6BC0 04         imul eax,eax,4
00459BBA    5F              pop edi
00459BBB    83C7 1C         add edi,1C
00459BBE    8B3F            mov edi,dword ptr ds:[edi]
00459BC0    03FB            add edi,ebx
00459BC2    03F8            add edi,eax
00459BC4    8B7F FC         mov edi,dword ptr ds:[edi-4]
00459BC7    03FB            add edi,ebx
00459BC9    803F CC         cmp byte ptr ds:[edi],0CC
00459BCC   /75 09           jnz short 复件_[MS.00459BD7   

取得GetProcAddress在内存中的位置还不忘检查其入口有没有断点。。。

00459BD7    E8 00000000     call 复件_[MS.00459BDC
00459BDC    58              pop eax
00459BDD    2D EC3A0000     sub eax,3AEC
00459BE2    B0 00           mov al,0
00459BE4    05 00200100     add eax,12000
00459BE9    8BF0            mov esi,eax
00459BEB    891E            mov dword ptr ds:[esi],ebx
00459BED    897E 10         mov dword ptr ds:[esi+10],edi

将KERNEL32的基址存入EP,GetProcAddress则放在EP+10

00459BF7    5F              pop edi
00459BF8    81C7 C4090000   add edi,9C4
00459BFE    0FB60439        movzx eax,byte ptr ds:[ecx+edi]
00459C02    83F0 15         xor eax,15
00459C05    880439          mov byte ptr ds:[ecx+edi],al
00459C08    41              inc ecx
00459C09    81F9 3F0C0000   cmp ecx,0C3F
00459C0F  ^ 72 ED           jb short [MSLRH].00459BFE
00459C11    EB 05           jmp short [MSLRH].00459C18

对0045a5bb-0045b1fa解码,同样是XOR 15。

0045A5D0    E8 00000000     call 复件_[MS.0045A5D5
0045A5D5    832C24 18       sub dword ptr ss:[esp],18
0045A5D9    FF36            push dword ptr ds:[esi]
0045A5DB    FF56 10         call dword ptr ds:[esi+10]                    ; KERNEL32.GetProcAddress

0012FF98   77E60000  KERNEL32.77E60000
0012FF9C   0045A5BD  ASCII "OutputDebugStringA"

指令间穿插字符。。

0045A5DE    8946 14         mov dword ptr ds:[esi+14],eax                 ; KERNEL32.OutputDebugStringA

存进EP+14的位置。似乎EP要被重写为输入表了

下一个API地址的载入方法对于我来说比较新鲜。

0045A5EB    E8 10000000     call 复件_[MS.0045A600
0045A600    FF36            push dword ptr ds:[esi]
0045A602    FF56 10         call dword ptr ds:[esi+10]
0045A605    8946 18         mov dword ptr ds:[esi+18],eax                 ; KERNEL32.GetCommandLineA

0045A5EB处CALL的返回地址竟然是

0045A5F0   47 65 74 43 6F 6D 6D 61 6E 64 4C 69 6E 65 41 00  GetCommandLineA.

把OD的堆栈参考骗过去了,只提示是返回地址,没有字符参考。不过跟进KERNEL32的领域就能显示字符参考了。而且后面将地址保存的时候也有注释,这个技巧意义不大。后面全是类似的技巧和函数的载入,就忽略了。

0045B1C9    8CC9            mov cx,cs
0045B1CB    32C9            xor cl,cl
0045B1CD    83F9 00         cmp ecx,0
0045B1D0    75 28           jnz short 复件_[MS.0045B1FA

上面的代码似乎是检查操作系统的,就不会有后面PEB的检查了。据说如果是WIN9X就会跳走

0045B1D2    64:FF35 3000000>push dword ptr fs:[30]
0045B1D9    58              pop eax
0045B1DA    0FB648 02       movzx ecx,byte ptr ds:[eax+2]
0045B1DE    884E 0C         mov byte ptr ds:[esi+C],cl

将ISDEBUG标记写入0046800C。当然我有插件。

0045B1E1    8B40 0C         mov eax,dword ptr ds:[eax+C]
0045B1E4    8B40 0C         mov eax,dword ptr ds:[eax+C]
0045B1E7    8D58 20         lea ebx,dword ptr ds:[eax+20]
0045B1EA    8D48 18         lea ecx,dword ptr ds:[eax+18]
0045B1ED    8103 C8000000   add dword ptr ds:[ebx],0C8
0045B1F3    B8 00000000     mov eax,0
0045B1F8    0101            add dword ptr ds:[ecx],eax
0045B1FA    33C9            xor ecx,ecx
0045B1FC    E8 00000000     call 复件_[MS.0045B201

改写PEB中程序在内存中的基址和大小信息,大小+0c8,基址+0。有意义?

0045B1FC    E8 00000000     call 复件_[MS.0045B201
0045B201    5F              pop edi                                       ; 复件_[MS.0045B201
0045B202    81C7 C1090000   add edi,9C1
0045B208    0FB60439        movzx eax,byte ptr ds:[ecx+edi]
0045B20C    83F0 11         xor eax,11
0045B20F    880439          mov byte ptr ds:[ecx+edi],al
0045B212    41              inc ecx
0045B213    81F9 521D0000   cmp ecx,1D52
0045B219  ^ 72 ED           jb short 复件_[MS.0045B208
0045B21B    EB 05           jmp short 复件_[MS.0045B222

0045bbc2-0045d914解码,这次是XOR 11

0045C56C    E8 00000000     call [MSLRH].0045C571
0045C571    810424 CA090000 add dword ptr ss:[esp],9CA
0045C578    64:FF35 0000000>push dword ptr fs:[0]
0045C57F    64:8925 0000000>mov dword ptr fs:[0],esp
0045C586    33DB            xor ebx,ebx
0045C588    8B1B            mov ebx,dword ptr ds:[ebx]

安装完SEH就立刻产生内存访问错误进入了。

0045D8DF    8B4424 0C       mov eax,dword ptr ss:[esp+C]
0045D8E3    33C9            xor ecx,ecx
0045D8E5    3348 04         xor ecx,dword ptr ds:[eax+4]
0045D8E8    3348 08         xor ecx,dword ptr ds:[eax+8]
0045D8EB    3348 0C         xor ecx,dword ptr ds:[eax+C]
0045D8EE    3348 10         xor ecx,dword ptr ds:[eax+10]

继续检查DRX

0045DA76    884E 0D         mov byte ptr ds:[esi+D],cl

这里将检查结果存在0046800D了。

0045E42A    FF56 14         call dword ptr ds:[esi+14]                    ; KERNEL32.OutputDebugStringA

0045EDD4    FF56 18         call dword ptr ds:[esi+18]                    ; KERNEL32.GetCommandLineA

0045EDD7    40              inc eax
0045EDD8    33C9            xor ecx,ecx
0045EDDA    41              inc ecx
0045EDDB    803C01 00       cmp byte ptr ds:[ecx+eax],0
0045EDDF    74 0C           je short 复件_[MS.0045EDED
0045EDE1    803C01 22       cmp byte ptr ds:[ecx+eax],22
0045EDE5  ^ 75 F3           jnz short 复件_[MS.0045EDDA
0045EDE7    C60401 00       mov byte ptr ds:[ecx+eax],0
0045EDEB  ^ EB ED           jmp short 复件_[MS.0045EDDA
0045EDED    6A 00           push 0
0045EDEF    6A 00           push 0
0045EDF1    6A 03           push 3
0045EDF3    6A 00           push 0
0045EDF5    6A 00           push 0
0045EDF7    68 00000080     push 80000000
0045EDFC    50              push eax
0045EDFD    FF56 1C         call dword ptr ds:[esi+1C]

一段计算字符长度未经优化的代码。然后是CREATEFILE打开自己,这样就DUMP不了了。修改EIP直接跳过

0045F7A7    837E 40 00      cmp dword ptr ds:[esi+40],0
0045F7AB    74 24           je short [MSLRH].0045F7D1
0045F7AD    FF56 24         call dword ptr ds:[esi+24]
0045F7B0    50              push eax
0045F7B1    6A 00           push 0
0045F7B3    68 00040000     push 400
0045F7B8    FF56 28         call dword ptr ds:[esi+28]
0045F7BB    8BDC            mov ebx,esp
0045F7BD    83EB 04         sub ebx,4
0045F7C0    6A 00           push 0
0045F7C2    6A 00           push 0
0045F7C4    6A 04           push 4
0045F7C6    53              push ebx
0045F7C7    6A 07           push 7
0045F7C9    50              push eax
0045F7CA    FF56 40         call dword ptr ds:[esi+40]
0045F7CD    58              pop eax
0045F7CE    8846 0E         mov byte ptr ds:[esi+E],al

比较ntdll.是ZwQueryInformationProcess否获取成功,获取成功就用该API检查是否被DEBUG,将结果写入0046800E

00460178    8CC9            mov cx,cs
0046017A    32C9            xor cl,cl
0046017C    83F9 00         cmp ecx,0
0046017F    0F84 A1130000   je [MSLRH].00461526
00460185    8B46 38         mov eax,dword ptr ds:[esi+38]
00460188    8078 01 4C      cmp byte ptr ds:[eax+1],4C
0046018C    0F85 94130000   jnz [MSLRH].00461526

检查系统,前半部分检查是不是WIN9X,如果是则通过

SetUnhandledExceptionFilter

在KERNEL32中的偏移来确定具体是哪一个系统?我这里是2K,跳走了

00461ED2    58              pop eax                                       ; [MSLRH].00461ED2
00461ED3    2D E2BD0000     sub eax,0BDE2
00461ED8    B0 00           mov al,0
00461EDA    05 00200100     add eax,12000
00461EDF    8BF0            mov esi,eax
00461EE1    807E 0C 00      cmp byte ptr ds:[esi+C],0
00461EE5    74 51           je short [MSLRH].00461F38
00461F38    807E 0D 00      cmp byte ptr ds:[esi+D],0
00461F3C  ^ 0F85 AF41FFFF   jnz [MSLRH].004560F1
00461F42    74 04           je short [MSLRH].00461F48
00461F44    75 02           jnz short [MSLRH].00461F48

00461F4B    807E 0E 00      cmp byte ptr ds:[esi+E],0
00461F4F  ^ 0F85 9C41FFFF   jnz [MSLRH].004560F1
00461F55    E8 0A000000     call [MSLRH].00461F64

00461F6C    807E 0F 00      cmp byte ptr ds:[esi+F],0
00461F70  ^ 0F85 7B41FFFF   jnz [MSLRH].004560F1
00461F76    50              push eax
00461F77    E8 02000000     call [MSLRH].00461F7E

0046800F不知道是什么的校验值,估计是针对某操作系统的。后面开始自校验了,清除所有断点,还原花指令。

00461F92    59              pop ecx

00461F9D    83E9 05         sub ecx,5

00461FAA    33DB            xor ebx,ebx

00461FB6    B8 9CBE0000     mov eax,0BE9C

00461FC5    8BF9            mov edi,ecx                                   ; [MSLRH].00461F8D

00461FD1    2BF8            sub edi,eax

00461FDD    0FB607          movzx eax,byte ptr ds:[edi]

00461FEA    03D8            add ebx,eax

00461FF6    47              inc edi                                       ; [MSLRH].004560F1

00462001    3BF9            cmp edi,ecx                                   ; [MSLRH].00461F8D

0046200D  ^\72 CE           jb short [MSLRH].00461FDD

计算004560f1到00461f8d的校验和(从花指令入口处到进入自校验之前的代码)

0046200F    BF 00704400     mov edi,[MSLRH].00447000
00462014    B9 00BC0000     mov ecx,0BC00
00462023    0FB607          movzx eax,byte ptr ds:[edi]
00462030    02DF            add bl,bh
00462032    32DF            xor bl,bh
00462034    32C3            xor al,bl
00462040    8807            mov byte ptr ds:[edi],al
0046204C    47              inc edi
00462057    49              dec ecx
00462062  ^\75 B5           jnz short [MSLRH].00462019

对00447000开始大小为BC00的区域解码,KEY就是刚才的校验和。

00462064    E8 00000000     call [MSLRH].00462069
00462069    59              pop ecx
0046206A    2959 16         sub dword ptr ds:[ecx+16],ebx
0046206D    61              popad
0046206E    60              pushad
0046206F    BE 00704400     mov esi,[MSLRH].00447000
00462074    8DBE 00A0FBFF   lea edi,dword ptr ds:[esi+FFFBA000]
0046207A    57              push edi
0046207B    83CD FF         or ebp,FFFFFFFF
0046207E    68 0FDE9F00     push 9FDE0F
00462083    C3              retn

这里的结果仍然跟校验和关联

0046206A    2959 16         sub dword ptr ds:[ecx+16],ebx

之后,最后两条指令便变成

0046207E    68 D0284500     push [MSLRH].004528D0
00462083    C3              retn

跳到下一部分,据前辈的文章说,就是UPX核心了。

004528d8-004529a1是将00447000解压到00401000。

004529e0-00452a1a是填写IAT(在00450fe7获得API名字,将地址填进00415028,就是说没加密)。

用OLLYDUMP下来就完成脱壳了
2006-11-20 13:29
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
3
同一个壳的不同版本,由于有了前一个版本的经验,这次跟起来很轻松,显然经验是大多数新人所欠缺的,只能将勤补拙了。另外一个问题就是,当你遇到你所不知道的ANTI时,你会怎么办?到论坛请教高手?还是尝试自己弄清楚?我只想说,探索精神很重要。有的时候,象这里的例子,其实完全可以自己解决的。此外通过脱这个壳,有的API的运用,其实可以很巧妙,例如本例子中的SetUnhandledExceptionFilter,无论你怎么BP,都是断不下来的。

源程序下载http://emadicius.rvlcnsecurity.com/programas/MSLRHv0.32a.zip

已脱壳的程序
http://www.nxer.cn/709394/attachment/1163728509_0.rar

用OD加载程序时报错。现在用WINDBG载入OD,bp messageboxa。用OD载入MSLRHv0.32a。断下。

0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012c5c8 00454059 00120106 0012c5e0 004bb410 USER32!MessageBoxA
0012cbe4 0045dce7 004bc1ea 063f0050 005bd670 image00400000!Error+0x3d
0012d2d0 0045f7eb 063f0000 76bc1f1c 76bc2075 image00400000!Createlistwindow+0x2af7
00000000 00000000 00000000 00000000 00000000 image00400000!Decoderange+0x180b

在反汇编窗口输入00454059

0045401c 55              push    ebp
0045401d 8bec            mov     ebp,esp
0045401f 81c4fcf9ffff    add     esp,0FFFFF9FCh
00454025 8d450c          lea     eax,[ebp+0Ch]
00454028 50              push    eax
00454029 8b5508          mov     edx,dword ptr [ebp+8]
0045402c 52              push    edx
0045402d 8d8dfcf9ffff    lea     ecx,[ebp-604h]
00454033 51              push    ecx
00454034 e81b2c0500      call    image00400000!Createpatchwindow+0x79f4 (004a6c54)
00454039 83c40c          add     esp,0Ch
0045403c 8d85fcf9ffff    lea     eax,[ebp-604h]
00454042 8b157c3b4d00    mov     edx,dword ptr [image00400000!__CPPdebugHook+0x23a54 (004d3b7c)]
00454048 6810200000      push    2010h
0045404d 6810b44b00      push    offset image00400000!__CPPdebugHook+0xb2e8 (004bb410)
00454052 50              push    eax
00454053 52              push    edx
00454054 e8bdb40500      call    image00400000!Createpatchwindow+0x102b6 (004af516)
00454059 6a00            push    0  ;MESSAGEBOX的返回地址
0045405b e878dafdff      call    image00400000!Animate (00431ad8)
00454060 59              pop     ecx
00454061 8be5            mov     esp,ebp
00454063 5d              pop     ebp
00454064 c3              ret

在00454064下断,返回OD按确定。

0045dcd1 eb30            jmp     image00400000!Createlistwindow+0x2b13 (0045dd03)
0045dcd3 837df402        cmp     dword ptr [ebp-0Ch],2
0045dcd7 7513            jne     image00400000!Createlistwindow+0x2afc (0045dcec)
0045dcd9 8d4e50          lea     ecx,[esi+50h]
0045dcdc 51              push    ecx
0045dcdd 68eac14b00      push    offset image00400000!__CPPdebugHook+0xc0c2 (004bc1ea)
0045dce2 e83563ffff      call    image00400000!Error (0045401c)
0045dce7 83c408          add     esp,8  ;返回到这里
0045dcea eb17            jmp     image00400000!Createlistwindow+0x2b13 (0045dd03)

这里比较EBP-C是否为2,是则弹出错误窗口。

0:000> ? ebp-0c
Evaluate expression: 1233604 = 0012d2c4

重新载入OD,下条件断点

0:000> ba w4 0012d2c4 "r @$t0=poi(0012d2c4);j(@$t0!=2)'g'"

OD载入MSLRHv0.32a。

0045c651 7527            jne     image00400000!Createlistwindow+0x148a (0045c67a)
0045c653 0fb79534faffff  movzx   edx,word ptr [ebp-5CCh]
0045c65a 81c280000000    add     edx,80h
0045c660 8b8da0f9ffff    mov     ecx,dword ptr [ebp-660h]
0045c666 c1e103          shl     ecx,3
0045c669 81c1e0000000    add     ecx,0E0h
0045c66f 3bd1            cmp     edx,ecx
0045c671 7407            je      image00400000!Createlistwindow+0x148a (0045c67a)
0045c673 c745f402000000  mov     dword ptr [ebp-0Ch],2
0045c67a 837df400        cmp     dword ptr [ebp-0Ch],0 ss:0023:0012d2c4=00000002  ;断在这里
0045c67e 7524            jne     image00400000!Createlistwindow+0x14b4 (0045c6a4)

这里对比ebp-5CC和ebp-660。一定条件ebp-0Ch=2。

0:000> db ebp-660
0012cc70  ff 00 00 00 00 00 00 00-00 00 00 00 f8 19 05 00  ................

重新载入OD,下条件断点

0:000> ba w4 0012cc70 "r @$t0=poi(0012cc70);j(@$t0!=ff)'g'"

OD载入MSLRHv0.32a。

eax=0012cc14 ebx=004caf4c ecx=00000020 edx=000000e0 esi=01b028a8 edi=0012cc74
eip=004a3547 esp=0012cb90 ebp=0012cb98 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00200212
image00400000!Createpatchwindow+0x42e7:
004a3547 f3a5            rep movs dword ptr es:[edi],dword ptr [esi] es:0023:0012cc74=00160106 ds:0023:01b028a8=00000000

在内存窗口中输入ESI

01b02908 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ........................
01b02920 00 00 00 00 00 00 00 00 2e 65 64 61 74 61 00 00 00 10 04 00 00 10 00 00  .........edata..........
01b02938 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 e0  ........................
01b02950 2e 65 64 61 74 61 00 00 00 d0 00 00 00 20 04 00 00 c8 00 00 00 04 00 00  .edata....... ..........
01b02968 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 c0 00 00 00 00 03 00 00 00  ............@...........
01b02980 00 30 00 00 00 f0 04 00 00 2c 00 00 00 cc 00 00 00 00 00 00 00 00 00 00  .0.......,..............
01b02998 00 00 00 00 40 00 00 c0 00 00 00 00 00 00 00 00 00 50 00 00 00 20 05 00  ....@............P... ..
01b029b0 00 50 00 00 00 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 e0  .P.................. ...
01b029c8 2e 74 65 78 74 00 00 00 00 10 00 00 00 70 05 00 00 00 00 00 00 48 01 00  .text........p.......H..

象PE头。向上移看看,果然

01b02830 50 45 00 00 4c 01 05 00 fe df 9c 42 00 00 00 00 00 00 00 00 e0 00 0f 01  PE..L......B............
01b02848 0b 01 05 0c 00 30 01 00 00 90 00 00 00 10 04 00 00 20 05 00 00 20 05 00  .....0........... ... ..
01b02860 00 f0 04 00 00 00 40 00 00 10 00 00 00 02 00 00 04 00 00 00 04 00 00 00  ......@.................
01b02878 04 00 00 00 00 00 00 00 00 80 05 00 00 10 00 00 00 00 00 00 02 00 00 00  ........................
01b02890 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 00 00 00 00 ff 00 00 00  ........................
01b028a8 00 00 00 00 00 00 00 00 f8 19 05 00 88 01 00 00 00 f0 04 00 f8 29 00 00  .....................)..

既然是PE,用LORDPE打开MSLRHv0.32a。

可选头部大小 00e0
RVA数及大小  FF

点RVA数及大小旁边的减号

可选头部大小 0850
RVA数及大小  FE

再点加

可选头部大小 0858
RVA数及大小  FF

这两项是相关联的,可见OD中EBP-660和EBP-5CC就是这两项了,校验不正确就报错。程序在系统中能正确运行。RVA数及大小错,只影响OD加载。

0045c671 7407            je      image00400000!Createlistwindow+0x148a (0045c67a)

为了以后对该ANTI 免疫,将上面的JE改成JMP。

现在可以用OD分析了。该壳跟上一版差不多,又是RDTSC海,不过限制宽了,从FF变成FFFF,最多只能防单步,有等于没有。同样是插入宏的方式加花,方向向下,看到有意义的地方直接下断F9过去就好了。相同的地方就不说了,说说不同的地方,不过不代表不需要处理CreateFile。

00453118    64:FF35 0000000>push dword ptr fs:[0]
0045311F    64:8925 0000000>mov dword ptr fs:[0],esp
00453126    33C0            xor eax,eax
00453128    CD 01           int 1
0045312A    40              inc eax
0045312B    40              inc eax

此处在INT 1后下断就可以了。然后是用CREATEMUTEX建立互斥对象,存在则继续,不存在则新建一个进程,自己退出。修改EIP直接跳到后面就可以了。再来是FindWindow,也查IMPORTRECT窗口,最好也自己动手把窗口标题改了。

SetUnhandledExceptionFilter用得有点诡异。

00455216    8B46 38         mov eax,dword ptr ds:[esi+38]  ;[esi+38]=SetUnhandledExceptionFilter
00455219    8B40 0B         mov eax,dword ptr ds:[eax+B]
0045521C    8908            mov dword ptr ds:[eax],ecx     ;ECX是程序自定义的SEH

我们来看看为什么可以这么用

77E678A7 >/$  8B4C24 04     mov ecx,dword ptr ss:[esp+4]
77E678AB  |.  A1 4C04EC77   mov eax,dword ptr ds:[77EC044C]
77E678B0  |.  890D 4C04EC77 mov dword ptr ds:[77EC044C],ecx
77E678B6  \.  C2 0400       retn 4

SetUnhandledExceptionFilter入口点+B的地方刚好是4C04EC77。当然也可以+5。

0045549A    33DB            xor ebx,ebx
0045549C    F7F3            div ebx

除0错误,进入SEH例程,之后便来到最后的自校验了。

该版本跟前一个版本一样,将一些DEBUG的校验放到最后,校验值的存放位置45700c到45700F,处理CREATEMUTEX和CreateFile后,直接在该处下内存断点就能到最后的自校验了,仍然是UPX内核。
2006-11-20 13:41
0
雪    币: 279
活跃值: (145)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
4
学习!历害
2006-11-20 14:06
0
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
5
笨笨雄也来玩壳了,相信会有许多精彩文章出现
2006-11-20 14:07
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
6
从对记事本加壳到最后把壳脱掉,大概用了一星期,但是实际上在分析代码的时间也就几小时。其他时间都在看相关分析文章,或者对着一大堆代码,就是不想分析。

对于这个经典的壳,我想再也没有象我这么简单的分析了。用ATTACH法找到OEP,然后定位加密的数据表,找出数据结构和解密算法,直接用程序自身的解密算法将数据解密,覆盖被加密的部分。ATTACH法是从看雪的精华集看到的,似乎因为局限性,近年好象没怎么看到文章提到,或者你可以通过这篇文章对其了解一下,假如壳只是简单的解密或者解压程序,例如前两篇脱文那种。这个方法可以秒杀那种壳,当然假如目标程序会隐藏进程或者不会进入消息循环,那么这个方法是无能为力的。

加壳的程序

http://www.pediy.com/tools/PACK/Protectors/PE-Armor/PE-Armor0.74.rar

脱掉的记事本

http://www.nxer.cn/709394/attachment/1163996037_0.rar

在主页下了pe-armor0.74,对记事本加壳。运行一下,等了超过1分钟,记事本的窗口才出来,CPU运行都这么久,绝对适合锻炼耐性的壳。佩服那些跟完整个壳的人。看堆栈中的返回地址,一层一层向上,找到伪OEP(真正的被偷掉了)。

重新加载程序,在伪OEP处下内存写入断点,在程序解码完伪OEP之后,在该位置下断。SHIFT+F9来到这个位置。看堆栈看寄存器

EAX 0006FFE0
ECX 00000101
EDX FFFFFFFF
EBX 7FFDF000
ESP 0006FFB0
EBP 0006FFC0

0006FFB0   0006FFE0  指针到下一个 SEH 记录
0006FFB4   010065D0  SE 句柄
0006FFB8   01001888  notepad.01001888
0006FFBC   FFFFFFFF
0006FFC0   0006FFF0
0006FFC4   77E67903  返回到 KERNEL32.77E67903

程序入口点堆栈结尾一般都是C4,储存的是返回系统的地址。一般入口EAX为0,EBP则是XXXXFFF0。现在的堆栈入口是一个SEH,可见包含SEH的装入语句,即
PUSH FS:[0]
mov fs:[0],esp
我们看到EAX=入口堆栈的数据,可知程序是先将FS[0]移入EAX再PUSH的。因此入口点可以修复如下

PUSH EBP
MOV EBP,ESP        ;这两句不需要解释了,几乎都有的
PUSH -1                ;-1=FFFFFFFF
PUSH 01001888
PUSH 010065D0
MOV eax,fs:[0]
push eax
mov fs:[0],esp

然后DUMP下来就好了。运行DUMP,发现出错了,看到错误窗口之后点取消就可以调试了。看堆栈的返回地址,找到出问题的地方,输入表被加密了。现在必须跟踪壳处理输入表的过程。重新载入未脱壳的程序,刚才找到输入表的首址为01001000,在该处下内存写入断点。

002B7E98     8907            mov dword ptr ds:[edi],eax ;写入输入表
002B7E9A     5A              pop edx                ;当前数据位置
002B7E9B     0FB642 FF       movzx eax,byte ptr ds:[edx-1]
002B7E9F     03D0            add edx,eax
002B7EA1     42              inc edx                ;下一个数据的位置
002B7EA2     83C7 04         add edi,4                ;下一个API
002B7EA5     59              pop ecx                ;未处理API数
002B7EA6     49              dec ecx
002B7EA7   ^ 0F85 F7F9FFFF   jnz 002B78A4        ;未完就下一个
002B7EAD     E9 F4280000     jmp 002BA7A6        ;另外的处理流程

--------这里EDX指向一张表

DWORD        RVA,在输入表范围内
BYTE        DLL NAME的长度
STRING        ASCII字符,DLL NAME
DWORD        需要处理的API数

接下来是一个结构
BYTE        长度,数据指针-1取得其长度,指针+长度+1获得下一数据的指针
DATA        加密了的API NAME

跟踪的过程中注意看其指向的内存位置和读取数据的方法,很容易就知道各常量的长度和用途了。

--------回到正题

002B71E5     8B3A            mov edi,dword ptr ds:[edx]        ;输入表中该DLL的起始位置
002B71E7     68 00FE98B7     push B798FE00
002B71EC     50              push eax
002B71ED     E8 5D000000     call 002B724F                ;将代码写到堆栈中并运行

--------堆栈中的代码

0006FF4C     873424          xchg dword ptr ss:[esp],esi
0006FF4F     8B36            mov esi,dword ptr ds:[esi]
0006FF51     81F6 EBFF7108   xor esi,871FFEB
0006FF57     75 19           jnz short 0006FF72

进入堆栈前用的是CALL,如果返回处有INT3,XOR的结果就不为0。

0006FF59     8B7424 50       mov esi,dword ptr ss:[esp+50]
0006FF5D     56              push esi
0006FF5E     8B36            mov esi,dword ptr ds:[esi]
0006FF60     81F6 EBFF7178   xor esi,7871FFEB
0006FF66     75 09           jnz short 0006FF71

这里也是一样ESP+50处是call 002B724F的返回地址,巧妙的ANTI DEBUG。

0006FF68     5E              pop esi
0006FF69     83C6 4C         add esi,4C        ;将刚才对比的地址+4C
0006FF6C     897424 48       mov dword ptr ss:[esp+48],esi
0006FF70     8D7424 58       lea esi,dword ptr ss:[esp+58]
0006FF74     51              push ecx        ;垃圾代码
0006FF75     B9 01000000     mov ecx,1        ;垃圾代码
0006FF7A     8136 EBFF7074   xor dword ptr ds:[esi],7470FFEB
0006FF80     83EE FC         sub esi,-4        ;垃圾代码
0006FF83     49              dec ecx        ;垃圾代码
0006FF84   ^ 75 F4           jnz short 0006FF7A        ;垃圾代码
0006FF86     59              pop ecx        ;垃圾代码
0006FF87     8D7424 58       lea esi,dword ptr ss:[esp+58] ;垃圾代码
0006FF8B     FFD6            call esi
0006FF8D     5E              pop esi
0006FF8E     F3:             prefix rep:
0006FF8F     68 61722B00     push 2B7261 ;被0006FF6C处指令改写
0006FF94     C2 5000         retn 50

进入CALL之后发现还是垃圾。call 002B724F其实就相当于一个短跳转,转向当前位置+4C+5。看来看后面,居然是将EAX还原和释放堆栈。晕!将002B71E7处的代码直接修改为JMP 002B7336,后面就不说类似的代码修复过程了, 直接给出有意义的代码。

---------代码总结如下:

002B71E5     8B3A            mov edi,dword ptr ds:[edx]        ;输入表中该DLL的起始位置
002B7336     0BFF            or edi,edi
002B7338     75 05           jnz short 002B733F
002B733A     E9 6C340000     jmp 002BA7AB

似乎EDI=0即为IAT处理完毕。

002B733F     03BD 36F44000   add edi,dword ptr ss:[ebp+40F436]

RVA+IMG BASE,写入输入表的位置。

002B7494     83C2 05         add edx,5
002B74C4     8BF2            mov esi,edx
002B74C6     56              push esi        ;API的第一个参数(这里是DLLNAME)
002B74C7     8D85 0A624000   lea eax,dword ptr ss:[ebp+40620A]
002B74FA     50              push eax        ;返回地址
002B74FB     8B85 2AF44000   mov eax,dword ptr ss:[ebp+40F42A]
002C0072     6A 00           push 0        ;没搞懂
002C0074     50              push eax        ;调用API的地址(GETMODULEHANDLEA)
002C0075     8B85 1AFD4000   mov eax,dword ptr ss:[ebp+40FD1A]
002C007B     68 00FE2FC7     push C72FFE00
002C0080     50              push eax        ; 缓冲区域
002C0081     E8 5D000000     call 002C00E3

该处实际就是使用GETMODULEHANDLEA取得KERNEL32的基址

---------说明

此后程序将会把API入口点的代码移到缓冲区域,先在缓冲区域运行API入口点的代码,然后再直接跳进API的区域。所以在API入口下断是不行的。此后直接在返回地址下断就可以了。

---------继续分析~~

002B7508     0BC0            or eax,eax        ;判断是否获取成功
002B750A     75 1E           jnz short 002B752A

0006FF90     0FB64E FF       movzx ecx,byte ptr ds:[esi-1]
0006FF94     01CE            add esi,ecx
0006FF96     89F2            mov edx,esi
0006FF99     FFC2            inc edx
0006FF9B     8B0A            mov ecx,dword ptr ds:[edx]
0006FF9D     81E1 00000080   and ecx,80000000

堆栈运行中有这样一段代码,取DLLNAME前面的一个BYTE并与DLLNAME的地址相加后再加1,得到下一个数据的首址。

002B7746     8BF0            mov esi,eax
002B7748     0BC9            or ecx,ecx
002B774A     0F85 62070000   jnz 002B7EB2

此处校验ECX高位是否为80。API数怎么可能占DWORD这么大空间呢。对比EDX指向的表(注意给出的每个DLL数据段的最后4个字节,该处就是ECX读取的地方)。

002C137F                                             D4 12
002C138F   00 00 0C 43 4F 4D 44 4C 47 33 32 2E 44 4C 4C 00  ...COMDLG32.DLL.
002C139F   09 00 00 00                                      ....

002C141F                                                94
002C142F   11 00 00 0B 53 48 45 4C 4C 33 32 2E 44 4C 4C 00  .. SHELL32.DLL.
002C143F   04 00 00 00                                      ...

002C146F                                             44 11
002C147F   00 00 0A 4D 53 56 43 52 54 2E 44 4C 4C 00 13 00  ...MSVCRT.DLL..
002C148F   00 00                                            ..

002C155F                                    00 10 00 00 0C            ...
002C156F   41 44 56 41 50 49 33 32 2E 44 4C 4C 00 07 00 00  ADVAPI32.DLL...
002C157F   00                                               .

002C15DF                                                80
002C15EF   10 00 00 0C 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C  ...KERNEL32.DLL
002C15FF   00 30 00 00 80                                   .0..?

002C18AF               20 10 00 00 09 47 44 49 33 32 2E 44      ...GDI32.D
002C18BF   4C 4C 00 17 00 00 00                             LL....

002C19EF                                 A8 11 00 00 0A 55            ..U
002C19FF   53 45 52 33 32 2E 44 4C 4C 00 46 00 00 80        SER32.DLL.F..?

002C1E2F                     C4 12 00 00 0C 57 49 4E 53 50        ...WINSP
002C1E3F   4F 4F 4C 2E 44 52 56 00 03 00 00 00              OOL.DRV....

只有KERNEL32.DLL和USER32.DLL所在的表有80,在输入表中的RVA分别为1080和11A8,对比之前DUMP出的程序的IAT。

01001070 <>10 17 F4 77 F7 29 F6 77 02 59 F4 77 00 00 00 00  赭?鲼Y赭....
01001080   00 10 02 01 20 10 02 01 40 10 02 01 60 10 02 01  . @`

010011A0 <>4E 7E 56 77 00 00 00 00 00 20 02 01 20 20 02 01  N~Vw.....   
010011B0   40 20 02 01 60 20 02 01 80 20 02 01 A0 20 02 01  @ ` ??

刚好是那些位置被加密了。看来80是API是否被加密的标记,继续跟下去看看它是如何解密的。

002B7EB2     8B0A            mov ecx,dword ptr ds:[edx]
002B7EB4     81E1 FFFFFF7F   and ecx,7FFFFFFF   ;获取需要解密的API数
002B7EBA     51              push ecx
002B7EBB     52              push edx

002B800B     C1E1 05         shl ecx,5
002B800E     6A 04           push 4
002B8010     68 00100000     push 1000
002B8015     51              push ecx
002B8016     6A 00           push 0
002B8018     8D85 2D6D4000   lea eax,dword ptr ss:[ebp+406D2D]
002B801E     50              push eax        ;此为返回地址
002B801F     8B85 32F44000   mov eax,dword ptr ss:[ebp+40F432]
002C0072     6A 00           push 0
002C0074     50              push eax
002C0075     8B85 1AFD4000   mov eax,dword ptr ss:[ebp+40FD1A]
002C007B     68 00FE2FC7     push C72FFE00
002C0080     50              push eax
002C0081     E8 5D000000     call 002C00E3

此处准备调用VirtualAlloc申请空间了。关于call 002C00E3,前面已经解释过了,在返回地址处下断就可以了。

002B802B     8985 82F44000   mov dword ptr ss:[ebp+40F482],eax

保存申请到的空间地址。

002B8197     8907            mov dword ptr ds:[edi],eax
002B8199     83C0 20         add eax,20
002B819C     83C7 04         add edi,4
002B819F     49              dec ecx
002B81A0     0BC9            or ecx,ecx
002B81A2   ^ 75 F3           jnz short 002B8197
002B81A4     59              pop ecx

这里直接从输入表填入加密后的地址,看来输入表解密在后面

002B81D2     58              pop eax
002B81D3     8BF8            mov edi,eax
002B81D5     57              push edi
002B81D6     51              push ecx
002B81D7     E9 8B040000     jmp 002B8667

将加密后的地址传入EDI,准备解密了。

002B81DC     8D47 1C         lea eax,dword ptr ds:[edi+1C]

002B820C     66:C707 FF35    mov word ptr ds:[edi],35FF

写入PUSH DWORD PTR DS:[0]指令。

002B8360     C747 06 8134240>mov dword ptr ds:[edi+6],243481

XOR DWORD PTR SS:[ESP],0的形式。

002B84B6     8947 02         mov dword ptr ds:[edi+2],eax

把前面的指令改写为PUSH DWORD PTR DS:[75001c]。

002B84E6     C647 0D C3      mov byte ptr ds:[edi+D],0C3

写入RETN

002B865F     8947 09         mov dword ptr ds:[edi+9],eax

该处经过一些复杂的运算,用RDTSC随机生成一个密钥。

--------总结

输入表中加密的地址为20H对齐,750000处的代码为

00750000    FF35 1C007500   push dword ptr ds:[75001C]
00750006    813424 5BDE27CD xor dword ptr ss:[esp],CD27DE5B
0075000D    C3              retn

75001C处保存加密过的数据。

--------回到正题

002B8662     5A              pop edx
002B8663     83C7 20         add edi,20
002B8666     49              dec ecx
002B8667     0BC9            or ecx,ecx
002B8669   ^ 0F85 6DFBFFFF   jnz 002B81DC

这里判断是否需要处理下一个加密数据地址,直接在后面下断跳出循环

002B866F     59              pop ecx
002B8670     5F              pop edi
002B8671     83C2 04         add edx,4
002B8674     51              push ecx
002B8675     0FB602          movzx eax,byte ptr ds:[edx]
002B8678     0BC0            or eax,eax
002B867A     0F85 B4090000   jnz 002B9034

进入下一个循环,先跟一次看看是干什么的

002B9034     42              inc edx
002B9035     52              push edx
002B9036     60              pushad
002B9037     68 FF559EB6     push B69E55FF
002B903C     8BF2            mov esi,edx
002B903E     68 3E3F8F00     push 8F3F3E
002B9043     8DBD FCF94000   lea edi,dword ptr ss:[ebp+40F9FC]
002B9049     68 00FE98C7     push C798FE00
002B904E     50              push eax
002B904F     E8 5D000000     call 002B90B1

002B9043处取解密API的缓存区

002B91A4     0FB64E FF       movzx ecx,byte ptr ds:[esi-1] ;取字符长度

0006FF68     50              push eax
0006FF69     AC              lods byte ptr ds:[esi]
0006FF6A     34 79           xor al,79
0006FF6C     2C 55           sub al,55
0006FF6E     C0C0 03         rol al,3
0006FF71     F6D0            not al
0006FF73     AA              stos byte ptr es:[edi]
0006FF74     31C0            xor eax,eax
0006FF76     49              dec ecx
0006FF77   ^ 75 F0           jnz short 0006FF69
0006FF79     AA              stos byte ptr es:[edi]
0006FF7A     58              pop eax

在堆栈中解密数据,得到的是一个API NAME。到这里,EBX指向的那个表所有常量的结构和用法都很清楚了。我直接写了代码还原表中的加密的API NAME,然后用直接用GetProcAddress取地址,按顺序排成一张表,再手动覆盖原来被加密的IAT,最后用IMPORTRECT修复就OK了。

002B7E97     60              pushad
002B7E98     8BEC            mov ebp,esp
002B7E9A     BE EE152C00     mov esi,2C15EE

此处把表的入口传给ESI,手动修改。反正只有两个表被加密。

002B7E9F     8B3E            mov edi,dword ptr ds:[esi]
002B7EA1     83C6 05         add esi,5
002B7EA4     56              push esi
002B7EA5     B8 DB56E777     mov eax,KERNEL32.GetModuleHandleA
002B7EAA     FFD0            call eax
002B7EAC     50              push eax
002B7EAD     0FB646 FF       movzx eax,byte ptr ds:[esi-1]
002B7EB1     03F0            add esi,eax
002B7EB3     46              inc esi
002B7EB4     0FB60E          movzx ecx,byte ptr ds:[esi]
002B7EB7     83C6 04         add esi,4
002B7EBA     51              push ecx
002B7EBB     0FB60E          movzx ecx,byte ptr ds:[esi]
002B7EBE     46              inc esi
002B7EBF     57              push edi
002B7EC0     AC              lods byte ptr ds:[esi]
002B7EC1     34 79           xor al,79
002B7EC3     2C 55           sub al,55
002B7EC5     C0C0 03         rol al,3
002B7EC8     F6D0            not al
002B7ECA     AA              stos byte ptr es:[edi]
002B7ECB     33C0            xor eax,eax
002B7ECD     49              dec ecx
002B7ECE   ^ 75 F0           jnz short 002B7EC0
002B7ED0     AA              stos byte ptr es:[edi]

002B7ED7     8B0C24          mov ecx,dword ptr ss:[esp]
002B7EDA     51              push ecx
002B7EDB     8B45 FC         mov eax,dword ptr ss:[ebp-4]
002B7EDE     50              push eax
002B7EDF     B8 4B56E777     mov eax,KERNEL32.GetProcAddress
002B7EE4     FFD0            call eax
002B7EE6     85C0            test eax,eax
002B7EE8     74 10           je short 002B7EFA

此处跳转需要说明一下,有时解密后的API NAME的后面会包含多余字符,所以当获取API地址失败时便把最后一个字节填00

002B7EEA     5F              pop edi
002B7EEB     8907            mov dword ptr ds:[edi],eax
002B7EED     83C7 04         add edi,4
002B7EF0     46              inc esi
002B7EF1     59              pop ecx
002B7EF2     49              dec ecx
002B7EF3   ^ 75 C5           jnz short 002B7EBA
002B7EF5     61              popad
002B7EF6     CC              int3

002B7EFA     4F              dec edi
002B7EFB     4F              dec edi
002B7EFC     AA              stos byte ptr es:[edi]
002B7EFD   ^ EB D8           jmp short 002B7ED7

看关于这个壳的分析文章时,有提及关于特殊代码加密的问题。虽然我没有使用这个功能加壳,还在学习中,不想搞得太复杂,不过在上述的表中的末尾,有这样一个表

002C0AFD               00 58 44 4C 4C 2E 44 4C 4C 00 46 75      DLL.DLL.Fu
002C0B0D   6E 63 32 46 75 6E 63 00 54 65 73 74 44 65 62 75  nc2Func.TestDebu
002C0B1D   67 00 45 6E 43 72 79 70 74 00 44 65 43 72 79 70  g.EnCrypt.DeCryp
002C0B2D   74 00 43 52 43 00 54 65 73 74 42 6D 70 00 43 72  t.CRC.TestBmp.Cr
002C0B3D   65 61 74 65 44 69 61 6C 6F 67 50 61 72 61 6D 41  eateDialogParamA
002C0B4D   00 44 69 61 6C 6F 67 42 6F 78 50 61 72 61 6D 41  .DialogBoxParamA
002C0B5D   00 45 78 69 74 50 72 6F 63 65 73 73 00 46 72 65  .ExitProcess.Fre
002C0B6D   65 52 65 73 6F 75 72 63 65 00 47 65 74 50 72 6F  eResource.GetProcAddress
002C0B7D   63 41 64 64 72 65 73 73 00 47 65 74 56 65 72 73  cAddress.GetVers
002C0B8D   69 6F 6E 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E  ion.GetModuleHan
002C0B9D   64 6C 65 41 00 47 65 74 43 75 72 72 65 6E 74 50  dleA.GetCurrentP
002C0BAD   72 6F 63 65 73 73 00 47 65 74 43 75 72 72 65 6E  rocess.GetCurren
002C0BBD   74 50 72 6F 63 65 73 73 49 64 00 47 65 74 43 6F  tProcessId.GetCo
002C0BCD   6D 6D 61 6E 64 4C 69 6E 65 41 00 4C 6F 61 64 4C  mmandLineA.LoadL
002C0BDD   69 62 72 61 72 79 41 00 4C 6F 63 6B 52 65 73 6F  ibraryA.LockReso
002C0BED   75 72 63 65 00 53 65 6E 64 4D 65 73 73 61 67 65  urce.SendMessage
002C0BFD   41 00 73 65 6E 64 00 72 65 63 76 00 00           A.send.recv..

程序在解密API NAME之后再对比是否上述表中的API,似乎对比成功之后就特别照顾。我这么修复IAT,似乎也能解决特定API加密。
2006-11-20 14:15
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
7
暂时还停留于自己摸索,不行就参考高手文章的阶段,感觉这样印象会深一点,要不只看文章,不自己动手,实在看不明白高手文章里说什么

说到精彩文章,也许要你们耐性点等我提升水平了
2006-11-20 14:29
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
认真学习一下
2006-11-20 15:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
呵呵,好好跟你学习一下,
不知楼主收徒弟吗?
我想拜师学业呀。
2006-11-20 16:45
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
10
最初由 pengym 发布
呵呵,好好跟你学习一下,
不知楼主收徒弟吗?
我想拜师学业呀。


我,也在弄壳。
2006-11-20 17:13
0
雪    币: 331
活跃值: (56)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
11
问一下.hying的壳似乎用了断点很容易就GameOver.楼主有啥好办法?
2006-11-21 05:15
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
12
如果是主页上的那个

该壳使用API时会在该API的入口抽几段代码放到申请的空间中,然后生成一个跳转直接跳到API内部,具体抽多少没细心看。你可以试试进入目标API领域,对NTDLL的一些关键API下断。

一些关于那个壳的分析文章,有提过对特殊API加密其实就是完全模拟该API。例如GETMOUDLENAME,可以用PEB表中+0x00c Ldr结构来模拟。GETPROCADDRESS则可以通过查询导出表

我没有具体看过系统的GETMOUDLENAME和GETPROCADDRESS是怎么做的,如果原理是一样的,那么在PEB+0x00c处下硬件断点大概就是断下来的唯一方法了。

希望这点看法对你有用
2006-11-21 11:26
0
雪    币: 331
活跃值: (56)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
13
6个字:
学习,学习,学习~
2006-11-21 11:45
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
学了一个月,没有什么进步
2006-11-21 13:39
0
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
15
一个字,强!
2006-11-21 13:40
0
雪    币: 213
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
ZwQueryInformationProcess
这个如何扰过呢
有插件吗?
在哪里呢?
2006-11-21 13:57
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
17
搜索词:ZwQueryInformationProcess

范围:工具下载
2006-11-21 14:30
0
雪    币: 898
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
18
笨笨雄 脱壳很有劲头啊
支持一下
脱壳界再出牛人
2006-11-21 14:39
0
雪    币: 214
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
厉害,看来楼主该改名叫聪明雄了
2006-11-22 16:48
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
谢谢版主..这些新人文章很需要...
我会长期来锻炼
2006-11-28 01:44
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
学习了。很精彩。
2006-11-28 12:39
0
游客
登录 | 注册 方可回帖
返回
//