• 标 题:研究aspr壳的pre-dip
  • 作 者:lipton
  • 时 间:2004年4月04日 10:00
  • 链 接:http://bbs.pediy.com

一年多前,在汉化新世纪论坛看到Volx关于Aspr壳的pre-dip跟踪和处理的帖子,获益非浅。
汉化新世纪论坛多次被黑,资料也丢失了,实在可惜。
在这里只是把几个帖子内容重复叙述。
何谓pre-dip?我只能说一个大概,就是在程序代码解压后达到OEP之前壳在程序放入壳的地址指针,达到程序后返回壳执行相应的功能。
pre-dip按照分布的位置可分为四个部分,第一个部分有6个Call EAX和一个Call EBX(也有Call [xxxxxx]的形式。
位置在第21个异常(准确位置以堆栈窗出现硬盘指纹为准)
硬盘指纹在我的机子上看到是这样"mIjMiACQQJ8=",每部机子的代码都不一样,但字节长度一样,以“=”结尾。
到达异常后在下方设断点,按Shift+F9跳出异常后按F8单步往下走就能看到如下的结构,每个Aspr壳都有这样的结构,除了内存地址不同其它的结构都是一样的。

011BAA53   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAA58   8B40 0C          MOV EAX,DWORD PTR DS:[EAX+C]
011BAA5B   FFD0             CALL EAX                      <<==pre-dip1
011BAA5D   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAA62   8B40 30          MOV EAX,DWORD PTR DS:[EAX+30]
011BAA65   85C0             TEST EAX,EAX
011BAA67   74 29            JE SHORT 011BAA92
011BAA69   8B15 1CC71B01    MOV EDX,DWORD PTR DS:[11BC71C]
011BAA6F   E8 C8FCFFFF      CALL 011BA73C
011BAA74   68 90551B01      PUSH 11B5590
011BAA79   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAA7E   8B40 30          MOV EAX,DWORD PTR DS:[EAX+30]
011BAA81   FFD0             CALL EAX                     <<==pre-dip2
011BAA83   68 90551B01      PUSH 11B5590                  
011BAA88   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAA8D   8B40 2C          MOV EAX,DWORD PTR DS:[EAX+2C]
011BAA90   FFD0             CALL EAX                      <<==pre-dip3
011BAA92   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAA97   8378 28 00       CMP DWORD PTR DS:[EAX+28],0
011BAA9B   74 0F            JE SHORT 011BAAAC
011BAA9D   68 60561B01      PUSH 11B5660
011BAAA2   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAAA7   8B40 28          MOV EAX,DWORD PTR DS:[EAX+28]
011BAAAA   FFD0             CALL EAX                      <<==pre-dip4
011BAAAC   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAAB1   8378 2C 00       CMP DWORD PTR DS:[EAX+2C],0
011BAAB5   74 0F            JE SHORT 011BAAC6
011BAAB7   68 30561B01      PUSH 11B5630
011BAABC   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAAC1   8B40 2C          MOV EAX,DWORD PTR DS:[EAX+2C]
011BAAC4   FFD0             CALL EAX                     <<==pre-dip5
011BAAC6   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAACB   8378 30 00       CMP DWORD PTR DS:[EAX+30],0
011BAACF   74 0F            JE SHORT 011BAAE0
011BAAD1   68 FC551B01      PUSH 11B55FC
011BAAD6   A1 1CC71B01      MOV EAX,DWORD PTR DS:[11BC71C]
011BAADB   8B40 30          MOV EAX,DWORD PTR DS:[EAX+30]
011BAADE   FFD0             CALL EAX                     <<==pre-dip6
011BAAE0   8B15 C4C51B01    MOV EDX,DWORD PTR DS:[11BC5C4]
................
011BAB43   8B15 1CC71B01    MOV EDX,DWORD PTR DS:[11BC71C]
011BAB49   E8 EEFBFFFF      CALL 011BA73C
011BAB4E   8B1D 1CC71B01    MOV EBX,DWORD PTR DS:[11BC71C]
011BAB54   8B1B             MOV EBX,DWORD PTR DS:[EBX]
011BAB56   FFD3             CALL EBX                     <<==pre-dip7
011BAB58   8D55 C8          LEA EDX,DWORD PTR SS:[EBP-38]
011BAB5B   E8 20C0FEFF      CALL 011A6B80
011BAB60   8B55 C8          MOV EDX,DWORD PTR SS:[EBP-38]
011BAB63   A1 FCC51B01      MOV EAX,DWORD PTR DS:[11BC5FC]
011BAB68   E8 738AFEFF      CALL 011A35E0
011BAB6D   EB 0A            JMP SHORT 011BAB79

跟进Call EAX 后是位置在程序领空,能看到类似的结构
004FE148   55               PUSH EBP
004FE149   8BEC             MOV EBP,ESP
004FE14B   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
004FE14E   A3 D4085200      MOV DWORD PTR DS:[5208D4],EAX <<=看EAX的值指向壳地址。
004FE153   5D               POP EBP
004FE154   C2 0400          RETN 4

EAX的值就是壳的地址指针,越过OEP后会返回到壳地址执行相应的功能。

第一部分有7个pre-dip,有相应的7种功能。
pre-dip1(以在壳的位置排序)
硬盘指纹,越过OEP后会返回到壳检测是否有硬盘指纹,脱壳后没有这个地址,会造成异常。
有部分程序以硬盘指纹来计算注册码。
应对:在程序领空找一个空地,最好是块的最后,填入硬盘指纹,然后把这个地址放入相应的位置。
假设硬盘指纹放在521FF0处,那么5208D4填入F01F5200(注意高低位的顺序)。
pre-dip2
指向壳的一个RET(C3),如果单独使用是简单检测壳是否存在。
应对:在程序领空找一个RET让指针指向此处。
pre-dip3
同pre-dip2
pre-dip4
校验注册码,与硬盘指纹计算后生成一个密匙,在部分壳里,会解压N段代码起到防止脱壳的功能。
应对:越过OEP后对此地址设断点监视运行时是否解压代码,如果解压代码等代码解压完后,dump下这段代码,修补dump.exe相应的位置,并把指针指向程序的一个RET.如果没有解压代码,把指针指向当时的EIP例如上例在5208D4处填入4EE14F00.
pre-dip5
已经注册的程序在执行重要功能时返回壳解密N段关键代码,这是Aspr强悍之处,使用此功能如果没有key很难破解,曾经在001论坛看到zombieys放过一个例子,Awmaw1.55;Awmaw1.6;Awmaw1.81其中Awmaw1.81在不用key的情况下根据Awmaw1.55;Awmaw1.6还原Awmaw1.81的解密代码。
应对:越过OEP后对此地址设断监视,等N段代码解密完成后dump下这段代码修补dump.exe相应的代码,并把相应的指针指向程序的RET,但要注意堆栈值,如果有变必须做相应的调整。
pre-dip6
和pre-dip5是成对出现,功能是对解密代码重新加密。
应对:解密后的代码一般会出现pre-dip6的指针,跟踪加密完成后的堆栈值,然后做相应的处理,CALL RET
或nop掉或调整堆栈指针。如果有pre-dip5;pre-dip6就不必理会pre-dip2;pre-dip3因为地址是相同的。
pre-dip7
这个比较特别,起破坏作用,运行后修复难度加大,具体例子可参考jingulong在001论坛的《Afslock1.60a脱壳》的帖子。

第22个异常中断后是注册名的pre-dip
第23个异常后两个pre-dip第一个是时间计数,第二个是使用次数计数。
第24个异常有两个pre-dip这是生死转折,试用时间和使用次数已过会跳到第一个pre-dip,用工具脱壳往往也会
跳到第一个pre-dip。
另外还有一处隐藏的pre-dip(aspr强悍之处),例如水晶按钮在第22异常后如果是注册版会引发新的异常中断后有一排功能相同的pre-dip,像这种情况除非是能算出key了。

由于水平有限很难表达清楚,不足之处望各位指正。
再次感谢VolX的精彩帖子。