首页
社区
课程
招聘
[旧帖] [原创]手工脱壳方法总结 0.00雪花
发表于: 2009-5-31 12:29 1425

[旧帖] [原创]手工脱壳方法总结 0.00雪花

2009-5-31 12:29
1425
初来看雪,在潜水许久之后我也来发发帖子,希望对跟我一样的初学者能有一些帮助
  为了不让软件的作者告我侵权,本次所用的软件就是微软的扫雷游戏,用小P查一下,使用C++编译的(Microsoft Visual C++ 7.0 Method2 [Debug])先用ASPack加壳,具体过程我就不多说了,这不是重点。加完后再用小P查,变为(ASPack 2.12 -> Alexey Solodovnikov)
现在开始我们的脱壳。
  
  方法一  纯手工单步步入发
  用OD载入,开进入后显示如下:
01020001 >  60              PUSHAD
01020002    E8 03000000     CALL winmine.0102000A
01020007  - E9 EB045D45     JMP 465F04F7
0102000C    55              PUSH EBP
0102000D    C3              RETN
0102000E    E8 01000000     CALL winmine.01020014
01020013    EB 5D           JMP SHORT winmine.01020072
01020015    BB EDFFFFFF     MOV EBX,-13
0102001A    03DD            ADD EBX,EBP
0102001C    81EB 00000200   SUB EBX,20000
01020022    83BD 22040000 0>CMP DWORD PTR SS:[EBP+422],0
01020029    899D 22040000   MOV DWORD PTR SS:[EBP+422],EBX
  我们看到,第二行就有一个Call,用来调用子程序,接着F8到第二行,用F7跟进。这是手工单步步入最关键的地方,在遇到刚开始就出现的Call,一定要F7跟进。
进入后显示如下:
0102000A    5D              POP EBP             ; winmine.01020007
0102000B    45              INC EBP
0102000C    55              PUSH EBP
0102000D    C3              RETN
0102000E    E8 01000000     CALL winmine.01020014
01020013    EB 5D           JMP SHORT winmine.01020072
   我们在第五行又遇到了一个Call,继续用F8到第五行,然后F7跟进,也许有的初学者会说上面还有一个retn,但你在步过后发现,他在跳上后还是指向了0102000E处,或者,你如果不放心,直接在0102000E处F4(即运行的选定位置处),一样可以。
  然后我们就不要在步入了,,因为我们在步入之后发现:
01020014    5D              POP EBP                ; winmine.01020013
01020015    BB EDFFFFFF     MOV EBX,-13
0102001A    03DD            ADD EBX,EBP
0102001C    81EB 00000200   SUB EBX,20000
01020022    83BD 22040000 0>CMP DWORD PTR SS:[EBP+422],0
01020029    899D 22040000   MOV DWORD PTR SS:[EBP+422],EBX
0102002F    0F85 65030000   JNZ winmine.0102039A
01020035    8D85 2E040000   LEA EAX,DWORD PTR SS:[EBP+42E]
0102003B    50              PUSH EAX
0102003C    FF95 4D0F0000   CALL DWORD PTR SS:[EBP+F4D]
  离我们最近的call也有第十行,所以就不要在步入了,一般ASPack的壳两处Call就可以了,至于别的壳也是差不多。所以我们就一直F8下去,此时不要心急,不要点得太快,因为最关键的在下面:
0102012D    0BC9            OR ECX,ECX
0102012F    74 2E           JE SHORT winmine.0102015F
01020131    78 2C           JS SHORT winmine.0102015F
01020133    AC              LODS BYTE PTR DS:[ESI]
01020134    3C E8           CMP AL,0E8
01020136    74 0A           JE SHORT winmine.01020142
01020138    EB 00           JMP SHORT winmine.0102013A
0102013A    3C E9           CMP AL,0E9
0102013C    74 04           JE SHORT winmine.01020142
0102013E    43              INC EBX
0102013F    49              DEC ECX
01020140  ^ EB EB           JMP SHORT winmine.0102012D
01020142    8B06            MOV EAX,DWORD PTR DS:[ESI]
   看见没有,01020140处有一个向上的跳转,指向0102012D,我们此刻点击它的下一处地址01020142处,按F4。然后接着一路F8,如果有向上的跳转,就用上面的方法绕过。
  经过了N次F8和F4,我们终于到了这里:
010203A9    8985 A8030000   MOV DWORD PTR SS:[EBP+3A8],EAX
010203AF    61              POPAD
010203B0    75 08           JNZ SHORT winmine.010203BA
010203B2    B8 01000000     MOV EAX,1
010203B7    C2 0C00         RETN 0C
010203BA    68 213E0001     PUSH winmine.01003E21
010203BF    C3              RETN
   接着按F8到010203BF(RETN)上,再按一下,就跳到程序真正的入口了,在上面点右键——>用Ollydump脱壳调试进程,再然后点脱壳,保存就行了。
完事后用小P检查一下——Microsoft Visual C++ 7.0 Method2 [Debug],脱壳成功!
  总结:上述方法是利用绕过壳的跳转找到软件的OEP的,相当于步过了壳的所有代码,在面对一般的壳,如ASPack,UPX是很好用,因为它们的壳的代码不长,如果是一些高级壳,F8会让你按到手软的。
  
  方法二   一步跳转法
还记得我们用第一种方法是最后的代码吗?
010203A9    8985 A8030000   MOV DWORD PTR SS:[EBP+3A8],EAX
010203AF    61              POPAD
010203B0    75 08           JNZ SHORT winmine.010203BA
010203B2    B8 01000000     MOV EAX,1
010203B7    C2 0C00         RETN 0C
010203BA    68 213E0001     PUSH winmine.01003E21
010203BF    C3              RETN
看到没有,010203AF处为POPAD,那么有人就想到了,能不能用查找命令直接找到popad,然后自然就找到retn呢?答案是肯定的。
当这个方法也比较局限,我只在UPX和ASPack上用过。
用OD载入扫雷,按CTRL+F(查找命令),在弹出的查找命令框中输入popad,然后点查找,注意不要选“整个块”,点击“查找”,再查找到一个后,发现不是我们想要的,按ctrl+L(查找下一个),直到找到我们要的popad,然后用F8到RETN,接着脱壳。
  总结:这种方法利用了retn附近的特殊码来进行查找,从而找到retn,但具有一定的局限性,我也是只在UPX和ASPack壳上用过,大家自己看着办吧。

  方法三  ESP追入法
看看我们的壳的开头:
01020001 >  60              PUSHAD
01020002    E8 03000000     CALL winmine.0102000A
01020007  - E9 EB045D45     JMP 465F04F7
0102000C    55              PUSH EBP
0102000D    C3              RETN
0102000E    E8 01000000     CALL winmine.01020014
01020013    EB 5D           JMP SHORT winmine.01020072
01020015    BB EDFFFFFF     MOV EBX,-13
0102001A    03DD            ADD EBX,EBP
0102001C    81EB 00000200   SUB EBX,20000
01020022    83BD 22040000 0>CMP DWORD PTR SS:[EBP+422],0
01020029    899D 22040000   MOV DWORD PTR SS:[EBP+422],EBX
注意这句:01020001 >  60              PUSHAD
众所周知,pushad是进栈语令,那么,有进就有出,出时就到了程序入口,所以,我们先按一下F8让它进栈,接着在01020002上,我们看右边的寄存器,ESP后面是红的值0007FFA4,既有数据进栈,我们在命令行(最下面)里输入dd(显示堆栈格式数据)  0007FFA4,然后按回车,在左下方弹出的地址上点右键——>断点——>硬盘访问——>字。
然后按F9让程序运行,我们可以看见,直接到了RETN。
   
  总结:这种方法主要是利用第一句中的pushad,因为有了入栈,我们才有了后面通过在ESP上下断的思路,大家在以后见到第一句是入栈命令,如:pushad,pushfd的,都可以用这种方法,看到右侧的寄存器中ESP后数值为红色,既有数据进栈。

  第四种:利用OD自己检测
载入扫雷,在“调试”——>“调试选项”中有一“SFX”选项卡,中间有一项——“字节方式跟踪真正入口处”,我当时有点被小雷了,照这么说OD可以自己查找OEP,所以我就选了这一项,结果……OD做到了,在弹出的入口处脱壳,一样可以成功。我真的被雷了……
  总结:这种方法比较诡异,我没在多数的壳上试过,但也是种偷懒的方法,就是有时速度有点慢。

  声明:上述方法大部分都是网上常用的方法,所以你如果说我抄袭我不想说什么话来辩解,但这篇文章是我一个字一个字敲出来的,这四种方法我也是个试了不下十遍的,这点我可以凭良心保证,虽然这年头良心不值钱。我只是希望上述方法对跟我一样的初学者有一定的帮助,还有我的总结,我觉得这些心得比方法更重要。要说的就是这么多,不想辩解什么。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 52
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
实在不好意思,我向大家道歉!!!!!我当天晚上在法这篇文章时,显示我的发帖量已达到4篇,所以不能再发,所以今天又发了这篇,不知道看雪的系统还可以寄存,所以实在对不起各位,浪费你们的时间,请管理员删除这篇文章。
再一次抱歉!!!
2009-5-31 12:34
0
游客
登录 | 注册 方可回帖
返回
//