前言
因为我们的终于目标是编写出针对于这次的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”button,此时会弹出一个对话框:
图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以下的“>>”button进行进一步的查看:
图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的内容(原始病毒文件的附加数据处)。那么就须要我们进行改动,将这个偏移改动为当前文件附加数据的位置,才干够保障程序的正常执行。
小结
这次我们演示了一整套脱壳的操作。涉及侦壳、脱壳、修复导入表以及处理附加数据等问题。因为经过这一系列的操作,文件已是无壳的状态,这就有利于我们进行下一步的分析工作。
而对于这个病毒本体的逆向分析,我会在下一次进行分析。