【文章标题】:脱壳手记---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虚拟机自动化脱壳的方法