ACProtect Professional 1.3C 主程序脱壳(2)(图)
4. dump
根据脱US UnpackMe的经验,不能在false OEP处dump,此时BSS section中许多数据已经初始化了。最好在第一句(push ebp)就dump。可是那个push ebp离false OEP很远L。
Packer EP的初始化环境:
先看看发出第1个call的壳代码:
可以看到(跟一下可以证实),在call入原程序空间前,最后的异常是div 0。用现在的OllyDbg脚本(跟到737B63),停下后修改异常拦截选项:
试试能否拦截异常找到合适的dump位置。当前OllyScript脚本停下时的环境:
栈中为pushad的结果。
第7次div 0异常时:
注意ebp的值已经入栈了。Pushad的结果,对应寄存器值为:
esp = 12FFC0 (原来为12FFC4)
ebp = 12FFC0 = esp (原来为12FFF0)
看看BSS section:
全为0,就在这里dump。如果需要仔细跟stolen code,也可以从这里入手(可以从脚本停下的第6次div 0异常处理后开始)。
先用4D9DE4为OEP。
用LoadPE查看节表:
先把CODE的Vsize和Rsize加大,以避免修复stolen codes时空间不够。
重新跟到false OEP(4D9E37)。重建输入表。
用了Add new section,会不会有问题(好象有篇脱文里提到过这个)? 先这样处理。
用IDA编译dumped_.exe,结果不错。
现在剩下stolen code和replaced code。
5. 修复stolen code
既然不打算仔细跟,就只有猜了。对执行第1个call以前的stolen code进行猜测,应该是安全的。后面的4次call需要仔细看看。
1) call 406EDC
在IDA中看dumped_.exe的结果:
先执行脚本,停下后只勾选div 0异常。直到73A9AF。经过一番遮遮掩掩的代码:
在call前的寄存器:
堆栈:
call完后,下面的pushad为分界线,标识stolen code的结束。所以到这里的stolen code为(对于不确定的,可以在Packer EP修改寄存器值,到这里核对):
Call完后,pushad前的环境:
2) call 46261C
到这里的stolen code:
从这里开始,不能图省事了。要追出全部的stolen code,必须跟(必须确保上一次pushad和下一次popad时的环境一致,才不会丢代码)。先试直接拦截div 0异常,注意后面是否有popad。如果两次的环境不一致,则必须单步跟L。
另外,追stolen code不是一次完成的,所以有些图中寄存器和堆栈中的数据对不上,不必管它。
3) 0073BC47
4) 0073C558
5) 第1次call 462634
这个函数有2个参数L。
这是最后一次后面存在popad的div 0异常。看看是如何回到原程序的。
在73D872忽略所有异常,对code section下内存访问断点。中间在kernel32中有一次内存访问异常。
最后一次div ebx在73DBE1。单步跟到这里:
73DE38破坏前面代码。
至此修复所有stolen codes,将前面的6部分和fasle OEP的2个call合在一起。
根据脱US UnpackMe的经验,不能在false OEP处dump,此时BSS section中许多数据已经初始化了。最好在第一句(push ebp)就dump。可是那个push ebp离false OEP很远L。
Packer EP的初始化环境:
先看看发出第1个call的壳代码:
可以看到(跟一下可以证实),在call入原程序空间前,最后的异常是div 0。用现在的OllyDbg脚本(跟到737B63),停下后修改异常拦截选项:
试试能否拦截异常找到合适的dump位置。当前OllyScript脚本停下时的环境:
栈中为pushad的结果。
第7次div 0异常时:
注意ebp的值已经入栈了。Pushad的结果,对应寄存器值为:
esp = 12FFC0 (原来为12FFC4)
ebp = 12FFC0 = esp (原来为12FFF0)
看看BSS section:
全为0,就在这里dump。如果需要仔细跟stolen code,也可以从这里入手(可以从脚本停下的第6次div 0异常处理后开始)。
先用4D9DE4为OEP。
用LoadPE查看节表:
先把CODE的Vsize和Rsize加大,以避免修复stolen codes时空间不够。
重新跟到false OEP(4D9E37)。重建输入表。
用了Add new section,会不会有问题(好象有篇脱文里提到过这个)? 先这样处理。
用IDA编译dumped_.exe,结果不错。
现在剩下stolen code和replaced code。
5. 修复stolen code
既然不打算仔细跟,就只有猜了。对执行第1个call以前的stolen code进行猜测,应该是安全的。后面的4次call需要仔细看看。
1) call 406EDC
在IDA中看dumped_.exe的结果:
先执行脚本,停下后只勾选div 0异常。直到73A9AF。经过一番遮遮掩掩的代码:
在call前的寄存器:
堆栈:
call完后,下面的pushad为分界线,标识stolen code的结束。所以到这里的stolen code为(对于不确定的,可以在Packer EP修改寄存器值,到这里核对):
Call完后,pushad前的环境:
2) call 46261C
到这里的stolen code:
从这里开始,不能图省事了。要追出全部的stolen code,必须跟(必须确保上一次pushad和下一次popad时的环境一致,才不会丢代码)。先试直接拦截div 0异常,注意后面是否有popad。如果两次的环境不一致,则必须单步跟L。
另外,追stolen code不是一次完成的,所以有些图中寄存器和堆栈中的数据对不上,不必管它。
3) 0073BC47
4) 0073C558
5) 第1次call 462634
这个函数有2个参数L。
这是最后一次后面存在popad的div 0异常。看看是如何回到原程序的。
在73D872忽略所有异常,对code section下内存访问断点。中间在kernel32中有一次内存访问异常。
最后一次div ebx在73DBE1。单步跟到这里:
73DE38破坏前面代码。
至此修复所有stolen codes,将前面的6部分和fasle OEP的2个call合在一起。