• 标 题:对Crunch v1.1主程序文件的脱壳方法 ---ljtt
  • 作 者:ljtt
  • 时 间:2000-11-30 17:32:15
  • 链 接:http://bbs.pediy.com

对Crunch v1.1主程序文件的脱壳方法

【声明】
我写文章以交流为主,希望大家在转载时能保持文章的完整性。

【前言】
Crunch v1.1的主程序文件的注册方法采用了和Armadilo的方法类似,由于其自身有多处反跟踪的代码,所以如果不处理。。。。。

样例文件:    Crunch.EXE    (Crunch v1.1的主程序文件)
加壳方式:    Crunch v1.1
目标:        手动脱壳
作者:        ljttt
写作日期:    2001-xx-xx (有感于某制假企业)

1、启动ICEDUMP,并启动ProcDump 1.6.2,选择Option/Rebuild new import table,单击Bhrama Server。这样我们将来手动脱壳时可以借助ProcDump的自动脱壳功能。这样很方便、快洁。

2、Ctrl-D进入SoftICE,设断点
bpint 3

3、用PEditor 1.5打开Crunch.EXE,单击break'n'enter。这时将在第一条指令处中断进入SoftICE。可以看到如下提示:
015F:0066C000  CC                  INT      3
015F:0066C001  E800000000          CALL      0066C006
015F:0066C006  5D                  POP      EBP
在命令窗口提示如下:
You have to enter "eb eip 55" before you continue !

现在我按照提示输入
eb eip 55
这样修改了入口处的 CC (int 3)。现在显示如下,可以继续跟踪了。
015F:0066C000  55                  PUSH      EBP
015F:0066C001  E800000000          CALL      0066C006
015F:0066C006  5D                  POP      EBP

4、继续到如下代码处:(特征是第一个 REPZ MOVSB 指令)
015F:0066C0D9  BFE4000000          MOV      EDI,000000E4
015F:0066C0DE  03FD                ADD      EDI,EBP
015F:0066C0E0  8BC8                MOV      ECX,EAX
015F:0066C0E2  F3A4                REPZ MOVSB                <--在该指令执行完后,以下将得到SMC方法还原后的正确代码
015F:0066C0E4  8B07                MOV      EAX,[EDI]        <--现在还是加密的代码
015F:0066C0E6  D581                AAD
015F:0066C0E8  C2A614              RET      14A6

5、在 REPZ MOVSB 执行后,我们可以看到如下的代码:
015F:0066C0D9  BFE4000000          MOV      EDI,000000E4
015F:0066C0DE  03FD                ADD      EDI,EBP
015F:0066C0E0  8BC8                MOV      ECX,EAX
015F:0066C0E2  F3A4                REPZ MOVSB
015F:0066C0E4  8BD5                MOV      EDX,EBP        <--这是还原后的正确代码了,可以继续跟踪了
015F:0066C0E6  81C2A6140000        ADD      EDX,000014A6
015F:0066C0EC  52                  PUSH      EDX

6、继续跟踪到如下代码处:(特征是 CALL EDX 后紧跟着两个 INT 3 指令)
015F:0066C11C  5A                  POP      EDX
015F:0066C11D  90                  NOP
015F:0066C11E  FFD2                CALL      EDX            <--在此处我们要停下,其中有反跟踪的代码,我们要跳过这段代码
015F:0066C120  CC                  INT      3
015F:0066C121  CC                  INT      3
015F:0066C122  E85E140000          CALL      0066D585

7、在 CALL EDX 处我们要停下,下指令跳过反跟踪代码(关于这段反跟踪代码的分析我已在《对Crunch v1.1加壳程序的手动脱壳的一点分析》一文中说明)
r eip eip+E
r esi 10

8、好了,现在我们又可以继续跟踪了,到如下代码处:(特征是 JG 0066C19F 指令)
015F:0066C1A6  83C701              ADD      EDI,01
015F:0066C1A9  4B                  DEC      EBX
015F:0066C1AA  83FB00              CMP      EBX,00
015F:0066C1AD  7FF0                JG        0066C19F        <--现在程序又要用到SMC的方法来还原代码了。
015F:0066C1AF  90                  NOP                        <--现在这里还是加密的代码
015F:0066C1B0  EBCD                JMP      0066C17F
015F:0066C1B2  90                  NOP

9、我们来看看SMC方法还原的正确代码:
015F:0066C1A6  83C701              ADD      EDI,01
015F:0066C1A9  4B                  DEC      EBX
015F:0066C1AA  83FB00              CMP      EBX,00
015F:0066C1AD  7FF0                JG        0066C19F        <--该指令后的代码现在是还原后的正确代码了,可以比较以上的代码看看
015F:0066C1AF  B942000000          MOV      ECX,00000042
015F:0066C1B4  59                  POP      ECX

10、继续跟踪到如下代码处:(特征是 SUB ECX,00000042 指令)
015F:0066C216  83F900              CMP      ECX,00
015F:0066C219  75EB                JNZ      0066C206
015F:0066C21B  59                  POP      ECX
015F:0066C21C  81E942000000        SUB      ECX,00000042
015F:0066C222  51                  PUSH      ECX
015F:0066C223  E8C3110000          CALL      0066D3EB        <--内有反跟踪的代码,所以在此处我们要按F8键进入
015F:0066C228  33C0                XOR      EAX,EAX

11、在 CALL 0066D3EB 处我们按进入,可以看到如下代码:(这里的反跟踪代码说明见我写的《对Crunch v1.1加壳程序的手动脱壳的一点分析》一文)
015F:0066D3EB  8BDD                MOV      EBX,EBP
015F:0066D3ED  8B85483C0000        MOV      EAX,[EBP+00003C48]
015F:0066D3F3  8B8D86330000        MOV      ECX,[EBP+00003386]
015F:0066D3F9  C1E908              SHR      ECX,08
015F:0066D3FC  33D2                XOR      EDX,EDX
015F:0066D3FE  B902000000          MOV      ECX,00000002
015F:0066D403  F7F1                DIV      ECX
015F:0066D405  0BD2                OR        EDX,EDX
015F:0066D407  7502                JNZ      0066D40B        <--在此处我们要停下!
015F:0066D409  EB72                JMP      0066D47D
015F:0066D40B  8BDD                MOV      EBX,EBP

12、在 JNZ 006D40B 处停下,我们不能让其跳转,所以我们可下指令
方法一:修改跳转方向
r fl z
方法二:NOP掉跳转指令
eb eip 90
eb eip+1 90

13、按F12返回到主程序代码段中,继续跟踪如下代码处:(特征是 CALL EBX 后紧跟一条 NOP 指令)
015F:0066C273  BB76060000          MOV      EBX,00000676
015F:0066C278  03DD                ADD      EBX,EBP
015F:0066C27A  899D643C0000        MOV      [EBP+00003C64],EBX
015F:0066C280  BB050A0000          MOV      EBX,00000A05
015F:0066C285  03DD                ADD      EBX,EBP
015F:0066C287  FFD3                CALL      EBX            <--内有反跟踪代码,在此处我们要停下,想办法跳过它
015F:0066C289  90                  NOP
015F:0066C28A  60                  PUSHAD
015F:0066C28B  BB85230000          MOV      EBX,00002385

14、在 CALL EBX 处停下,下指令跳过反跟踪(其中的反跟踪代码说明见我写的《Crunch v1.1中的一段有趣的检测跟踪代码》一文)
r eip eip+2

15、好了,到此主程序中的反跟踪代码大部分被我们跳过了,有没有一种登山的感觉,但是现在还只是过了一小段路程,我们继续!

如果你有过对Crunch加壳的程序的脱壳经验,一定会发现大部分类似,现在我们来看看Crunch.EXE主程序和他们的不同。这也是我们以下要进行的步骤的一个原理说明吧:
首先,Crunch.EXE自身用Crunch v1.1的方法加了壳,(其中我们在跟踪时已经知道了有大量的反跟踪代码,如果不小心掉了进去,呵呵!接受一次被超度的感觉吧!)。
然后,Crunch.EXE建立一个临时文件,其中的代码是由主程序在内存中还原得到的(此文件也用Crunch v1.1加了壳)。然后通过此文件建立一个子进程。进行注册分析。
此时,主程序Crunch.EXE进入一个的循环中,等待子进程(临时文件创建)的注册过程结束,当子进程退出后,主程序Crunch.EXE退出循环。并删除此临时文件。最后,主程序进入主界面。
因此,我们要在主程序进入主界面之前,DUMP得到我们想要的脱壳文件。由于子进程中也有反跟踪代码,所以我们必须也要跳过其中的反跟踪代码,否则前功尽弃。开始我想过很多办法,比如在临时文件刚刚保存还未创建进程的时候得到完整的加壳文件来进行单独的脱壳,然后在下次跟踪时用我脱壳后没有反跟踪代码的文件替换掉临时文件,但是发现单独运行临时文件竟然无法工作,(看来作者早有防范)可见主程序Crunch.EXE需要和子进程有信息通讯,必须要同时工作,我们也只有在主程序中运行的情况下对子进程进行分析跳过其中的反跟踪代码。不过这把我一下难住了。由于WINDOWS的多任务特点,我们无法在单步跟踪时知道何时子进程开始执行第一条指令。我跟踪的情况并非在CreatProcess函数执行后,也不在ResumeThread函数执行后。不过还是让我想出了办法。Yeah!

16、继续跟踪来到如下代码处:
015F:0066C473  50                  PUSH      EAX
015F:0066C474  FFB50D240000        PUSH      DWORD PTR [EBP+0000240D]    <--数据缓冲区地址,我跟踪时为 920000
015F:0066C47A  FFB505240000        PUSH      DWORD PTR [EBP+00002405]
015F:0066C480  FF951E210000        CALL      [EBP+0000211E]                <--即 CALL WriteFile
015F:0066C486  FFB505240000        PUSH      DWORD PTR [EBP+00002405]
015F:0066C48C  FF9522210000        CALL      [EBP+00002122]
015F:0066C492  6800800000          PUSH      00008000
015F:0066C497  6A00                PUSH      00
015F:0066C499  FFB50D240000        PUSH      DWORD PTR [EBP+0000240D]
015F:0066C49F  FF9512210000        CALL      [EBP+00002112]

17、在 CALL [EBP+0000211E] 处停下,我们要做些准备工作。我跟踪时 [EBP+0000240D] = 920000 ,这就是即将被保存到临时文件中的数据。
我们要修改其中第一条指令为 CC 。临时文件的 Entry Point = 31C00,(这个值可以通过显示 920000 的内容,分析 PE 结构知道,也可以在无调试环境下用ProcDump来DUMP出临时文件得到。方法很多,可以自己去分析。)所以第一条指令位于 920000+31C00 处。
下指令
eb 920000+31C00 CC

18、下指令
I3HERE ON

19、继续跟踪到如下代码处:(特征是 JMP EBX 后紧跟一条指令 MOV EAX,[EBP+00003536])
015F:0066C52D  83C304              ADD      EBX,04
015F:0066C530  FF33                PUSH      DWORD PTR [EBX]
015F:0066C532  FFD0                CALL      EAX
015F:0066C534  BBCC0C0000          MOV      EBX,00000CCC
015F:0066C539  03DD                ADD      EBX,EBP
015F:0066C53B  FFE3                JMP      EBX                <--在此处停下
015F:0066C53D  8B8536350000        MOV      EAX,[EBP+00003536]    <--在此处设下断点
015F:0066C543  83C014              ADD      EAX,14
015F:0066C546  B914000000          MOV      ECX,00000014
015F:0066C54B  33D2                XOR      EDX,EDX
015F:0066C54D  8034101A            XOR      BYTE PTR [EDX+EAX],1A
015F:0066C551  42                  INC      EDX
015F:0066C552  49                  DEC      ECX
015F:0066C553  83F900              CMP      ECX,00

20、在 JMP EBX 处时我们暂时停下,在 MOV EAX,[EBP+00003536] 处设下断点
bpx 0066C53D
此处断点将在子进程结束后中断。现在子进程还并未真正运行。在 JMP EBX 后将进入了一个循环。我们不需要浪费时间,按F5键继续。

21、程序将中断在子进程第一条指令处:
015F:0047FFFF  FFCC                DEC      ESP
015F:00480001  E800000000          CALL      00480006
015F:00480006  5D                  POP      EBP
015F:00480007  83ED06              SUB      EBP,06
015F:0048000A  8BC5                MOV      EAX,EBP

22、还原原来的代码,下指令
r eip eip-1
e eip 55        <--由于原来的第一条指令代码为 55

23、现在我们的跟踪步骤和前面对主程序Crunch.EXE类似了。重复第 4 - 14 步中的方法来反跟踪。这里就不多说了,只是把一些特征代码列出。方法比较。
㈠请对比步骤4:
特征一: REPZ MOVSB
015F:004800E2  F3A4                REPZ MOVSB            <--特征
015F:004800E4  8B07                MOV      EAX,[EDI]    <--未还原前的加密代码
015F:004800E6  D581                AAD
015F:004800E8  C29D14              RET      149D
015F:004800EB  0E                  PUSH      CS
以下是还原后的代码
015F:004800E2  F3A4                REPZ MOVSB            <--特征
015F:004800E4  8BD5                MOV      EDX,EBP    <--还原后的正确代码
015F:004800E6  81C29D140000        ADD      EDX,0000149D
015F:004800EC  52                  PUSH      EDX
015F:004800ED  33C0                XOR      EAX,EAX

㈡请对比步骤6:
特征二: CALL EDX 后紧跟 INT 3
015F:0048011D  90                  NOP
015F:0048011E  FFD2                CALL      EDX        <--特征,要跳过这里的反跟踪
015F:00480120  CC                  INT      3
015F:00480121  CC                  INT      3
015F:00480122  E855140000          CALL      0048157C

㈢请对比步骤8:
特征三: JG 0048019F
015F:004801AA  83FB00              CMP      EBX,00
015F:004801AD  7FF0                JG        0048019F    <--特征
015F:004801AF  90                  NOP                    <--未还原前的加密代码
015F:004801B0  EBCD                JMP      0048017F
015F:004801B2  90                  NOP
以下是还原后的代码
015F:004801AA  83FB00              CMP      EBX,00
015F:004801AD  7FF0                JG        0048019F    <--特征
015F:004801AF  B942000000          MOV      ECX,00000042    <--还原后的正确代码
015F:004801B4  59                  POP      ECX
015F:004801B5  57                  PUSH      EDI

㈣请对比步骤10:
特征四: SUB ECX,00000042
015F:0048021B  59                  POP      ECX
015F:0048021C  81E942000000        SUB      ECX,00000042
015F:00480222  51                  PUSH      ECX
015F:00480223  E8BA110000          CALL      004813E2    <--要跳过这里的反跟踪
要跳过的地方
015F:004813FA  F7F1                DIV      ECX
015F:004813FC  0BD2                OR        EDX,EDX
015F:004813FE  7502                JNZ      00481402    <--NOP
015F:00481400  EB72                JMP      00481474

㈤请对比步骤13:
特征五: CALL EBX 后紧跟 NOP
015F:00480285  03DD                ADD      EBX,EBP
015F:00480287  FFD3                CALL      EBX        <--要跳过此处的反跟踪
015F:00480289  90                  NOP
015F:0048028A  60                  PUSHAD

24、跳过了以上这些反跟踪的部分后,按F5键让子进程进行注册分析。这时将回到WINDOWS中,单击 CONTINUE 键将进入程序主界面。(如果你想分析注册码,可以试试了)这时将中断在我们在主程序中留下的一个断点 CALL 0066C53D。显示如下:
015F:0066C534  BBCC0C0000          MOV      EBX,00000CCC
015F:0066C539  03DD                ADD      EBX,EBP
015F:0066C53B  FFE3                JMP      EBX                
015F:0066C53D  8B8536350000        MOV      EAX,[EBP+00003536]    <--在此处中断
015F:0066C543  83C014              ADD      EAX,14
015F:0066C546  B914000000          MOV      ECX,00000014
015F:0066C54B  33D2                XOR      EDX,EDX
015F:0066C54D  8034101A            XOR      BYTE PTR [EDX+EAX],1A

25、我们继续跟踪到如下代码处:(特征是  JMP EAX 后紧跟 JMP [EBP+00003C6C])
015F:0066C9DB  83850124000014      ADD      DWORD PTR [EBP+00002401],14
015F:0066C9E2  FF8D55330000        DEC      DWORD PTR [EBP+00003355]
015F:0066C9E8  6683BD5533000000    CMP      WORD PTR [EBP+00003355],00
015F:0066C9F0  0F85FAFDFFFF        JNZ      0066C7F0
015F:0066C9F6  B83C160000          MOV      EAX,0000163C
015F:0066C9FB  03C5                ADD      EAX,EBP
015F:0066C9FD  FFE0                JMP      EAX                <--此处有大量的代码
015F:0066C9FF  FFA56C3C0000        JMP      [EBP+00003C6C]        <--这里是关键!
015F:0066CA05  8CD8                MOV      AX,DS
015F:0066CA07  A804                TEST      AL,04

26、我们可以在 JMP EAX 处停下,直接在 JMP [EBP+00003C6C] 处设下断点,或者把光标移动到此处按F7键,快速到此。(如果你想了解各个细节可以继续慢慢跟踪。)然后继续跟踪到如下代码处:
特征是 MOV EAX,[EBP+00002415] 加 ADD [EBP+00003382],EAX 后跟一条 JMP [EBP+00003C5C] 指令
015F:00670094  BB810A0000          MOV      EBX,00000A81
015F:00670099  03DD                ADD      EBX,EBP
015F:0067009B  FFD3                CALL      EBX
015F:0067009D  64678F060000        POP      DWORD PTR FS:[0000]
015F:006700A3  83C408              ADD      ESP,08
015F:006700A6  8B8515240000        MOV      EAX,[EBP+00002415]
015F:006700AC  018582330000        ADD      [EBP+00003382],EAX
015F:006700B2  FFA55C3C0000        JMP      [EBP+00003C5C]        <--在这里将跳转到最后一段代码处
015F:006700B8  C3                  RET                     

27、在 JMP [EBP+00003C5C] 处按F10键将来到如下代码处:
015F:0066C0E4  61                  POPAD
015F:0066C0E5  5D                  POP      EBP
015F:0066C0E6  8B8582330000        MOV      EAX,[EBP+00003382]
015F:0066C0EC  5D                  POP      EBP
015F:0066C0ED  FFE0                JMP      EAX                <--EAX=OEP,这里将跳转到程序真正的入口处了!

28、在 JMP EAX 处我们要停下来,这里将到了我们来DUMP文件的时候到了。(这里我使用的是ICEDUMP 6.0168的命令使用方法)
/bhrama ProcDump32 - Dumper Server
这时程序将回到WINDOWS,过一段时间,如果成功,将出现文件保存对话框让你选择想保存的文件名。存完将回到SoftICE,好!我们按F5结束工作。

【后记】
用这种方法脱壳很累,写这篇文章也很累。不过再累也得把方法留下来,让自己以后能够对该程序的加壳方法温故知新。
Crunch.EXE v1.1
在脱壳后,还需要修改一处代码使之成为注册版。
004043C8: 8D45EC                    lea eax,dword ptr [ebp-14]
004043CB: BA02000000                mov edx,00000002
004043D0: E81BA40D00                call 004DE7F0
004043D5: 59                        pop ecx
004043D6: 84C9                      test cl,cl
004043D8: 7409                      jz 004043E3                    <--修改此处的代码为NOP,即 7409=9090
004043DA: C605F4054E0001            mov byte ptr [004E05F4],01
004043E1: EB07                      jmp 004043EA
004043E3: C605F4054E0000            mov byte ptr [004E05F4],00
004043EA: FF4E1C                    dec dword ptr [esi+1C]
004043ED: 8D45FC                    lea eax,dword ptr [ebp-04]
004043F0: BA02000000                mov edx,00000002
004043F5: E8F6A30D00                call 004DE7F0

【补充】
最新下载了Crunch v1.2 。发现脱壳方法与上类似,就不写了。
不过注意在跟踪