标签:
本系列教程版权归“i春秋”所有,转载请标明出处。
本文配套视频教程,请访问“i春秋”(www.ichunqiu.com)。
由于我们的最终目标是编写出针对于这次的U盘病毒的专杀工具,而通过上次的分析我们知道,病毒有可能在不同的计算机中会以不同的名称进行显示,如果真是如此,那么就有必要在此分析出病毒的命名规律等特征,然后再进行查杀。
按照常规,首先是对病毒进行查壳的工作,这里我所使用的是“小生我怕怕”版的PEiD,之所以用这个版本,是因为经过我的实际测试,常规的PEiD或者说其它的查壳工具都难以很好地对这次的程序所加的壳进行识别:
图1 使用PEiD进行查壳
这里请大家注意的是,将程序载入“小生我怕怕”版的PEiD后,是检测不出什么的,需要单击右下角的“->”,然后选择“核心扫描”才可以。
在上图中可以发现,程序所加的壳的名称为“UpolyXv0.5”,并且还有附加数据(Overlay)。对于“UpolyX v0.5”来说,经过在网上对于这款壳的检索发现,如果PEiD认为某个程序加了“UpolyX v0.5”的壳,那么误报的可能性是很大的,有可能是加了多重壳,有可能是UPX壳并加了混淆的效果。网上说法很多,但尽管如此,大家对于这个问题的共识是,使用“ESP定律”进行脱壳,那么基本都是能够成功脱壳的。另外,由于脱壳后的程序是不包含有附加数据的,因此脱壳后还需要将原始程序的附加数据再添加回去,并进行一定的处理,从而保持病毒程序的完整性。因此接下来就需要解决这两个问题。
根据“ESP定律”就能够实现我们这次的病毒的脱壳工作。其实“ESP定律”所依据的是堆栈平衡原理,利用这个思想,就可以脱掉非常多的不同种类的壳了。事实上,“ESP定律”是一套严格的流程,我们只要依据这个步骤,就能够实现脱壳。
首先我们用OD载入病毒程序:
图2
注意这里选择“否”,然后按下F8单步运行,这时可以发现,在寄存器窗口中的ESP以及EIP都变成了红色:
图3
说明经过上一步的操作,这两个寄存器中的值发生了变化。那么现在就在ESP寄存器上单击鼠标右键,选择“数据窗口中跟随”:
图4
然后在数据窗口中的ESP的位置下一个硬件断点:
图5
然后按下F9执行程序,就会在我们下断点的位置停下来:
图6
然后不断按下F8单步执行,就会来到0x00403C81的位置:
图7 找到程序入口点
可以发现,这里就是程序的入口点。可能大家会疑惑,为什么这里是程序的入口点,事实上,对于VC++编写的程序来说,它们入口点的反汇编代码是基本一致的,当我们接触得多了,自然而然也就认识了。那么下一步先取消硬件断点。可以在“调试”菜单下选择“硬件断点”,然后将我们刚才下的断点删除掉。之后在我们所找到的程序入口位置单击鼠标右键,选择“Dump debugged process”:
图8
在上图中可以看到“RebuildImport”这一项。因为壳往往会修改导入表,因此很多时候在将壳脱掉后,还需要修复导入表,否则程序是不能正常运行的。对于有些壳来说,我们使用OD的这个插件进行修复就可以,也就是说保持打钩的状态,再提取。但是有些时候这款插件并不能够很好地实现导入表的修复,所以这时我们一般使用ImportREC这款软件进行导入表的修复。
对于我们这次的病毒样本来说,似乎无论是采用哪种修复方式,都没有显著的不同。所以这里我会演示这两种方法,有兴趣的朋友可以对比它们的不同。首先是利用插件进行修复,也就是保持打钩的状态,然后单击“Dump”,给提取出来的文件起一个名字,这里我取的是“unpacked_1.exe”。然后再重新提取,将“Rebuild Import”前面的钩去掉,再进行提取,命名为“unpacked_2.exe”。注意这里需要记住上图中的Modify中的内容,是新的入口点,这里是“3C81”,它是一个偏移地址。然后打开ImportREC,注意OD不要关闭。在下拉菜单中选择脱壳前的程序:
图9
然后我们输入新的OEP,也就是“3C81”:
图10
然后单击“IAT AutoSearch”按钮,此时会弹出一个对话框:
图11
这个对话框告诉我们已经找到了一些东西,并且说如果查找错误,那么可以将RVA以及Size进行相应的修改。这里我们可以点击确定。既然程序已经提示我们,查找可能不准确,那么现在可以在OD中观察一下,看看是不是找到了我们想要的内容。回到OD,在数据窗口中跳转到0x407000的位置,也就是上图中的RVA与0x400000这个基址相加的结果:
图12
因为有些壳会在这个地址区域做手脚,因此我们应当浏览一下这个位置上下有没有一些可疑的内容。这里一切都是正常的,说明这个RVA没什么问题。然后回到ImportREC,点击“Get Imports”。如果说有不合法的结果,可以点击“Show Invalid”查看具体的细节。这次没有不合法的结果,那么就点击“Fix Dump”,并将它附加在“unpacked_2.exe”上面,此时程序会帮我们生成一个名为“unpacked_2_.exe”的文件,就是修复了导入表的文件。至此,我们的脱壳工作就基本完成了。此时再用PEiD查壳:
图13
可以看到此时PEiD已经检测到它是由VC++编写的了。或者再单击PEiD下面的“>>”按钮进行进一步的查看:
图14 利用PEiD进行进一步的检测
可以发现,现在我们的病毒样本确实是无壳的。
我们尝试双击运行一下这个病毒程序:
图15 提示文件中有非法数据
这里提示出错,说明我们还需要对附加数据进行处理。这里首先可以看一下原始病毒样本的附加数据。这里还需要利用PEiD,载入原始样本,查看一下区段表:
图16 查找病毒样本的附加数据
附加数据会放在最后一个区段的后面,对于这个程序来说,最后一个区段是.rsrc,其偏移是0x14000,大小为0x5000,那么附加数据的偏移就是0x14000加上0x5000,也就是0x19000的位置。利用WinHex,载入原始样本,跳到0x19000的位置:
图17
这个程序的附加数据很多,从0x19000一直到文件的最后。目前尚不知道病毒利用附加数据做了什么,我们必须要将附加数据添加到脱壳后的样本中。在WinHex的“编辑”菜单下选择“定义区块”,然后将需要提取的区块定义为“文件中间”的“19000”一直到“文件结尾”:
图18 定义区块
那么这段区块就被选中了,通过复制粘贴,将其添加到脱壳后的病毒样本的后面,就完成了附加数据的添加。
那么现在还有一个问题,那就是我们这样直接把附加数据拷贝到脱了壳的程序最后,程序能够有效地识别吗?我们不妨先看一下脱了壳之后的程序的反汇编代码。这里我使用IDA Pro来载入脱壳后的程序。首先是一个CreateFile函数:
图19 调用CreateFile函数
这里它会将病毒文件自身打开,然后将文件句柄赋给edi寄存器,如果文件能够正常打开,那么下面就调用SetFilePointer函数:
图20 调用SetFilePointer函数
一般来说,如果一个程序需要利用自身的附加数据,那么一般都会在文件打开之后,利用SetFilePointer这个函数来移动文件指针,使其指向想要读取的数据位置。对于这次的程序而言,首先可以看一下上图中的dwMoveMethod这个参数,这里是2,它代表的是FILE_END,也就是说,会从文件最后的位置进行数据的读取。 lpDistanceToMoveHigh表示要移动的距离,这是高32位,这里的值为0,我们就可以先不管它。lDistanceToMove表示低32位要移动的距离,这里是0xFFFFFFF8,它是一个负数,表示向前移动,也就是向前移动8个字节。
总结来说,由于这个程序本身在获取附加数据时,不论程序的大小如何变化,它都是从文件的最后开始读取的也就是说,只要文件后面的附加数据没有问题,那么这个病毒样本就能够正确获取附加数据的信息,因此这里不存在附加数据不能读取的问题。那么什么情况才需要我们注意呢,那就是如果程序的SetFilePointer是从文件的开始,读取偏移位置为0x19000的内容(原始病毒文件的附加数据处),那么就需要我们进行修改,将这个偏移修改为当前文件附加数据的位置,才能够保障程序的正常运行。
这次我们演示了一整套脱壳的操作,涉及侦壳、脱壳、修复导入表以及处理附加数据等问题。由于经过这一系列的操作,文件已是无壳的状态,这就有利于我们进行下一步的分析工作。而对于这个病毒本体的逆向分析,我会在下一次进行分析。
标签:
原文地址:http://blog.csdn.net/ioio_jy/article/details/51198399