手动脱壳有效手段
不可否认,壳的确是个好东西,很多时候它可以帮你拦截大多数软件分析者的跟踪。
同样,病毒的作者也有同样的感想。因此,为了避免自己辛苦写出来的病毒程序被安全工程师或者同行跟出来,他们可算是想尽了一切办法完善,加强壳的能力。
不过话又说回来,你壳再强大,再复杂,再变态,程序总会在某一时刻到达OEP,也就是真正的入口点。因此,只要你有足够的耐心和了解一些基本的注意点,那么跟到OEP还是不难的。
需要说明的,在我看来判定一个壳难不难脱的标准在于PEID能不能识别。当然,这个标准仅仅是我自己定义的,一般来说这还是符合客观事实。
PEID能够识别的壳,相对都比较的好脱。一般来说简单的壳可以通过ESP定律,F4定律轻松搞定。难的壳大都需要LoadLibrary定律来辅助。如果实在不会百度下就基本有了思路。
就杀毒软件公司的病毒样本分析人员而言,他们很少关注PEID无法探测的壳,也没有太大的把握能够把这些壳脱下来。因此,病毒如果加上这些强壳,那么至少会让安全人士郁闷一些。同时他们也不能把你的病毒细细的跟出来。这点很重要,毕竟知识产权对自己而言是至少无上的!!
很多脱壳的朋友经常会遇到这样一个问题,不停的F8或者F4之后,OD就会显示异常,之后就跳到了NTDLL领空,之后程序就退出了。关于这一点,我并没有深入研究。不过呢,据我的观察:壳作者会故意插入引起异常的代码
比如: mov eax ,0
mov
[eax],888
并且在上面代码前插入SEH异常处理函数。很明显,这是故意添加的,其目的就是故意产生异常,按道理讲,这个异常的出现会导致异常处理函数的调用。如果你使用OD调试的话,此类异常会首先被OD捕获。当然,你可以忽略异常,但是问题来了,如果壳的作者在异常处理函数里添加些有用的代码(比如解压代码),那么的话你OD即使忽略了异常也再也跟不下去了。这关键的关键就是千万别忽略异常,当作为调试器的OD无法处理的异常,系统会继续交给程序来处理。正如我们所知道的,壳的作者已经定义好了异常处理函数。所以,按道理讲,你完全可以F8或者F7跟下去。但是这样做太乱了,太令人心碎了。这也就是为什么很多菜鸟只能放弃这些壳了。
因此有人想出了LoadLibrary定律。为什么会有这个定律呢?
作为壳而言,它肯定会做的事情就是要具有还原节区的功能。那么肯定就必须调用API函数,这些函数必须动态获得,因此LoadLibrary函数肯定就会被调用。对于壳而言,故意添加异常的代码大都出现的刚开始的地方,获得相关API之后才会开始还原节区的动作。还原好了之后才会跳到OEP。一旦程序运行到LoadLibrary,那么至少可以保证跳过了最开始的令人心碎的部分。
现在重点开始研究LoadLibrary定律该如何的使用。首先,我们必须知道,LoadLibrary函数可以直接被调用也会被间接调用。而在壳代码中,它肯定会被直接调用!!说白了,你下完此函数断点后按F9的时候务必关注堆栈窗口的函数返回地址!!并且在第一次调试的时候还要数清楚你按了几次F9后,堆栈窗口的返回地址不再是程序领空内部地址了(在系统领空)。为什么呢?正如我上面所说,壳的代码会直接调用LoadLibrary函数,因此返回地址肯定还是壳的领空(也就是程序领空)。如果说在某个时刻按F9,堆栈中的返回地址变成了系统领空,至少可以判定这次的LoadLibrary调用肯定和壳的正常行为无关,或许这个时候已经走过了OEP了。所以以上我所说的只有一个目的:准确定位到“万事俱备”这一时刻,接下来就开始等着开始还原节区了。
当壳获得了自己所需要的API之后,那么它就可以做还原节区的工作了。你可以按F8走。但是中途有些地方必须要注意。特别是遇到像这样的指令:
Call
eax
(此时eax指向一个系统领空地址)
如果说你不注意,死命的按F8的话,那么你就不知不觉进入了系统领空,像这样的情况,能走出来还算好的,走不出来就郁闷死你。这也就是为什么很多人放弃继续跟的另外一个原因。因此你遇到这些变态壳的时候,一步一步的走,如果遇到诸如上面的指令,那么按F7进去,之后再把堆栈中的返回地址记录下来并在反汇编窗口中下断。这样直接按F9就跳出来了。这样就避免了你在系统领空跳来跳去影响心情。
当然啦,这些壳还有个比较显著的特征就是CALL语句跳转的地方就在附近,因此在壳中遇到CALL语句千万记得养成先按“回车键”的习惯,如果是近跳(程序嵌套现象)经务必F7。如果你F8了,那么后果是严重的。如果是普通的跳,那么F8就行。总之一切要小心。
在壳中,Loopd指令也会经常的出现,记得必要的时候下条件断点 “ecx==1”,这样避免你按的手指发酸。
*************************
另外补充下,壳还有一个重要的特征:当它要还原节区的时候,首先必须先要修改内存属性,毕竟还原节区这个举动是要操作内存的,从而必须要修改相应内存属性为可写,可读。因此,我们可以在virtualprotect函数上下断点。上面我们已经说过,壳的作者会故意插入异常,进而执行异常处理函数内的实用代码,不排除人家会在调用LoadLibrary后面继续插入这样令人恶心的东西。因此下断virtualprotect可以更加多的越过异常。
当然,下断VirtualFree也是很好的方式,因为壳在还原节区的时候总是会申请一段内存作为交换区域。还原操作完成之后,就会用这个函数释放所申请的区域。因此在这个函数下断更加的和谐。
*******************************
读者可以用
PECompact
2.x壳做实验。这个壳很好的表现出以上几乎所有的特征。并且有些版本还会稍微加上一些反调试的功能,比如说调用IsDebugerPersent函数。像这样的情况很容易处理,要么NOP掉这个函数调用,要么就修改跳转。关于这个函数,还请读者熟知其代码细节:
IsDebugerPersent()
{
_asm
{
mov
eax, dword ptr fs:[18]
mov
eax, dword ptr [eax+30]
movzx eax,
byte ptr [eax+2]
retn
}
}
如果读者非得细细跟带有“故意插入异常的壳”的话,你会很容易发现注册异常处理函数的代码,之后找到异常处理函数的入口点。下断吧!
之后慢慢跟下去。
其实网上有很多脱壳的教程,有图有步骤,但是本着知其然知其所以然的精神,笔者还是决定写出这篇文章让读者知道为什么要下这些断点,为什么要有那些操作。当然,笔者在这方面也是菜鸟,有些地方出现错误或者说理解有问题也是难免,还请高手们赐教。谢谢~~~
***********************
反调试:
1,rdtsc指令。
2,
|