本次实验我们会分析一个特别准备好的二进制文件(非恶意文件),但是里面使用了各种反-反汇编技术
首先使用IDA打开antidisasm.exe:
你可以看到这里有一组函数调用,每一个函数使用了不同的反反汇编技术,并把返回值保存在eax寄存器。本次任务是通过静态分析找出每个函数的返回值是什么?
首先进入到0x40101A函数
看上去IDA并没有识别出这是一个函数,而且这个函数看上去也没有返回值,因为在CALL EAX指令后面有一些垃圾指令,而loc_401045标签位置是下一个函数的开始。
注意 在loc_40101A开始的地方有一个奇怪的call( call $+5).
这个有趣的CALL的调用地址是下一条指令(0x401022)。它这样调用的目的是为了把返回地址(0x401022)PUSH到栈上,然后通过执行POP EAX指令把刚才的地址加载到EAX。
然后EAX+10被加10后,CALL向了这个新的EAX的值。
现在你知道EAX的值是0x401032(0x401022+0x10)。不幸的是,这个地址的位置是垃圾代码中间的位置,并且看上去这个地址的位置并没有指令。
很明显这些垃圾代码是因为反汇编引擎解析某些指令时出现了错位导致的。因为在IDA解析CALL EAX这条指令,IDA并不知道它CALL的地址是多少,所以尝试反汇编CALL EAX的下一条指令。
要修复这个问题,首先选中所有的垃圾代码,然后右键选择undefined(或者按U键):
下一步,选中0x401032位置的第一个字节,按下C键把这个位置的字节转换成代码。可以看到CALL EAX指令后面出现了一个字符串”Fintastic!”。
现在代码比刚才清晰多了,你可以看到loc_40101A函数的返回值是0x1337
总结一下,在这个函数中学到了两种反反汇编技术,第一这里有个间接调用到动态计算的地址。IDA不知道这个被调用的地址是多少,因此它尝试解析这个CALL后面在行内嵌入的字符串(第二种反反汇编技术)。最终导致解析出了一些垃圾指令,而不是一个有效的汇编指令。
本次我们将分析位于loc_401045的函数。
第一眼看上去尽管IDA并没有识别出这里的代码是一个正常的函数,但是这里有一个经典的函数开始和结束retn指令。你也可以高亮EAX寄存器来找到它在哪里被赋值的。
看上去EAX第一次被赋值成了0x11EB,然后增加了0x1000。即使如此,我们应该把注意力放在跳转指令(jz),jz看上去是跳转到了另一条汇编指令的中间位置。同样注意到这里有个有条红色交叉引用,看上去这里貌似出现了什么问题。
在分析jz将要跳转到哪里之前,先来看看什么条件它才会跳转。最后一条指令导致零标志位ZF被置1的指令是jz跳转指令前面的XOR EAX EAX,它会清空EAX寄存器,并设置ZF标志为1。这表示跳转一定会被执行。
由于跳转到了一条汇编指令中间,选中这条指令并把它转换成数据(使用Undefine 或 按U键)。
IDA可能会转换比你预期等多的代码,但没关系,因为你知道jz跳转的目标地址是0x40104B,原始的jz指令位于0x401050。
现在选中0x40104B处的一字节,按下C转换成代码,同样操作来转换jz指令的位置,0x401050。做完这些操作后,你应该能看到类似下面这样的代码:
这表示在PUSH指令中间隐藏了另一个跳转指令jmp。
正如你所见,这条被隐藏的跳转指令的目的地址是0x40105E(另一条汇编指令0x40105D的中间位置)。但是这次看上去是一个正常的汇编错位解析指令。
为了继续进行,把0x40105D转换成数据,然后把0x40105E位置转成代码,转换完成后,你看到的代码应该是这个样子:
现在你可以清楚的看到返回值被设置成了0x4096。注意在返回指令retn后面的这几个垃圾字节,是曾经被用来阻止IDA反汇编EAX被赋值这条指令的。
下面截图展示了在没有做任何修改之前,这个函数的执行流程:
总结一下通过这个函数你学习到的一些反-反汇编技术。最明显的一个就是跳转到另一条指令中间。在这种情况下PUSH指令被用来隐藏另一个跳转指令。你还看到把jz条件跳转变成了无条件跳转,以及一些垃圾字节来阻止IDA反汇编。
下一个要分析的函数是sub_401065。但是这次IDA把它识别成一个正常的函数了。
可以看到EAX开始被清空了,然后调用了sub_40107D函数(传入参数0x1000),最终EAX又增加了0x1000。问题是不知道sub_40107D函数的返回值EAX有没有被修改。
来看一下sub_40107D函数:
看上去这个函数做的唯一一件事就是把参数0x1000赋值给了EAX,然后又加了0x1000,当这个函数返回时EAX应该是0x2000。难道sub_401065函数的返回值是0x3000(0x2000+0x1000)?
正如你所怀疑,并不是那么简单。来看一下sub_40107D返回前发生了什么:
首先把第一个参数的地址传给了EDX,然后把EDX减去4。还知道现在EDX保存的指针指向哪里么?看一下堆栈的结构:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!