前言
恶意代码编写者会使用对抗反汇编技术来延缓或者阻止分析人员分析恶意代码。所以反汇编技术的目的是为了掩盖程序的真实意图。
比如
jmp short near ptr loc_2+1
这个指令看起来没什么,不过结合下文的汇编代码就发现问题了
loc_2:
call near ptr 15FF2A71h
or [ecx],dl
inc eax
这段代码由线性反汇编技术产生,但结果是错误的。因为call指令的跳转地址是无效的
下面是另一段
jmp short loc_3
db 0E8h
loc_3:
push 2Ah
call Sleep
这段指令是由面向代码流的反汇编器产生的。而不是刚才的线性反汇编器。
线性反汇编
线性反汇编策略是遍历一个代码段,一次一条指令的线性反汇编,不偏离。
具体实现可利用反汇编库libdisasm。
恶意代码编写者利用线性反汇编算法的关键方法是植入能够组成多字节指令机器码的数据字节。
例如,机器码0xEB开头,反汇编器将会把后面 的四个字节当作call指令的操作数,这也就是之前第一个例子中的call指令指向无效地址的原因。
面向代码流的反汇编
面向代码流的反汇编算法是一种更先进的反汇编算法,它与线性反汇编的主要不同在于面向代码流的反汇编并不盲目的反汇编整个缓冲区,也不假设代码段中仅包含指令而不包含数据。它会检查每一条指令,建立一个需要反汇编的地址列表。
反汇编器会优先选择分支指令中的false分支或者call指令跳转后的代码进行反汇编。
处理方法
其实面对这样的反汇编代码是比较容易发现的,当我们发现的时候就可以在这一段代码开始的地方按d(ida加载),转换为十六进制数据,然后到正确的地方按c,转换为代码,最后再nop多余的字节,用PatchByte()就可以简单实现了。
滥用结构化异常处理
结构化异常处理提供一种控制流的方法,该方法不能被反汇编器采用,但可以用来欺骗反汇编器。
实现这一功能的代码是
push ExceptionHandler
push fs:[0]
push fs:[0],esp
再反汇编器处理后的代码中,ExceptionHandler可以被替换成一些自定义的地址,而相应的地址处的数据则不会被ida汇编,因为它以为这段代码并不会执行,不过这段代码却是一定会被调用的。
举个例子
这个程序的main()函数没什么问题,不过其中的这段指令有些奇怪,是修改了函数的ebp+4也就是返回地址,改为了0x40148C。
所以我们来到0x40148C观察发现这里有一处反汇编器修改过的指令
还原后是这样
不过这里还有一个SEH异常处理的跳转,跳转到4014C0,我们跟进
发现这段代码才是恶意代码的行为所在,不过却加了一些反汇编器的修改,我们依次将其还原,并把它们分别用nop替代多出来的字节。
当我们修改回原来的代码后就发现这个代码是一个下载器,从目的网址下载文件,不过文件名和网址都是经过sub_401534()函数加密的,加密函数比较简单,每个字符与0xFF异或,解密即可得到。
内容与程序源自《恶意代码分析实战》一书