首页
社区
课程
招聘
脱壳手记---themida(1.8.5.5)
发表于: 2013-6-4 13:47 28455

脱壳手记---themida(1.8.5.5)

2013-6-4 13:47
28455
【文章标题】:脱壳手记---themida(1.8.5.5)
【文章作者】: qqmcc
【下载地址】:  sayhello.rar
载入OD后,先看看Memory map,看到多了个壳段(图1)
 
00401000下硬件写入断点
两次shift+f9断在
00618D04    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
这里写入代码段,之后去00401000看看
00401000    55              PUSH EBP
00401001    8BEC            MOV EBP,ESP
00401003    51              PUSH ECX
00401004    53              PUSH EBX
00401005    56              PUSH ESI
00401006    57              PUSH EDI
00401007    68 30604000     PUSH 00406030        ; ASCII "hello"
0040100C    6A 65           PUSH 65
0040100E    6A 00           PUSH 0
00401010    90              NOP
00401011    90              NOP   00401012    90              NOP
00401013    90              NOP
00401014    90              NOP
00401015    90              NOP
00401016    8BF0            MOV ESI,EAX
00401018    56              PUSH ESI
00401019    6A 00           PUSH 0
0040101B    90              NOP
0040101C    90              NOP   ;下硬件写入断点
0040101D    90              NOP
0040101E    90              NOP
0040101F    90              NOP
00401020    90              NOP
00401021    56              PUSH ESI
00401022    6A 00           PUSH 0
00401024    90              NOP
00401025    90              NOP
00401026    90              NOP
00401027    90              NOP
00401028    90              NOP
00401029    90              NOP
0040102A    8BF0            MOV ESI,EAX

并没有完全解码,继续找未解码处下硬件写入断点:
006229B1    AA              STOS BYTE PTR ES:[EDI]  
分析一下这里的代码,F8单步:
发现填充的是一个call
00401018    56              PUSH ESI
00401019    6A 00           PUSH 0
0040101B    90              NOP
0040101C    E8 FBF34F02     CALL 0290041C
继续跟一下:
006229DB    8B85 B1250E0A   MOV EAX,DWORD PTR SS:[EBP+A0E25B1]
006229E1    2BC7            SUB EAX,EDI
006229E3    83E8 04         SUB EAX,4                    ;取得CALL偏移
006229E6    AB              STOS DWORD PTR ES:[EDI]      ;填充CALL偏移
006229E7    AD              LODS DWORD PTR DS:[ESI]      ;将[esi]赋值eax
                                                        [esi]是一张表见(图2)
006229E8    C746 FC 0000000>MOV DWORD PTR DS:[ESI-4],0    ;清零
006229EF  ^ E9 11FFFFFF     JMP 00622905   ;这里跳回去看是都还有需要处理的”nop”


--------------------------------------------------------------------------------------------------------------------------------
00622905    MOV DWORD PTRSS:[EBP+A0E04DD],ESI     ;比较[esi]的值                    
0062290B    83F8 FF         CMP EAX,-1           ;比较是否为FFFFFFFF
0062290E    0F85 20000000   JNZ 00622934         ;不是就跳走
00622914    813E DDDDDDDD   CMP DWORD PTR DS:[ESI],DDDDDDDD ;比较当前[esi]是否为DDDDDDDD
0062291A    0F85 14000000   JNZ 00622934                 ;不是跳走,应为结束标记以控制循环
00622920    C706 00000000   MOV DWORD PTR DS:[ESI],0    ;当前[ESI]填0, 
00622926    83C6 04         ADD ESI,4                    ;处理下一个[ESI+4]
00622929    89B5 DD040E0A   MOV DWORD PTR SS:[EBP+A0E04DD],ESI
0062292F  ^ E9 E6F6FFFF     JMP 0062201A    ;关注这个跳转,新一轮的解码处理
00622934    C1C0 03         ROL EAX,3
00622937    0385 45180E0A   ADD EAX,DWORD PTR SS:[EBP+A0E1845]
0062293D    83BD 9D190E0A 0>CMP DWORD PTR SS:[EBP+A0E199D],1
00622944    0F84 9D000000   JE 006229E7
0062294A    813E AAAAAAAA   CMP DWORD PTR DS:[ESI],AAAAAAAA
00622950    0F85 12000000   JNZ 00622968

[esi]数据截取(图2):

FFFFFFFF DDDDDDDD作为结束的话,那至少有五个元素,分别分析前面三个元素做什么用。
0062201A    C785 31110E0A 0>MOV DWORD PTR SS:[EBP+A0E1131],0;;从跳转到这里开始分析
00622024    C785 F5110E0A 0>MOV DWORD PTR SS:[EBP+A0E11F5],0
0062202E    83BD 723F1E0A 0>CMP DWORD PTR SS:[EBP+A1E3F72],0
00622035    0F84 08000000   JE 00622043
0062203B    8D9D 3D2C1D0A   LEA EBX,DWORD PTR SS:[EBP+A1D2C3D]
00622041    FFD3            CALL EBX
00622043    FF85 9D120E0A   INC DWORD PTR SS:[EBP+A0E129D]
00622049    83BD 9D120E0A 6>CMP DWORD PTR SS:[EBP+A0E129D],64 ;处理的元素大于0x64则进行一次校验
00622050    0F82 62000000   JB 006220B8     ;可以改成jmp忽略校验
00622056    C785 9D120E0A 0>MOV DWORD PTR SS:[EBP+A0E129D],1
00622060    60              PUSHAD
00622061    8DB5 4A401E0A   LEA ESI,DWORD PTR SS:[EBP+A1E404A]
00622067    8DBD B55C1E0A   LEA EDI,DWORD PTR SS:[EBP+A1E5CB5]
0062206D    2BFE            SUB EDI,ESI
0062206F    8BD7            MOV EDX,EDI    ;校验数据长度
00622071    8BBD 41150E0A   MOV EDI,DWORD PTR SS:[EBP+A0E1541]
00622077    83C9 FF         OR ECX,FFFFFFFF               ;初始化校验值
0062207A    33C0            XOR EAX,EAX
0062207C    8A06            MOV AL,BYTE PTR DS:[ESI]    ;校验数据起始地址
0062207E    32C1            XOR AL,CL
00622080    46              INC ESI
00622081    8B0487          MOV EAX,DWORD PTR DS:[EDI+EAX*4];查校验码表
00622084    C1E9 08         SHR ECX,8                  
00622087    33C8            XOR ECX,EAX                
00622089    4A              DEC EDX
0062208A  ^ 0F85 EAFFFFFF   JNZ 0062207A              ;循环检验
00622090    8BC1            MOV EAX,ECX
00622092    F7D0            NOT EAX                         ;得到最终验证码
00622094    3985 ED090E0A   CMP DWORD PTR SS:[EBP+A0E09ED],EAX ;校验比较


006220B8    B9 9CE7F31D     MOV ECX,1DF3E79C
006220BD    BA C4498C24     MOV EDX,248C49C4
006220C2    AD              LODS DWORD PTR DS:[ESI]
006220C3    89B5 DD040E0A   MOV DWORD PTR SS:[EBP+A0E04DD],ESI
006220C9    C746 FC 0000000>MOV DWORD PTR DS:[ESI-4],0
006220D0    3D EEEEEEEE     CMP EAX,EEEEEEEE     
006220D5    0F85 20000000   JNZ 006220FB
006220DB    813E DDDDDDDD   CMP DWORD PTR DS:[ESI],DDDDDDDD; EEEEEEEEDDDDDDDD实际上应为表全部处理完毕标识
006220E1    0F85 14000000   JNZ 006220FB
006220E7    C706 00000000   MOV DWORD PTR DS:[ESI],0
006220ED    83C6 04         ADD ESI,4
006220F0    89B5 DD040E0A   MOV DWORD PTR SS:[EBP+A0E04DD],ESI
006220F6    E9 F9080000     JMP 006229F4         ;跳出处理循环,到此处后可在代码段下访问断点来到OEP
006220FB    8BD8            MOV EBX,EAX
006220FD    3385 A9050E0A   XOR EAX,DWORD PTR SS:[EBP+A0E05A9]
00622103    C1C8 03         ROR EAX,3
00622106    2BC2            SUB EAX,EDX
00622108    C1C0 10         ROL EAX,10
0062210B    33C1            XOR EAX,ECX
0062210D    899D A9050E0A   MOV DWORD PTR SS:[EBP+A0E05A9],EBX
00622113    3D 00000100     CMP EAX,10000     
00622118    0F83 45000000   JNB 00622163
0062211E    813E BBBBBBBB   CMP DWORD PTR DS:[ESI],BBBBBBBB
00622124    0F85 39000000   JNZ 00622163
0062212A    C706 00000000   MOV DWORD PTR DS:[ESI],0
00622130    83C6 04         ADD ESI,4
00622133    89B5 DD040E0A   MOV DWORD PTR SS:[EBP+A0E04DD],ESI
00622139    8B9D F1230E0A   MOV EBX,DWORD PTR SS:[EBP+A0E23F1]
0062213F    8B0B            MOV ECX,DWORD PTR DS:[EBX]
00622141    8BD0            MOV EDX,EAX
00622143    60              PUSHAD
00622144    8BC2            MOV EAX,EDX
00622146    2B85 310A0E0A   SUB EAX,DWORD PTR SS:[EBP+A0E0A31]
0062214C    C1E0 02         SHL EAX,2
0062214F    0385 A1050E0A   ADD EAX,DWORD PTR SS:[EBP+A0E05A1]
00622155    96              XCHG EAX,ESI
00622156    AD              LODS DWORD PTR DS:[ESI]
00622157    03C1            ADD EAX,ECX
00622159    894424 1C       MOV DWORD PTR SS:[ESP+1C],EAX
0062215D    61              POPAD
0062215E    E9 7C000000     JMP 006221DF
0062215E    E9 7C000000     JMP 006221DF
00622163    51              PUSH ECX
00622164    52              PUSH EDX
00622165    33C9            XOR ECX,ECX
00622167    8B95 2D0B0E0A   MOV EDX,DWORD PTR SS:[EBP+A0E0B2D];[esi]表中取得的第一个元素将和[EBP+A0E0B2D]数组的元素一一对比
                                    它是取得原始API的一个KEY
0062216D    3B02            CMP EAX,DWORD PTR DS:[EDX]
0062216F    0F84 38000000   JE sayhello.006221AD  ;找到后跳转到后续执行
00622175    83C2 04         ADD EDX,4
00622178    41              INC ECX          ;此时的ecx将是[EBP+A0E0B2D]表的数组下标
00622179    3B8D 59040E0A   CMP ECX,DWORD PTR SS:[EBP+A0E0459]
0062217F  ^ 0F85 E8FFFFFF   JNZ sayhello.0062216D
00622185    8DB5 2F3F1E0A   LEA ESI,DWORD PTR SS:[EBP+A1E3F2F]
0062218B    8DBD 2D010E0A   LEA EDI,DWORD PTR SS:[EBP+A0E012D]
00622191    AC              LODS BYTE PTR DS:[ESI]
00622192    84C0            TEST AL,AL
00622194    0F84 06000000   JE sayhello.006221A0
0062219A    AA              STOS BYTE PTR ES:[EDI]
0062219B  ^ E9 F1FFFFFF     JMP sayhello.00622191
006221A0    B8 00000000     MOV EAX,0
006221A5    8D8D 734B0E0A   LEA ECX,DWORD PTR SS:[EBP+A0E4B73]
006221AB    FFE1            JMP ECX
006221AD    898D C9310E0A   MOV DWORD PTR SS:[EBP+A0E31C9],ECX
006221B3    5A              POP EDX
006221B4    59              POP ECX
006221B5    56              PUSH ESI
006221B6    8B9D F1230E0A   MOV EBX,DWORD PTR SS:[EBP+A0E23F1]
006221BC    8B0B            MOV ECX,DWORD PTR DS:[EBX]
006221BE    8B85 C9310E0A   MOV EAX,DWORD PTR SS:[EBP+A0E31C9]
006221C4    D1E0            SHL EAX,1
006221C6    0385 CD270E0A   ADD EAX,DWORD PTR SS:[EBP+A0E27CD]
006221CC    33F6            XOR ESI,ESI
006221CE    96              XCHG EAX,ESI
006221CF    66:AD           LODS WORD PTR DS:[ESI]
006221D1    C1E0 02         SHL EAX,2
006221D4    0385 A1050E0A   ADD EAX,DWORD PTR SS:[EBP+A0E05A1]
006221DA    96              XCHG EAX,ESI
006221DB    AD              LODS DWORD PTR DS:[ESI]
006221DC    03C1            ADD EAX,ECX              ;到这里eax出现了api地址,
此时我们明白第一个元素解析出API地址 
但是经过后面的实验,
这里有时候出现的只是API的字符串
006221DE    5E              POP ESI
006221DE    5E              POP ESI
006221DF    83BD E5030E0A 0>CMP DWORD PTR SS:[EBP+A0E03E5],1
006221E6    0F84 39000000   JE sayhello.00622225
006221EC    3B8D A1130E0A   CMP ECX,DWORD PTR SS:[EBP+A0E13A1]
006221F2    0F84 2D000000   JE sayhello.00622225
006221F8    3B8D 75200E0A   CMP ECX,DWORD PTR SS:[EBP+A0E2075]
006221FE    0F84 21000000   JE sayhello.00622225
00622204    3B8D C5080E0A   CMP ECX,DWORD PTR SS:[EBP+A0E08C5]
0062220A    0F84 15000000   JE sayhello.00622225
00622210    8D9D 8D541E0A   LEA EBX,DWORD PTR SS:[EBP+A1E548D]
00622216    FFD3            CALL EBX
00622218    8BF8            MOV EDI,EAX
0062221A    8985 B1250E0A   MOV DWORD PTR SS:[EBP+A0E25B1],EAX
00622220    E9 B4060000     JMP sayhello.006228D9
00622225    8D9D 8D541E0A   LEA EBX,DWORD PTR SS:[EBP+A1E548D]
0062222B    FFD3            CALL EBX               ;经过这个CALL后 ,eax确定为API地址
0062222D    83BD E5030E0A 0>CMP DWORD PTR SS:[EBP+A0E03E5],0 

找出之后还会比较是不是指定的几个API 
将API代码逻辑上复制到一个新地址,这里是28d0000 

0062277E    8D9D D7561E0A   LEA EBX,DWORD PTR SS:[EBP+A1E56D7]
00622784    FFD3            CALL EBX
00622786    8D9D BF591E0A   LEA EBX,DWORD PTR SS:[EBP+A1E59BF]
0062278C    FFD3            CALL EBX
0062278E    0F83 0C000000   JNB sayhello.006227A0
00622794    8385 A50F0E0A 0>ADD DWORD PTR SS:[EBP+A0E0FA5],5
0062279B  ^ E9 DEFFFFFF     JMP sayhello.0062277E
006227A0    8D9D E8591E0A   LEA EBX,DWORD PTR SS:[EBP+A1E59E8]
006227A6    FFD3            CALL EBX
006227A8    0F83 08000000   JNB sayhello.006227B6
006227AE    83C2 04         ADD EDX,4
006227B1    E9 32000000     JMP sayhello.006227E8
006227B6    8D9D 512F1C0A   LEA EBX,DWORD PTR SS:[EBP+A1C2F51]
006227BC    FFD3            CALL EBX
006227BE    0F83 0B000000   JNB sayhello.006227CF
006227C4    8BB5 A50F0E0A   MOV ESI,DWORD PTR SS:[EBP+A0E0FA5]
006227CA    E9 80070000     JMP sayhello.00622F4F
006227CF    8B8D A50F0E0A   MOV ECX,DWORD PTR SS:[EBP+A0E0FA5]
006227D5    89B5 A50F0E0A   MOV DWORD PTR SS:[EBP+A0E0FA5],ESI
006227DB    2BCE            SUB ECX,ESI
006227DD    F7D9            NEG ECX        ;计算出当前API函数的当前指令字节数

006227DF    2BF1            SUB ESI,ECX
006227E1    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
                                              将API原实现代码复制到一个新地址,这里是28c0000
006227E3  ^ E9 96FFFFFF     JMP sayhello.0062277E
在28e00000将28D0000代码变形
0062280E    8B85 9D110E0A   MOV EAX,DWORD PTR SS:[EBP+A0E119D]
00622814    50              PUSH EAX
00622815    57              PUSH EDI
00622816    8B85 F5000E0A   MOV EAX,DWORD PTR SS:[EBP+A0E00F5]
0062281C    50              PUSH EAX
0062281D    8D8D E12C1D0A   LEA ECX,DWORD PTR SS:[EBP+A1D2CE1]
00622823    FFD1            CALL ECX         ;这个CALL为代码变形并将变形的代码写入新地址
00622825    8BD0            MOV EDX,EAX
006228BD    8D85 73311D0A   LEA EAX,DWORD PTR SS:[EBP+A1D3173]
006228C3    FFD0            CALL EAX
006228C5    018D 7D110E0A   ADD DWORD PTR SS:[EBP+A0E117D],ECX
006228CB    8BBD B1250E0A   MOV EDI,DWORD PTR SS:[EBP+A0E25B1]
006228D1    8BB5 9D110E0A   MOV ESI,DWORD PTR SS:[EBP+A0E119D]
006228D7    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
代码复制到[edi],此时EDI即为处理后的”API”地址
006228D9    8BB5 DD040E0A   MOV ESI,DWORD PTR SS:[EBP+A0E04DD]       ; sayhello.0061A414

以上对API代码的变形其实对于脱壳并不太重要,我们只要知道TMD将从[esi]表成员中第一个元素将得到API就足够了
然后处理第二个元素:
第二个元素解密出IAT的地址,然后将变形后的API代码地址填充进去
006228DF    AD              LODS DWORD PTR DS:[ESI] ; 处理下一个元素
006228E0    C746 FC 0000000>MOV DWORD PTR DS:[ESI-4],0 ; 取得元素值后清0
006228E7    C1C0 05         ROL EAX,5
006228EA    05 9CE7F31D     ADD EAX,1DF3E79C
006228EF    0385 45180E0A   ADD EAX,DWORD PTR SS:[EBP+A0E1845] ;得到IAT的VA
006228F5    8B8D B1250E0A   MOV ECX,DWORD PTR SS:[EBP+A0E25B1]
006228FB    8908            MOV DWORD PTR DS:[EAX],ECX ; 将处理的API地址填进去

(图3)

 
这里我们可以看出,IAT的起始地址是405000
继续分析第三个元素:
很快可以发现第三个元素得到的是代码中需要填充的nop地址,我们姑且称之为CALLAPI
006228FD    AD              LODS DWORD PTR DS:[ESI] ;下一个元素
006228FE    C746 FC 0000000>MOV DWORD PTR DS:[ESI-4],0
00622905    89B5 DD040E0A   MOV DWORD PTR SS:[EBP+A0E04DD],ESI
0062290B    83F8 FF         CMP EAX,-1   ;比较否处理完毕
0062290E    0F85 20000000   JNZ sayhello.00622934
00622914    813E DDDDDDDD   CMP DWORD PTR DS:[ESI],DDDDDDDD
0062291A    0F85 14000000   JNZ sayhello.00622934
00622920    C706 00000000   MOV DWORD PTR DS:[ESI],0
00622926    83C6 04         ADD ESI,4
00622929    89B5 DD040E0A   MOV DWORD PTR SS:[EBP+A0E04DD],ESI
0062292F  ^ E9 E6F6FFFF     JMP sayhello.0062201A
00622934    C1C0 03         ROL EAX,3
00622937    0385 45180E0A   ADD EAX,DWORD PTR SS:[EBP+A0E1845] ;得到CALLAPI地址
0062293D    83BD 9D190E0A 0>CMP DWORD PTR SS:[EBP+A0E199D],1
00622944    0F84 9D000000   JE sayhello.006229E7
0062294A    813E AAAAAAAA   CMP DWORD PTR DS:[ESI],AAAAAAAA ;这里有个AAAAAAAA标识
00622950    0F85 12000000   JNZ sayhello.00622968
00622956    83C6 04         ADD ESI,4
00622959    C746 FC 0000000>MOV DWORD PTR DS:[ESI-4],0
00622960    97              XCHG EAX,EDI
00622961    B0 E9           MOV AL,0E9    ;AAAAAAAA将为AL赋值E9
00622963    E9 03000000     JMP sayhello.0062296B
00622968    97              XCHG EAX,EDI
00622969    B0 E8           MOV AL,0E8 ;不是将为AL赋值E8

这里比较AAAAAAAA需要说明一下,它实际上是TMD判断原来代码中的FF15(“CALL 地址”)和FF25(”JMP 地址”),我们在修复的时候也需要判断,至于判断的方法也不一定要从这里,知道了流程,脚本的方法是很多的。
00622993    803F 90         CMP BYTE PTR DS:[EDI],90
00622996    0F84 08000000   JE 006229A4
0062299C    83C7 05         ADD EDI,5
0062299F    E9 43000000     JMP 006229E7
006229A4    83F8 50         CMP EAX,50
006229A7    0F82 0A000000   JB 006229B7
006229AD    B0 90           MOV AL,90
006229AF    AA              STOS BYTE PTR ES:[EDI]
006229B0    58              POP EAX
006229B1    AA              STOS BYTE PTR ES:[EDI]
006229B2    E9 24000000     JMP 006229DB
006229B7    58              POP EAX
006229B8    AA              STOS BYTE PTR ES:[EDI]
006229B9    807F FF E9      CMP BYTE PTR DS:[EDI-1],0E9
。。。。
。。。。
006229E6    AB              STOS DWORD PTR ES:[EDI];填充CALLAPI
006229E7    AD              LODS DWORD PTR DS:[ESI]
006229E8    C746 FC 0000000>MOV DWORD PTR DS:[ESI-4],0
006229EF  ^ E9 11FFFFFF     JMP 00622905

上面这一段随机运算,看是否在第一个”NOP”开始填写
然后将刚才得到的变形API地址计算偏移后填充到此处

上面分析完了一个API的处理过程,其实主要还是在于TMD的这个[esi]表,由于我们的程序比较简单,可能有些情况是没有涉及到的,比如校验,比如导入多个模块,但是大体流程都是这样的,只要掌握了就算难一点的程序脱壳也是没有问题的。 
校验只是超过0x64个API后进行一次,脚本中已经做过处理,增加几个模块无非是[esi]表中增加一个XXXXXXXX之类的标识符来判断一个导入模块处理结束。
至于脱壳脚本,我并没有打算给出一个通用的,通用的已经有了。这里脚本并不通用,主要是回顾一下流程,TMD的流程都是这样,高版本也仅是略有差异,顺着这个思路分析高版本也是很快的(当然并不是说恢复VM,仅脱壳而言,它不过是将一些API的处理过程放在VM代码中,然而蛛丝马迹总是能找到的),我们的脚本思路是后发制人,就是等TMD填充好之后我们重新填充回去。下面整理分析过程中得到的几个断点
HW 00401000   
ESTO
ESTO        ;代码段解码初步完毕,实际上可以不需要
0062201A ;解码表代码初始位置
0062222d ;此时eax为解码的API地址
006228fd;此时eax为IAT地址
0062294a; 这里得到的是代码中的CALLAPI
006228fd; 这个时候代码填入变形API地址,我们再改回来
006229e8;CALLAPI填充完毕
注意我的断点都是比实际得到的稍微后几步,这个看个人爱好。
下面是脚本:
-----------------------------------------------------------------------------------------
var iatadd
var apiadd
var calladd
bc
BPHWC
BPHWS 00401000,"w"
ESTO
ESTO
BPHWC 00401000
BPHWS 0062201A,"x" ;解码表代码初始位置
ESTO
BPHWC 0062201A
bp 006229f4
BPHWS 0062222d,"x"  ;eax为API地址
BPHWS 006228fd,"x"   ;eax为IAT地址,并且已填入变形API地址
BPHWS 0062294a,"x" ;这里得到的是代码中的CALLAPI
ESTO
mov [00602050],#EB6690909090# ;这里达到条件跳转到校验代码,改成jmp略过
apilb:
cmp eip,0062222d  ;看是否断在取API地址处
jne iatlb           ;不是则跳到IAT处理段
mov apiadd,eax     ;保存API地址
esto
iatlb:
cmp eip,006228fd ;看是否断在取IAT处
jne iatlb2
mov iatadd,eax     ;保存IAT地址
mov [iatadd],apiadd ;填入正确的API地址
esto
iatlb2:

cmp eip,0062222d     ;有些函数不需要在代码中填充,因此不会在0062294aCALLAPI处断下,直接返回继续下一个元素  
je apilb             
mov calladd,eax     ; 此时只能是断在0062294a处eax中的值为代码中需要填充callapi的地址
BPHWS 006229e8,"x" 
esto
find calladd,#E9#,2  ;看TMD填充的是否为E9,如果是我们需要改为FF25 JMP型
cmp $RESULT,0
jne fillff25
mov [calladd],#ff15# ;不为E9,则改成FF15型
mov [calladd+2],iatadd
jmp fillend
fillff25:
mov [calladd],#ff25#
mov [calladd+2],iatadd
fillend:
BPHWC 006229e8
esto
cmp eip,006229f4
je exit
jmp apilb

exit:
bc
bprm 00401000,4000  ; 跳到伪OEP
esto
ret


脚本运行完毕之后,来到(图4)

堆栈如(图5)

可以看出这是一段VC的头部(VC头部代码如下):
text:004183D7
.text:004183D7 55                      push    ebp
.text:004183D8 8B EC                   mov     ebp, esp
.text:004183DA 6A FF                   push    0FFFFFFFFh
.text:004183DC 68 18 CB 41 00          push    offset unk_41CB18 ;需要修改
.text:004183E1 68 2C 9D 41 00        push    offset unknown_libname_2 ;需要修改
.text:004183E6 64 A1 00 00 00 00       mov     eax, large fs:0
.text:004183EC 50                      push    eax
.text:004183ED 64 89 25 00 00 00 00    mov     large fs:0, esp
.text:004183F4 83 EC 58                sub     esp, 58h       ;需要修改
.text:004183F7 53                      push    ebx
.text:004183F8 56                      push    esi
.text:004183F9 57                      push    edi
.text:004183FA 89 65 E8                mov     [ebp+var_18], esp
.text:004183FD FF 15 74 B1 41 00       call    ds:GetVersion
.text:00418403 33 D2                   xor     edx, edx
.text:00418405 8A D4                   mov     dl, ah       ;以上为缺失的代码
.text:00418407 89 15 DC 22 42 00       mov     dword_4222DC, edx
.text:0041840D 8B C8                   mov     ecx, eax
.text:0041840F 81 E1 FF 00 00 00       and     ecx, 0FFh

以上三处需要修改的值可以再堆栈中找到:
$ ==>    > 028B002A
$+4      > 00622C78  sayhello.00622C78
$+8      > 00622786  sayhello.00622786
$+C      > 00622C78  sayhello.00622C78
$+10     > 00000000
$+14     > 0012FF40                              ;sub esp,14
$+18     > 00622786  sayhello.00622786
$+1C     > 0012FF9C  指向下一个 SEH 记录的指针
$+20     > 004020AC  SE 处理器                 ;第二个push值
$+24     > 004050B0  sayhello.004050B0           ;第一个push值

然后把修改后的代码贴到0040147e前面,dump之后去掉壳段用import REC修复一下就可以了。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
免费 7
支持
分享
最新回复 (15)
雪    币: 45
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
谢谢正好要看下难点的壳怎么脱的
2013-6-4 14:05
0
雪    币: 60
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
前排留名
2013-6-4 16:57
0
雪    币: 437
活跃值: (78)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
收藏研究,感谢分享
2013-6-7 09:13
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好帖啊 学习学习!
2013-6-11 12:12
0
雪    币: 120
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
谢谢楼主详细的分析 。很好的贴子。学习学习。
2013-6-12 22:10
0
雪    币: 177
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
非常不错,学习了
2013-6-13 09:14
0
雪    币: 220
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢楼主分享,用OD打开会自动退出。
2013-6-13 10:30
0
雪    币: 143
活跃值: (108)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
9
配合使用StrongOD和PhantOm插件,多试几次,一般的壳反调试都可以忽略
2013-6-13 22:12
0
雪    币: 110
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
怎么也修复不理!!看来是哪里没搞对,估计是填那一定的时候,堆栈没搞好。
2013-8-18 21:37
0
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
TMD脱壳,难!LZ牛X!
2013-8-19 13:56
0
雪    币: 196
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
TMD脱壳,难!
2013-8-19 15:56
0
雪    币: 47
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
想问一下最后esp修改为14是什么意思呢?
2013-11-18 09:06
0
雪    币: 300
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
非常厉害。大牛!
2013-12-14 11:22
0
雪    币: 23
活跃值: (73)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
没有样本啊
2014-11-10 19:10
0
雪    币: 4662
活跃值: (3887)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
确实是一篇好文章,用你的方法在你提供的程序文件上确实可以跟到一样的数据。但OD不是随便选择的我这里用的是吾爱的版本。
2018-11-10 12:28
0
游客
登录 | 注册 方可回帖
返回
//