脱壳工具:脱壳基础知识入门的用内存断点找OEP

  1.前言

  发现论坛中很多兄弟在询问:什么是 2次内存断点 3次内存断点还有很多人对内存断点原理不是很明白其实只要懂得壳是如何解压代码那么就完全可以按自己喜欢来下断

  本文要解决问题是:

  1.什么是内存断点?

  2.如何在寻找OEP时使用内存断点

  3.内存断点局限性

  2.内存断点寻找OEP原理

  i.首先在OD中内存断点硬件断点和普通断点(F2下断)是有本质区别硬件断点等效和SoftICE命令bpm中断要用到DR0-DR7调试寄存器也就是说OD通过这些DR0-DR7调试寄存器来判断是否断下

  普通断点(F2下断)等效于bpx他是在所执行代码当前地址个字节修改为CC(3)运行到3时候就会产生个异常而这个异常将交给OD处理把这个异常regEIP-1以后就正好停在了需要中断地方(这个根据系统区别会不样)同时OD在把上面3修改回原来代码

  而内存断点基本上使用是对代码使用保护属性来实现中断

  内存断点分为:内存访问断点内存写入断点

  我们知道运行时候会有3种基本状态产生:读取写入执行

004AE242  A100104000   moveax,dwordptrds:[004AE24C]      //004AE24C处内存读取
004AE247  A300104000   movdwordptrds:[004AE24C],eax      //004AE24C处内存写入
004AE24C  83C001     addeax,1                 //004AE24C处内存执行
  那么我们应该如何中断在上面几行呢?

  1.当我们对004AE24C下内存访问断点时候可以中断在004AE242也可以中断在004AE247

  2.当我们对004AE24C下内存写入断点时候只能中断在004AE247

  3.当我们对004AE24C下内存访问断点时候能中断在004AE24C

  到这里你可能不明白了为什么内存访问断点能中断在004AE247这句对004AE24C写入而且还能中断在004AE24C执行呢?

  其实很简单我们只要仔细体会下“内存访问”这 4个字含义遍可以知道当我们对004AE24C进行读取时候需要“访问”他吧当我对004AE24C进行写入时候也需要“访问”他吧!!当然我们要执行内存地址004AE24C代码时候也是还是要“访问”他

  所以我们不难得出下面结论:

  1.内存写入中断地方定是也可以用内存访问中断

  2.内存执行地方也可以用内存访问中断

  如果这时你认为那么内存写入岂不是没用了呵呵~那我要告诉你当然不是如果你想快速准确定位到004AE247这时候那么他就大有作用了!

  整理总结下:内存断点不修改改原代码不会像普通断点那样修改代码被校验而导致中断失败;对于区段访问只是区域大了其原理和上面分析 3行代码是

  ii.如何使用内存断点来寻找OEP呢?

  要回答这个问题首先要回答这个问题:壳是如何解压代码

  正如我们知道壳如果要把原来加密或压缩代码运行起来就必须要解压和解密原来代码而这个过程我们难道不能将他看做是对代码段(code段)写入吗?好了解压完毕了我们要从壳代码区段JMP到原来代码段时候难道不正是对代码段(code段)执行吗?

  理清了上面关系就好办了那么如果载入OD后我们直接对code段下内存访问断点时候定会中断在壳对code段写入代码上面就像上面004AE247而如果当他把code段代码全部解压解密完毕了以后JMP到OEP时候我们是不是还可以停在OEP代码上面呢?而且每按下F9都会中断这时code段在执行中哦!

  相信很多人到这里已经明白了为什么在教程中到达了某个时候时候牛人们就叫我们对code段下内存访问断点了吧

  而如果你还要继续问我为什么定要到那个地方才可以下断呢?我难道不可以开始就下断吗?

  正入我上面所说如果你在前面下断很可能壳对code段还没解压完毕呢这时如果你不停按F9你将会看到OD下方不断在提示你“对401000写入中断”“对401002写入中断”“对401004写入中断”.......如果你不介意按F9到他把正个code段写完我除了同情你“F9”以外没什么其他意见!

  那么我们就没有别更快办法了吗?

  有!那就是我们呼的欲出两次内存断点办法

  如何理解两次内存断点呢?

  让我来做个假设吧假设我是个壳作者个EXE文件有code段data段rsrc段.....依次排列在你内存空间中那么我会如何解码呢?呵呵~我比较笨我会先将code段解码然后再将data段解压接着是rsrc段......那么聪明你不难发现只要你在data断或者rsrc段下内存访问断点那么中断时候code段就已经解压完毕了这时我们再对code段下内存反问断点不就可以到达OEP了吗?

  这里注意上面虽然下了两次内存访问断点但是本质是不也是不

  1.对data段下内存访问断点而中断是内存写入中断是断在对对data段解压时这时壳要对data段写数据但是code段已经解压完毕

  2.对code段下内存访问断点而中断是内存执行中断当然就是寻找OEP了

  整理总结下:如果我们知道壳在什么地方对code段解压完毕我们就可以使用内存断点找到OEP如果不知道那么我们就依靠2次内存断点去找如果还不行就用多次内存断点总的明白了原理在多次内存断点其实都从这个过程中我们了解是壳在对区段解码顺序!

  iii.实战

  说了这么多我想大家都越越欲试了吧

  好吧来弄个猛壳如何样:

  注:本节例子有些难度不适合新手练习新手可以跳过这个例子学习等找到合适例子会补充上来

  本节例子下载:unpackme.rar

  这个壳是个hying旧版我们用他来实验下我们内存断点法

  OD载入以后来到这里

0040D000u> 56          pushesi       //这里
0040D001  52          pushedx
0040D002  51          pushecx
0040D003  53          pushebx
0040D004  55          pushebp
0040D005  E815010000     callunpackme.0040D11F
   根据跟过经验我们将先设置3异常以外忽略其他异常SHIFT+F9

  

003725B1  64:89250000000>   mov  fs:[0],esp
003725B8  CC          3
003725B9  90          nop          //到这里
003725BA  8BCD         movecx,ebp
   然后再设置除“除零”异常外忽略其他异常SHIFT+F9

  

00372660  F7F3         divebx        //到这里
00372662  90          nop
  下面是很多单步异常太麻烦我们不管他现在开始用内存断点思路方法(记得将所有异常忽略)

  对code段下内存访问断点希望他已经解压完毕思路方法是按ALT+M键打开内存窗口在.code段按F2设断:

  

  SHIFT+F9执行:

0040D19D  A4          movsptres:[edi],ptrds:[esi]    //还没解完呢
0040D19E  B302        movbl,2
  对data段下内存“写入”断点试试看他是不是要写data段

00372712  F3:A4        repmovsptres:[edi],ptrds:[esi]   //断到这里
00372714  5E          popesi
  下面再对code段下内存访问断点F9

  00372855  8907         movdwordptrds:[edi],eax  ;SHELL32.DragFinish //这里是对IAT加密地方了!!!

00372857  5A          popedx
00372858  0FB642FF      movzxeax,ptrds:[edx-1]
0037285C  03D0         addedx,eax
0037285E  42          incedx
0037285F  83C704       addedi,4
00372862  59          popecx
00372863 ^E2A9        loopd0037280E
00372865 ^E963FFFFFF     jmp003727CD
0037286A  8BB593060000    movesi,dwordptrss:[ebp+693]           //到这里下断F2
  现在如果再对data下访问断点已经是没用了这时应该格外小心

  我们现在就想既然这段是对code解码那么我们就绕过他吧!

  到0037286A下断F2然后清除内存断点!!!!

  F9以后停在这里继续对code下内存访问断点

  看看左下角还在解码哎~真是麻烦!

003728E1  /EB1D        jmp00372900
003728E3  |25FFFFFF7F     andeax,7FFFFFFF
003728E8  |038583060000    addeax,dwordptrss:[ebp+683]
003728EE  |2B858F060000    subeax,dwordptrss:[ebp+68F]
003728F4  |8BDE         movebx,esi
003728F6  |2BD8         subebx,eax
003728F8  |8958FC       movdwordptrds:[eax-4],ebx          //停在这里
003728FB  |83C708       addedi,8
003728FE ^|EBDB        jmp003728DB
00372900  64:FF3530000000   pushdwordptrfs:[30]             //清除内存断点以后到这里下断F9
  又是段解码代码再次使用上面办法手动跳出去

  现在继续对code段下内存访问断点!!F9以后到达这里

004010CC  FFD7         calledi    ;unpackme.004010CE //OEP哦
004010CE  58          popeax
004010CF  83EC44       subesp,44
004010D2  56          pushesi
004010D3  90          nop
004010D4  E8B518F7FF     call0037298E
004010D9  8BF0         movesi,eax
  呵呵~虽然不是我们熟悉OEP但是地址是没错了况且根据我们步骤我可以很肯定说这是code段次“执行”中断!

  所以这就是OEP了

  整理总结下:当我们在寻找OEP时候要多次对code下断“赌”“赌”他解压完毕如果不是就对别段试试~如果跑飞了那就没办法了重来呗~其实说起来要赌是:当data段idata段rsrc段摆在你面前你会好好“珍惜”那个段不过还好上天还会给我们从来机会(ctrl+F2^_^)那么我们会对那个不会跑飞段说3个字----“先断你”如果非要在上面加个次数我希望是“次内存断点就好了”

  vi.下面来讨论下内存断点局限性问题

  是不是什么壳都可以用内存中断啊?

  不是每个都可以些像UPX和ASPACK就不行

  为什么?

  呵呵~follewme!

  情况1.

  我们来看看UPX

  首先壳代码在UPX1段

  这里是他要跳到OEP地方

0040ED4F  /7711      jaNOTEPAD_.0040ED62      
0040ED51  |01C3       addebx,eax
0040ED53  |8B03       moveax,dwordptrds:[ebx]
0040ED55  |86C4       xchgah,al
0040ED57  |C1C010     roleax,10             //在解码
0040ED5A  |86C4       xchgah,al
0040ED5C  |01F0       addeax,esi
0040ED5E  |8903       movdwordptrds:[ebx],eax
0040ED60 ^|EBE2      jmpNOTEPAD_.0040ED44
0040ED62  240F      andal,0F
0040ED64  C1E010     shleax,10
0040ED67  66:8B07     movax,wordptrds:[edi]
0040ED6A  83C702     addedi,2
0040ED6D ^EBE2      jmpNOTEPAD_.0040ED51    //回跳解码
0040ED6F  61        popad
0040ED70 -E95723FFFF   jmpNOTEPAD_.004010CC      //跳到OEP
  我们看到他在对code段解压完毕时候马上就JMP到OEP去了那么我们根本就来不及使用内存断点办法

  你可能说我可以在

  0040ED6F  61        popad//这句下段然后使用啊

  呵呵~~当然可以不过你把花在下内存断点时间多按下几次F8不更好?!

  也就是说当个壳如果他在JMP到OEP前行代码仍在都在对code段解压那么我们就不能再使用这种办法了!

  或者说我们没必要使用内存断点更贴切点!

  情况2.

  对于些在OEP处有stolencode代码

  我们来看看个OEP

0049E2F4u> 55        pushebp               //OEP
0049E2F5  8BEC       movebp,esp
0049E2F7  83C4F4     addesp,-0C
0049E2FA  B8BCE04900   moveax,unpack.0049E0BC
0049E2FF  E8048CF6FF   callunpack.00406F08         //这里
0049E304  A1B8FE4900   moveax,dwordptrds:[49FEB8]
0049E309  50        pusheax
0049E30A  6A00      push0
0049E30C  681F000F00   push0F001F
0049E311  E8E68EF6FF   call<jmp.&kernel32.OpenFileMappingA> //API
0049E316  A360194A00   movdwordptrds:[4A1960],eax
0049E31B  833D60194A0000 cmpdwordptrds:[4A1960],0
  这个软件Software在被PESPIN加壳了以后这些全被偷掉了!

  也就是说壳在模拟OEP代码时候必然会执行

  0049E2FF  E8048CF6FF   callunpack.00406F08 //这

  而这个地方是call向code段如果我们使用内存访问断点那么就停在这个子地方

00406F08  50        pusheax                    //会停在这里
00406F09  6A00      push0
00406F0B  E8F8FEFFFF   call<jmp.&kernel32.GetModuleHandleA>
00406F10  BA04F14900   movedx,unpack.0049F104
00406F15  52        pushedx
  这里既不是处理stolencode地方也不是FOEP地方这就会对我们判断产生误导



  当然你可以alt+F9返回到壳处理stolen地方然后用内存断点或者按几下F8到达FOEP处但试问如果你拿到个未知时候又如何知道应该这么处理呢?

  还有其他些情况留给大家整理总结吧!

  在下砖已抛出各位玉不久矣

  --------------------------------------------------

  3.整理总结

  好了说了很多大家应该对内存断点办法有了全面了解如果了解了内存断点原理就不难明白他使用思路方法不难明白为什么有写壳不能使用内存断点办法其实任何种办法都需要经验积累相信如果大家在回答开篇3个问题已经不难了

  大家可以结合原理再好好体会手动脱壳进阶第 8篇Skvp1.32这篇文章



Tags:  脱壳机 脱壳教程 脱壳软件 脱壳工具

延伸阅读

最新评论

发表评论