• 标 题:老王旧壳之INT3异常、过期限制和数据附加脱壳分析
  • 作 者:csjwaman
  • 时 间:004-11-17,16:35
  • 链 接:http://bbs.pediy.com

     日期:2004年11月17日   破解人:csjwaman[DFCG]
———————————————————————————————————————————
 
 
【软件名称】:EncryptPE1.0 V1.2003.5.18加壳的某程序
【软件限制】:INT3异常、过期限制、数据附加
【脱壳声明】:感谢fly、loveboom等高手的帮助!
【操作系统】:WIN2K
【脱壳工具】:OD等

【原文链接】:http://bbs.pediy.com/showthread.php?s=&threadid=7101

———————————————————————————————————————————
 
【脱壳过程】:
 
  壳中加了INT3异常,还有过期限制,还有数据附加。
对INT3异常只要象脱EncryptPE V1.2003.5.1 Preview一样把INT3异常NOP掉就行了。过期限制用bp GetLocalTime下断。下面是脱壳和修复过程:


一、脱壳

用OD载入,隐藏OD,忽略所有异常,同时添加忽略0EEDFADF和C0000008异常。载入后停在:


0044D000 >  60              PUSHAD=====>停在这儿。
0044D001    9C              PUSHFD
0044D002    64:FF35 0000000>PUSH DWORD PTR FS:[0]
0044D009    E8 79010000     CALL 脫2.0044D187
0044D00E    0000            ADD BYTE PTR DS:[EAX],AL
0044D010    0000            ADD BYTE PTR DS:[EAX],AL
0044D012    0000            ADD BYTE PTR DS:[EAX],AL
0044D014    0000            ADD BYTE PTR DS:[EAX],AL


F9运行异常在:

77F813A2    FF75 0C         PUSH DWORD PTR SS:[EBP+C]
77F813A5    FF75 08         PUSH DWORD PTR SS:[EBP+8]
77F813A8    E8 ECEC0000     CALL ntdll.77F90099
77F813AD    5D              POP EBP
77F813AE    C2 1800         RETN 18
77F813B1 >  CC              INT3======>NOP掉!
77F813B2    C3              RETN=======>停在此处。
77F813B3    33C9            XOR ECX,ECX
77F813B5    E9 A5BE0000     JMP ntdll.77F8D25F
77F813BA >  55              PUSH EBP
77F813BB    8BEC            MOV EBP,ESP
77F813BD    56              PUSH ESI
77F813BE    8B75 08         MOV ESI,DWORD PTR SS:[EBP+8]
77F813C1    8A06            MOV AL,BYTE PTR DS:[ESI]
77F813C3    3C 02           CMP AL,2

下断bp GetLocalTime后SHIFT+F9运行程序,断在:


77E649B6 >  55              PUSH EBP=====>断在此处。取消断点。看看堆栈区数据。
77E649B7    8BEC            MOV EBP,ESP
77E649B9    83EC 18         SUB ESP,18
77E649BC    56              PUSH ESI
77E649BD    A1 1800FE7F     MOV EAX,DWORD PTR DS:[7FFE0018]
77E649C2    8B0D 1400FE7F   MOV ECX,DWORD PTR DS:[7FFE0014]
77E649C8    3B05 1C00FE7F   CMP EAX,DWORD PTR DS:[7FFE001C]
77E649CE  ^ 75 ED           JNZ SHORT kernel32.77E649BD
77E649D0    8B15 2400FE7F   MOV EDX,DWORD PTR DS:[7FFE0024]
77E649D6    8B35 2000FE7F   MOV ESI,DWORD PTR DS:[7FFE0020]
77E649DC    3B15 2800FE7F   CMP EDX,DWORD PTR DS:[7FFE0028]
77E649E2  ^ 75 EC           JNZ SHORT kernel32.77E649D0
77E649E4    2BCE            SUB ECX,ESI
77E649E6    1BC2            SBB EAX,EDX
77E649E8    894D F8         MOV DWORD PTR SS:[EBP-8],ECX


堆栈区数据:

0123FBD8   7112A429  /CALL 到 GetLocalTime 来自 V1200351.7112A424
0123FBDC   0123FBE8  \pLocaltime = 0123FBE8
0123FBE0   71128B70  ASCII "%d"

到7112A429处:

7112A424    E8 8BC8FFFF     CALL V1200351.71126CB4    ; JMP to kernel32.GetLocalTime
7112A429    66:8B4C24 0E    MOV CX,WORD PTR SS:[ESP+E]=====>下断后F9运行到此。然后取消断点。
7112A42E    66:8B5424 0A    MOV DX,WORD PTR SS:[ESP+A]
7112A433    66:8B4424 08    MOV AX,WORD PTR SS:[ESP+8]
7112A438    E8 1BFEFFFF     CALL V1200351.7112A258
7112A43D    DD5C24 18       FSTP QWORD PTR SS:[ESP+18]
7112A441    9B              WAIT
7112A442    66:8B4424 16    MOV AX,WORD PTR SS:[ESP+16]
7112A447    50              PUSH EAX
7112A448    66:8B4C24 18    MOV CX,WORD PTR SS:[ESP+18]
7112A44D    66:8B5424 16    MOV DX,WORD PTR SS:[ESP+16]
7112A452    66:8B4424 14    MOV AX,WORD PTR SS:[ESP+14]
7112A457    E8 5CFCFFFF     CALL V1200351.7112A0B8
7112A45C    DC4424 18       FADD QWORD PTR SS:[ESP+18]
7112A460    DD1C24          FSTP QWORD PTR SS:[ESP]
7112A463    9B              WAIT
7112A464    DD0424          FLD QWORD PTR SS:[ESP]
7112A467    83C4 20         ADD ESP,20
7112A46A    C3              RETN=======>返回。

返回到:


711A0EF0    83C4 F8         ADD ESP,-8====>返回到这里。
711A0EF3    DD1C24          FSTP QWORD PTR SS:[ESP]
711A0EF6    9B              WAIT
711A0EF7    8D95 90FDFFFF   LEA EDX,DWORD PTR SS:[EBP-270]
711A0EFD    B8 741B1A71     MOV EAX,V1200351.711A1B74     ; ASCII "yyyymmdd"
711A0F02    E8 3DA1F8FF     CALL V1200351.7112B044
711A0F07    8B95 90FDFFFF   MOV EDX,DWORD PTR SS:[EBP-270]
711A0F0D    58              POP EAX
711A0F0E    E8 3D3BF8FF     CALL V1200351.71124A50=====>日期比较CALL。
711A0F13    73 0D           JNB SHORT V1200351.711A0F22=====>必须跳。修改C标志位为0。
711A0F15    8D45 E0         LEA EAX,DWORD PTR SS:[EBP-20]
711A0F18    BA 881B1A71     MOV EDX,V1200351.711A1B88
711A0F1D    E8 CA37F8FF     CALL V1200351.711246EC
711A0F22    B2 01           MOV DL,1
711A0F24    A1 D0961371     MOV EAX,DWORD PTR DS:[711396D0]
711A0F29    E8 9628F8FF     CALL V1200351.711237C4
711A0F2E    8945 D8         MOV DWORD PTR SS:[EBP-28],EAX
711A0F31    837D E8 00      CMP DWORD PTR SS:[EBP-18],0
711A0F35    0F85 32010000   JNZ V1200351.711A106D========>不能跳,修改Z标志位为1。
711A0F3B    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
711A0F3E    8078 34 00      CMP BYTE PTR DS:[EAX+34],0
711A0F42    0F85 18010000   JNZ V1200351.711A1060
711A0F48    8D8D 88FDFFFF   LEA ECX,DWORD PTR SS:[EBP-278]
711A0F4E    BA 08000000     MOV EDX,8
711A0F53    B8 01000000     MOV EAX,1
711A0F58    E8 177CF8FF     CALL V1200351.71128B74


至此,日期限制已取消。直接F9运行,等出现注册框后在内存镜像401000段下内存访问断点,然后点注册框中的“确定”。程序断在:

00408AF7    55              PUSH EBP=====>这就是入口。现在可以DUMP了。
00408AF8    8BEC            MOV EBP,ESP
00408AFA    6A FF           PUSH -1
00408AFC    68 20434100     PUSH 脫2.00414320
00408B01    68 F0C34000     PUSH 脫2.0040C3F0
00408B06    64:A1 00000000  MOV EAX,DWORD PTR FS:[0]
00408B0C    50              PUSH EAX
00408B0D    64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00408B14    83EC 58         SUB ESP,58
00408B17    53              PUSH EBX
00408B18    56              PUSH ESI
00408B19    57              PUSH EDI
00408B1A    8965 E8         MOV DWORD PTR SS:[EBP-18],ESP
00408B1D    FF15 F0414100   CALL NEAR DWORD PTR DS:[4141F0]          ; kernel32.GetVersion
00408B23    33D2            XOR EDX,EDX
00408B25    8AD4            MOV DL,AH
00408B27    8915 7C934100   MOV DWORD PTR DS:[41937C],EDX
00408B2D    8BC8            MOV ECX,EAX


DUMP后删除第二区段,然后用ImportREC直接修复IAT,重建PE后脱壳完成。

二、修复

运行脱壳后的程序提示某处不能访问等等。估计有自校验,用OD载入,下断bp GetFileSize,运行后程序断在:

77E66B4E >  55              PUSH EBP=====>断在这里,看看堆栈区数据。
77E66B4F    8BEC            MOV EBP,ESP
77E66B51    51              PUSH ECX
77E66B52    51              PUSH ECX
77E66B53    8D45 F8         LEA EAX,DWORD PTR SS:[EBP-8]
77E66B56    50              PUSH EAX
77E66B57    FF75 08         PUSH DWORD PTR SS:[EBP+8]
77E66B5A    E8 B7FFFFFF     CALL KERNEL32.GetFileSizeEx
77E66B5F    85C0            TEST EAX,EAX
77E66B61    0F84 1F6E0200   JE KERNEL32.77E8D986
77E66B67    8B45 0C         MOV EAX,DWORD PTR SS:[EBP+C]
77E66B6A    85C0            TEST EAX,EAX
77E66B6C    0F85 612D0000   JNZ KERNEL32.77E698D3
77E66B72    837D F8 FF      CMP DWORD PTR SS:[EBP-8],-1
77E66B76    0F84 FE6D0200   JE KERNEL32.77E8D97A
77E66B7C    8B45 F8         MOV EAX,DWORD PTR SS:[EBP-8]
77E66B7F    C9              LEAVE
77E66B80    C2 0800         RETN 8

堆栈区数据:

0012FEFC   0040189A  /CALL 到 GetFileSize 来自 dumped_.00401894
0012FF00   00000058  |hFile = 00000058 (window)
0012FF04   00000000  \pFileSizeHigh = NULL

到40189A处看看:

00401894    FF15 2C414100   CALL NEAR DWORD PTR DS:[<&kernel32.GetFi>; KERNEL32.GetFileSize
0040189A    56              PUSH ESI=====>来到这里。这时EAX=1A0F6F,其实就是文件长度。
0040189B    8BD8            MOV EBX,EAX
0040189D    E8 6A030000     CALL dumped_.00401C0C
004018A2    8BE8            MOV EBP,EAX=====>经过上面的CALL后EAX=EOFBA。
004018A4    59              POP ECX
004018A5    3BEB            CMP EBP,EBX=====>以上两个值比较。
004018A7    75 05           JNZ SHORT dumped_.004018AE====>不等则跳,跳则出错。原程序跳,脱壳后程序也跳。
004018A9    6A 0D           PUSH 0D
004018AB    5B              POP EBX
004018AC    EB 71           JMP SHORT dumped_.0040191F
004018AE    57              PUSH EDI
004018AF    55              PUSH EBP
004018B0    56              PUSH ESI
004018B1    E8 3E010000     CALL dumped_.004019F4
004018B6    6A 04           PUSH 4
004018B8    68 10914100     PUSH dumped_.00419110
004018BD    56              PUSH ESI
004018BE    E8 46010000     CALL dumped_.00401A09
004018C3    A1 10914100     MOV EAX,DWORD PTR DS:[419110]
004018C8    83C4 18         ADD ESP,18
004018CB    3BC7            CMP EAX,EDI
004018CD   /74 09           JE SHORT dumped_.004018D8====>跳!
004018CF   |50              PUSH EAX
004018D0   |E8 965E0000     CALL dumped_.0040776B
004018D5   |59              POP ECX
004018D6   |8BF8            MOV EDI,EAX
004018D8   \FF35 10914100   PUSH DWORD PTR DS:[419110]
004018DE    57              PUSH EDI
004018DF    56              PUSH ESI
004018E0    E8 24010000     CALL dumped_.00401A09
004018E5    FF35 10914100   PUSH DWORD PTR DS:[419110]
004018EB    57              PUSH EDI
004018EC    E8 E3030000     CALL dumped_.00401CD4
004018F1    FF35 10914100   PUSH DWORD PTR DS:[419110]
004018F7    57              PUSH EDI
004018F8    E8 0F040000     CALL dumped_.00401D0C
004018FD    8BD8            MOV EBX,EAX
004018FF    83C4 1C         ADD ESP,1C
00401902    85DB            TEST EBX,EBX
00401904    75 0E           JNZ SHORT dumped_.00401914
00401906    A1 10914100     MOV EAX,DWORD PTR DS:[419110]
0040190B    8D4428 04       LEA EAX,DWORD PTR DS:[EAX+EBP+4]
0040190F    A3 14914100     MOV DWORD PTR DS:[419114],EAX
00401914    85FF            TEST EDI,EDI
00401916    74 07           JE SHORT dumped_.0040191F
00401918    57              PUSH EDI
00401919    E8 FF5E0000     CALL dumped_.0040781D
0040191E    59              POP ECX
0040191F    56              PUSH ESI
00401920    E8 28010000     CALL dumped_.00401A4D
00401925    59              POP ECX
00401926    5D              POP EBP
00401927    5F              POP EDI
00401928    8BC3            MOV EAX,EBX
0040192A    5E              POP ESI
0040192B    5B              POP EBX
0040192C    C3              RETN



那么004018A7处到底该不该跳?跟踪原程序后发现也是不跳的。原程序经过0040189D处的CALL后EAX=95000。那95000又是什么呢?经过跟踪原程序发现,原来95000是文件偏移地址,那里有数据“000011BA”。看看原来95000处的数据:

Offset     0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00095000   BA 11 00 00 DC ED BD A9  B2 46 A9 79 48 86 9F 50   ?..茼僵睩﹜H啛P
00095010   84 60 19 91 58 D9 31 A8  13 F3 B5 A2 C4 C3 D4 E5   刞.慩??蟮⒛迷?

00095020   CB 9D FF DC FE EF 8F 5B  4B 44 03 32 17 04 C7 83   藵荥飶[KD.2..莾
00095030   03 82 62 48 28 A8 C8 13  55 A4 E3 92 B7 65 A6 22   .俠H(ㄈ.Uゃ挿e?
00095040   A2 82 F3 44 03 32 17 A3  A4 DA EC EE ED EF 1E 9E   驞.2.¥陟铐??

00095050   6A B4 43 DB DA 83 13 8A  8B 22 25 54 A5 95 F2 03   j碈圳?妺"%T?
00095060   33 28 48 08 68 C4 16 C3  B6 C3 17 A4 C5 F4 72 32   3(H.h?枚?づ魊2
00095070   C6 92 C2 25 33 82 C6 34  24 64 23 D3 F6 43 17 83   茠?3偲4$d#遇C.
........


再看看脱壳后文件的偏移EOFBA处:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

000E0FB0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
000E0FC0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
000E0FD0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
000E0FE0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
000E0FF0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
000E1000   00 00 00 00 00 00 00 00  00 00 00 00 A0 10 0E 00   ............?..
000E1010   00 40 01 00 00 00 00 00  00 00 00 00 00 00 00 00   .@..............
000E1020   E0 10 0E 00 10 40 01 00  00 00 00 00 00 00 00 00   ?...@..........
000E1030   00 00 00 00 04 11 0E 00  18 40 01 00 00 00 00 00   .........@......
000E1040   00 00 00 00 00 00 00 00  5A 12 0E 00 6C 40 01 00   ........Z...l@..
000E1050   00 00 00 00 00 00 00 00  00 00 00 00 58 19 0E 00   ............X...
000E1060   04 42 01 00 00 00 00 00  00 00 00 00 00 00 00 00   .B..............
000E1070   84 19 0E 00 14 42 01 00  00 00 00 00 00 00 00 00   ?...B..........
000E1080   00 00 00 00 D8 19 0E 00  28 42 01 00 00 00 00 00   ....?..(B......
000E1090   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

根本没有这些数据。再搜索“000011BA”,也搜索不到,看来这些数据在脱壳时丢失了。现在得想加法补回去。

从原程序文件的偏移95000处到文件末尾复制后粘贴到脱壳后的文件末尾。我这里的起始地址是50D50。运行后程序还是提示原来的错误。什么原因?原来程序还是从偏移EOFBA处查找“000011BA”,当然找不到。好,现在得让程序从50D50处查找。我是直接修改:

0040189D    E8 6A030000     CALL dumped_.00401C0C====>这个CALL是返回查找地址的,我直接改为MOV EAX,50D50 字节刚好。
004018A2    8BE8            MOV EBP,EAX

保存程序,运行OK。