单步法手脱PECompact 2.5 Retail - Jeremy Collake

  这是我的学习笔记,毕竟刚学破解,牛人们看了不要笑话我这入门级的水平,给我鼓励就好了。

  在学习黑鹰三人行的视频教程“6、手脱PECompact”中,当讲到脱PECompact 2.5这个壳时,老师用的方法是下断点BP VirtualFree和查找 push 8000(特征码)的方法,至于为什么要这样,老师说“现在也只能告诉你,脱壳时通过下这个断点,可以跳过壳的加密,现在也只能告诉大家这些。每一个壳都有一种套路。这个是经验。”

  作为新手的我,听了这话,只得不知其所以然地强记老师的方法,相信很多新手此时都是无奈的,知识断档了。可是看过之后,觉得不甘心,老师的经验也是通过跟踪得来的呀,作为新手,不是正需要从基础锻炼起吗?于是就单步法反复跟踪,终于成功了。高兴之余,就想百度查一下别人是不是和我的方法相同,一查才知道脱这个壳的教程不多,竟然全部是用下断点BP VirtualFree和查找 push 8000(特征码)的方法!所以,我将自己的学习笔记贴上来,也可给新手们一个参考。好了,借用老师的一句话:废话不多说,回到正题!

  带壳软件:加了PECompact 2.5 Retail -> Jeremy Collake壳的Win98下的记事本NotePad.exe(这里命名为PECompact 2.55.EXE)
  脱壳软件:OllyICE、PEiD、LordPE、ImportREC_fix

  一、查壳
  PEiD查出壳为PECompact 2.5 Retail -> Jeremy Collake

  二、找OEP
  设置Ollydbg忽略所有的异常选项,载入PECompact 2.55.EXE文件,提示“你仍要继续分析吗?”选“否”。

01001000 >  B8 90BA0101         mov     eax, PECompac.0101BA90        ; 载入时停在这里,F8单走
01001005    50                  push    eax
01001006    64:FF35 00000000    push    dword ptr fs:[0]
0100100D    64:8925 00000000    mov     dword ptr fs:[0], esp
01001014    33C0                xor     eax, eax
01001016    8908                mov     dword ptr ds:[eax], ecx       ; 这行F8后自动跳转
01001018    50                  push    eax                     
01001019    45                  inc     ebp
0100101A    43                  inc     ebx

7C92E480  |.  8B1C24            mov     ebx, dword ptr ss:[esp]       ; 自动跳转到这里。此处是系统空间,不可Alt+F9回到用户代码,否则后面会无法继续跟踪,加密惹的祸^_^,继续F8
7C92E483  |.  51                push    ecx
7C92E484  |.  53                push    ebx
7C92E485  |.  E8 B35A0200       call    ntdll.7C953F3D                ; 可F8步过
7C92E48A  |.  0AC0              or      al, al
7C92E48C  |.  74 0C             je      short ntdll.7C92E49A
7C92E48E  |.  5B                pop     ebx
7C92E48F  |.  59                pop     ecx
7C92E490  |.  6A 00             push    0
7C92E492  |.  51                push    ecx
7C92E493  |.  E8 C6EBFFFF       call    ntdll.ZwContinue              ; 必须F7跟进!否则一直停在“运行”状态无法继续
7C92E498  |.  EB 0B             jmp     short ntdll.7C92E4A5
7C92E49A  |>  5B                pop     ebx
7C92E49B  |.  59                pop     ecx

7C92D05E >/$  B8 20000000       mov     eax, 20                       ; 跟进到了这里,继续F8
7C92D063  |.  BA 0003FE7F       mov     edx, 7FFE0300
7C92D068  |.  FF12              call    dword ptr ds:[edx]            ; 必须F7跟进!否则一直停在“运行”状态无法继续
7C92D06A  \.  C2 0800           retn    8
7C92D06D      90                nop

7C92E510 >/$  8BD4              mov     edx, esp                      ; 跟进到了这里
7C92E512  |.  0F34              sysenter                              ; 这行F8后自动跳转
7C92E514 >\$  C3                retn
7C92E515   .  8DA424 00000000   lea     esp, dword ptr ss:[esp]
7C92E51C   .  8D6424 00         lea     esp, dword ptr ss:[esp]

0101BAB3    B8 97A801F1         mov     eax, F101A897                 ; 跳到了这里,继续F8
0101BAB8    64:8F05 00000000    pop     dword ptr fs:[0]
0101BABF    83C4 04             add     esp, 4
0101BAC2    55                  push    ebp
0101BAC3    53                  push    ebx
0101BAC4    51                  push    ecx
0101BAC5    57                  push    edi
0101BAC6    56                  push    esi
0101BAC7    52                  push    edx
0101BAC8    8D98 D5110010       lea     ebx, dword ptr ds:[eax+100011>
0101BACE    8B53 18             mov     edx, dword ptr ds:[ebx+18]
0101BAD1    52                  push    edx
0101BAD2    8BE8                mov     ebp, eax
0101BAD4    6A 40               push    40
0101BAD6    68 00100000         push    1000
0101BADB    FF73 04             push    dword ptr ds:[ebx+4]
0101BADE    6A 00               push    0
0101BAE0    8B4B 10             mov     ecx, dword ptr ds:[ebx+10]
0101BAE3    03CA                add     ecx, edx
0101BAE5    8B01                mov     eax, dword ptr ds:[ecx]
0101BAE7    FFD0                call    eax                           ; F8过
0101BAE9    5A                  pop     edx
0101BAEA    8BF8                mov     edi, eax
0101BAEC    50                  push    eax
0101BAED    52                  push    edx
0101BAEE    8B33                mov     esi, dword ptr ds:[ebx]
0101BAF0    8B43 20             mov     eax, dword ptr ds:[ebx+20]
0101BAF3    03C2                add     eax, edx
0101BAF5    8B08                mov     ecx, dword ptr ds:[eax]
0101BAF7    894B 20             mov     dword ptr ds:[ebx+20], ecx
0101BAFA    8B43 1C             mov     eax, dword ptr ds:[ebx+1C]
0101BAFD    03C2                add     eax, edx
0101BAFF    8B08                mov     ecx, dword ptr ds:[eax]
0101BB01    894B 1C             mov     dword ptr ds:[ebx+1C], ecx
0101BB04    03F2                add     esi, edx
0101BB06    8B4B 0C             mov     ecx, dword ptr ds:[ebx+C]
0101BB09    03CA                add     ecx, edx
0101BB0B    8D43 1C             lea     eax, dword ptr ds:[ebx+1C]
0101BB0E    50                  push    eax
0101BB0F    57                  push    edi
0101BB10    56                  push    esi
0101BB11    FFD1                call    ecx                           ; F8过
0101BB13    5A                  pop     edx
0101BB14    58                  pop     eax
0101BB15    0343 08             add     eax, dword ptr ds:[ebx+8]
0101BB18    8BF8                mov     edi, eax
0101BB1A    52                  push    edx
0101BB1B    8BF0                mov     esi, eax
0101BB1D    8B46 FC             mov     eax, dword ptr ds:[esi-4]
0101BB20    83C0 04             add     eax, 4
0101BB23    2BF0                sub     esi, eax
0101BB25    8956 08             mov     dword ptr ds:[esi+8], edx
0101BB28    8B4B 10             mov     ecx, dword ptr ds:[ebx+10]
0101BB2B    894E 24             mov     dword ptr ds:[esi+24], ecx
0101BB2E    8B4B 14             mov     ecx, dword ptr ds:[ebx+14]
0101BB31    51                  push    ecx
0101BB32    894E 28             mov     dword ptr ds:[esi+28], ecx
0101BB35    8B4B 0C             mov     ecx, dword ptr ds:[ebx+C]
0101BB38    894E 14             mov     dword ptr ds:[esi+14], ecx
0101BB3B    FFD7                call    edi                           ; F8过,寄存器窗口有较大的变化
0101BB3D    8985 C8120010       mov     dword ptr ss:[ebp+100012C8], >
0101BB43    8BF0                mov     esi, eax
0101BB45    59                  pop     ecx
0101BB46    5A                  pop     edx
0101BB47    EB 0C               jmp     short PECompac.0101BB55
0101BB49    03CA                add     ecx, edx
0101BB4B    68 00800000         push    8000                          ; 这里就是老师说的特征码!OEP就在附近!
0101BB50    6A 00               push    0
0101BB52    57                  push    edi
0101BB53    FF11                call    dword ptr ds:[ecx]
0101BB55    8BC6                mov     eax, esi
0101BB57    5A                  pop     edx
0101BB58    5E                  pop     esi
0101BB59    5F                  pop     edi
0101BB5A    59                  pop     ecx
0101BB5B    5B                  pop     ebx
0101BB5C    5D                  pop     ebp
0101BB5D  - FFE0                jmp     eax                           ; 跳往OEP!
0101BB5F    9D                  popfd
0101BB60    73 00               jnb     short PECompac.0101BB62
0101BB62    0100                add     dword ptr ds:[eax], eax
0101BB64    0000                add     byte ptr ds:[eax], al
0101BB66    0000                add     byte ptr ds:[eax], al

0100739D    6A 70               push    70                            ; 这里就是OEP!
0100739F    68 98180001         push    PECompac.01001898
010073A4    E8 BF010000         call    PECompac.01007568
010073A9    33DB                xor     ebx, ebx
010073AB    53                  push    ebx
010073AC    8B3D CC100001       mov     edi, dword ptr ds:[10010CC]   ; kernel32.GetModuleHandleA
010073B2    FFD7                call    edi

  三、脱壳
  分别用OD自带的脱壳功能(右键-Dump Degugged Process)及LordPE脱壳。其中OD自带的脱壳功能分别用方法1和方法2进行脱壳,保存文件名分别为1.exe和2.exe;运行LordPE,右键PECompact 2.55.EXE进程点“修正镜像大小”,右键PECompact 2.55.EXE进程点“完整转存”,保存为dump.exe。

  四、修复输入表
  运行脱壳文件,用OD自带的脱壳功能方法1脱壳的文件1.exe能正常运行,方法2脱的文件2.exe运行无反应;LordPE脱壳的文件dump.exe运行报初始化失败,因此需要对输入表修复。
  运行ImportREC_fix,选取PECompact 2.55.EXE进程,OEP改为739D,点“自动查找IAT”,再点“获取输入表”,点“显示无效的”,发现全是有效。(顺便带一句,如果此时有个别无效指针的话,可剪切掉;若有大量无效指针,则需要手工查找本软件调用的API函数,找出IAT的起始地址和计算出大小,手工填入IAT的RVA和大小。这里就不讲了,三人行的教程里有)。分别抓取1.exe、2.exe、dump.exe,保存新文件1_.exe、2_.exe、dump_.exe,都能正常运行,修复成功!用PEiD查出编程语言是Microsoft Visual C++ 7.0 Method2。

  小结:
  1、新手都应从基础练起,不要怕难,既然别人已经跟踪出了经验,就说明通过单步还是能跟出来的,那自己就要试试看。本例看似很复杂,但跟起来很快就有了结果,所以要有信心。
  2、当跟到无法继续时,就要按老师说的,看看附近有没有未实现的跳转,跟过去。还不行时,就要跟进call去看看,尽管如本例这些call看似调用的是系统领空,正如老师所说,每个壳都有自己的套路,我们不要中了SEH暗桩的陷阱。
  
  判断是否到了OEP的小技巧:
  这是我目前学习脱壳的一点心得,是不是正确还不知道,如有错误请高手指正,非常感谢!
  对于老师所说的“大跨段跳转”,在实际操作上有些困难,到底哪些算是“大跨段”,老师也说了有些不一定是很大,自己对编程语言OEP的特征码不熟悉,就常常没信心是不是到了OEP。怎么办呢?我通过观察得出了一个规律,因为刚学没多久,老师的初级教程我都还没看完,是不是老师已经讲过这个规律,我不清楚;如果大家在网上看到相同的说法,请相信我不是抄袭,只是巧合罢了。
  这个小技巧就是:OD载入程度后,点“M”图标,即内存映像。在PEheader下面的那一段(有的是.text,有的是.code,总之是紧接PEheader下面的那个代码段),看一下起始地址,加上大小就是结束地址,记下这个代码段的地址范围。加壳程序入口点一般不在这个范围,所以当OD跟踪到了这个地址范围,就可判断是OEP了,可直接dump了。但偷代码的壳就不能直接dump这么简单了(目前我还没学到脱这类壳的技术)。
  上面这个技巧一直都行得通,直到今天脱上面这个PECompact 2.55壳(我目前接触的壳还很少,有待进一步学习),OD一载入就是01001000,正在那个范围之内,一下子信心动摇了,好在才运行了几行代码就跑到别的段了,再返回来时,正是OEP!所以到目前为止,这个规律还是行得通的,呵呵。
上传的附件 PECompact 2.55.rar [解压密码:pediy]