By:来自轻院的狼【+Immlep+】
Site:http://ptteam.com
Blog:http://immlep.blogone.net

US_unpackMe_5是Unpacking Saga(简称 US)出的来验证成员的五个 UnpackMe中的一个,之前发过一篇unpackme_5的,今天趁着五一放假,整理了前面两个(unpackMe_1和unpackMe_2),这里讨论的是US_unpackMe_2,应该是用hying的壳加壳的,版本不知(知道的放一下话),应该是比较底版本的壳,因为脱壳难度不高,不知道是不是说明所说的放水的一个:)

这次不说那么多了,来个快脱:
载入unpackme_2,撤销所有的断点,忽略除除零异常外的异常,F9让OD飞起来,啪的一声,除零异常断下:

00383531    F7F3                  DIV EBX                       //断在这里
00383533    90                    NOP                           //F2这这里下断点

断下后,在00383533下软断,下断后SHIFT+F9忽略异常,在00383533断下,然后向下走,或向下翻,看到:
0038383F    55                    PUSH EBP                                               ; 偷掉的字节
00383840    8BEC                  MOV EBPESP                         ; 偷掉的字节
00383842    EB 19                 JMP SHORT 0038385D
00383844    83FB 02               CMP EBX, 2
00383847    75 0F                 JNZ SHORT 00383858
00383849    8BC5                  MOV EAXEBP
0038384B    5D                    POP EBP                                                ; 0012FFE0
0038384C    5B                    POP EBX                                                ; 0012FFE0
0038384D    59                    POP ECX                                                ; 0012FFE0
0038384E    5A                    POP EDX                                                ; 0012FFE0
0038384F    5E                    POP ESI                                                ; 0012FFE0
00383850    FFB0 A7060000         PUSH DWORD PTR [EAX+6A7]
00383856    EB 05                 JMP SHORT 0038385D
00383858    5D                    POP EBP                                                ; 0012FFE0
00383859    5B                    POP EBX                                                ; 0012FFE0
0038385A    59                    POP ECX                                                ; 0012FFE0
0038385B    5A                    POP EDX                                                ; 0012FFE0
0038385C    5E                    POP ESI                                                ; 0012FFE0
0038385D  - FFE0                  JMP NEAR EAX                                           ; 这里返回到程序OEP=00401950

程序OEP开头
00401950    FFD7                  CALL NEAR EDI                                          ; unpackme.00401952
00401952    58                    POP EAX                                                ; 0012FFF0

下面重点恢复被破坏的壳,进入程序后遇到第一个CALL
0040197D    90                    NOP
0040197E    E8 DC1EF8FF           CALL 0038385F   ;进去看看怎么解密的


0038385F    50                    PUSH EAX
00383860    60                    PUSHAD
00383861    E8 06000000           CALL 0038386C       //这里进去,会经过些异常
00383866    8B6424 08             MOV ESPDWORD PTR [ESP+8]                             ; unpackme.00401952
0038386A    EB 20                 JMP SHORT 0038388C //不用管00383861,运行到00383861时我们直接在这里下断,F9断下


接着就看到了解密的关键代码了:
ESI指向一个表,分布是这样的
调用CALL(JMP)下一条指令的地址:加密过的函数地址,如下
00383EF3  08 17 40 80| C7 16 34 E0 |
函数会解密原程序的CALLJMP
CALL FuntionAddr(如CALL NEAR DWORD PTR [<&msvcrt.#154>])

jmp FuntionAddr(如JMP NEAR DWORD PTR [<&msvcrt.#315>])
解密函数判断解密的是CALL还是JMP是根据ESI表中的高位的,如果是80则解密的是JMP指令,如果是00则解密的是CALL指令,像上面的我们就知道401708前面的00383EF3里的就是条CALL指令来的:
0038389D    5D                    POP EBP                                                ; 00383899
0038389E    8B6D 00               MOV EBPDWORD PTR [EBP]
003838A1    8B7C24 24             MOV EDIDWORD PTR [ESP+24]
003838A5    8BB5 AF060000         MOV ESIDWORD PTR [EBP+6AF]
003838AB    03F5                  ADD ESIEBP
003838AD    8B06                  MOV EAXDWORD PTR [ESI]                                //ESI对应一个表,取地址
003838AF    33D2                  XOR EDXEDX                                           ; ntdll.77FB1742
003838B1    B9 02000000           MOV ECX, 2
003838B6    F7E1                  MUL ECX
003838B8    D1E8                  SHR EAX, 1                                               
003838BA    0385 83060000         ADD EAXDWORD PTR [EBP+683]
003838C0    2B85 8F060000         SUB EAXDWORD PTR [EBP+68F]
003838C6    3BF8                  CMP EDIEAX
003838C8    75 0A                 JNZ SHORT 003838D4                                     
003838CA    0AD2                  OR DLDL                                              //如果刚才去到的地址高位是80的话,DL=1
003838CC    75 04                 JNZ SHORT 003838D2                                     //如果是jmp的话跳到003838D2执行
003838CE    EB 09                 JMP SHORT 003838D9
003838D0    EB 02                 JMP SHORT 003838D4
003838D2    EB 2F                 JMP SHORT 00383903
003838D4    83C6 08               ADD ESI, 8
003838D7  ^ EB D4                 JMP SHORT 003838AD
003838D9    8B46 04               MOV EAXDWORD PTR [ESI+4]
003838DC    03BD 8F060000         ADD EDIDWORD PTR [EBP+68F]
003838E2    2BBD 83060000         SUB EDIDWORD PTR [EBP+683]
003838E8    2BC7                  SUB EAXEDI
003838EA    F7D0                  NOT EAX
003838EC    C1C0 10               ROL EAX, 10
003838EF    0385 83060000         ADD EAXDWORD PTR [EBP+683]
003838F5    2B85 8F060000         SUB EAXDWORD PTR [EBP+68F]
003838FB    8B00                  MOV EAXDWORD PTR [EAX]
003838FD    894424 20             MOV DWORD PTR [ESP+20], EAX
00383901    61                    POPAD
00383902    C3                    RETN
00383903    8B46 04               MOV EAXDWORD PTR [ESI+4]                             ; 查表,地址解密
00383906    03BD 8F060000         ADD EDIDWORD PTR [EBP+68F]
0038390C    2BBD 83060000         SUB EDIDWORD PTR [EBP+683]
00383912    2BC7                  SUB EAXEDI
00383914    F7D0                  NOT EAX
00383916    C1C0 10               ROL EAX, 10                                            ;EAX放的才是函数的值
00383919    0385 83060000         ADD EAXDWORD PTR [EBP+683]
0038391F    2B85 8F060000         SUB EAXDWORD PTR [EBP+68F]
00383925    8B00                  MOV EAXDWORD PTR [EAX]
00383927    894424 24             MOV DWORD PTR [ESP+24], EAX
0038392B    61                    POPAD
0038392C    83C4 04               ADD ESP, 4                                              //jmp的话就没有返回地址的。。
0038392F    C3                    RETN


按照上面找个地方写修复代码,找到0040276C:
0040276C      60                  PUSHAD
0040276D      BE F33E3800         MOV ESI, 383EF3                     //383EF3表开始地址
00402772      8B06                MOV EAXDWORD PTR [ESI]            //取表中的地址
00402774      833E 00             CMP DWORD PTR [ESI], 0
00402777      74 51               JE SHORT unpackme.004027CA          //表是否结束,表以00 00 00 00为结束标志
00402779      90                  NOP
0040277A      90                  NOP
0040277B      90                  NOP
0040277C      90                  NOP
0040277D      33D2                XOR EDXEDX
0040277F      B9 02000000         MOV ECX, 2
00402784      F7E1                MUL ECX
00402786      D1E8                SHR EAX, 1
00402788      08D2                OR DLDL
0040278A      75 22               JNZ SHORT unpackme.004027AE            //是jmp
0040278C      90                  NOP
0040278D      90                  NOP
0040278E      90                  NOP
0040278F      90                  NOP 
00402790      8B7E 04             MOV EDIDWORD PTR [ESI+4]             //取加密过的函数地址
00402793      2BF8                SUB EDIEAX                            ;  unpackme.00401950
00402795      F7D7                NOT EDI                                 ;  unpackme.00401952
00402797      C1C7 10             ROL EDI, 10
0040279A      83E8 06             SUB EAX, 6
0040279D      C700 FF150000       MOV DWORD PTR [EAX], 15FF               //写入CALL NEAR DWORD PTR
004027A3      8978 02             MOV DWORD PTR [EAX+2], EDI             //写入地址
004027A6      83C6 08             ADD ESI, 8
004027A9    ^ EB C7               JMP SHORT unpackme.00402772
004027AB      90                  NOP
004027AC      90                  NOP
004027AD      90                  NOP
004027AE      8B7E 04             MOV EDIDWORD PTR [ESI+4]               //是jmp就跳到这里来
004027B1      2BF8                SUB EDIEAX                            ;  unpackme.00401950
004027B3      F7D7                NOT EDI                                 ;  unpackme.00401952
004027B5      C1C7 10             ROL EDI, 10
004027B8      83E8 06             SUB EAX, 6
004027BB      C700 FF250000       MOV DWORD PTR [EAX], 25FF               //写入JMP NEAR DWORD PTR 
004027C1      8978 02             MOV DWORD PTR [EAX+2], EDI              //写入地址
004027C4      83C6 08             ADD ESI, 8
004027C7    ^ EB A9               JMP SHORT unpackme.00402772
004027C9      61                  POPAD
004027CA      90                  NOP

60 BE F3 3E 38 00 8B 06 83 3E 00 74 51 90 90 90 90 33 D2 B9 02 00 00 00 F7 E1 D1 E8 08 D2 75 22
90 90 90 90 8B 7E 04 2B F8 F7 D7 C1 C7 10 83 E8 06 C7 00 FF 15 00 00 89 78 02 83 C6 08 EB C7 90
90 90 8B 7E 04 2B F8 F7 D7 C1 C7 10 83 E8 06 C7 00 FF 25 00 00 89 78 02 83 C6 08 EB A9 61 90 00

重新载入程序,跟到0038383F时(执行被偷的字节的地址),找到0040276C写入上面的代码,转到0040276C执行还原代码后,跳到刚才取得的原函数的OEP

00401950    FFD7                  CALL NEAR EDI                                          ; unpackme.00401952
00401952    58                    POP EAX                                                ; 0012FFF0
恢复为:
00401950 >/$  55                  PUSH EBP
00401951  |.  8BEC                MOV EBPESP
在把运行OEP转到00401950,dump it,用imprREC:
填入
OEP=00001950
RAV=2000,大小=2000   (RAV可以随便找程序里的CALL看看就知道了)
getimport,level3 trace,无效的cut,fixdump,ok



Special thx:
eaton,ama,catking668,www.pediy.com,www.crackslatinos.hispadominio.net,luocong's scc and you!

Ps:但要记住,虽然我没提到你,我还是记得你的,感谢着你的。。。