目录
笔记
反汇编技术:分为线性反汇编器和面向代码流的反汇编器,对于同一段字节集合。有时候反汇编出来的代码并不相同。
对抗反汇编技术是基于反汇编算法的天生漏洞而产生的
线性反汇编:用已经反汇编的指令大小来决定下一个要反汇编的字节,而不考虑代码流的控制指令。
而且PE的代码段还有一些数据。不能有效区分代码和数据
面向代码流的反汇编:检查每一条指令,然后建立一个需要反汇编的地址列表
对抗反汇编技术:利用反汇编器选择算法和假设算法的漏洞
相同目标的跳转指令:连续两个条件跳转指向一同一个目的地址,比如jz和jnz的结合,实际就是jmp
jz
jnz
call(数据)
当遇到jnz时会反汇编这个指令的false分支,与true分支产生冲突
(显示16进制字节Options->>General->>Number of Opcode Bytes)
固定条件的跳转指令:跳转条件总是相同的一条指令,比如xor eax ,eax然后jz。实际就是jmp
xor eax ,eax
jz
jmp (数据)
当遇到jz时会反汇编这个指令的false分支,与true分支产生冲突
无效的反汇编指令:EB FF C0 48
字节FF同时作为两条实际运行指令的一部分
import idaapi
idaapi.CompileLine('static n_key() {RunPythonStatement("nopIt()");}')
AddHotkey("Alt-N","n_key")
def nopIt():
start = ScreenEA()
end = NextHead(start)
for ea in range(start,end):
PatchByte(ea,0x90)
Jump(end)
Refresh()
IDApython对指令进行NOP
混淆控制流图:
函数指针问题:使用函数指针可以大大降低反汇编器自动推导出程序流的信息量
mov [ebp+var_4],offset sub_4011C0
call [ebp+var_4] 可以检测出来,一个函数偏移量加载到堆栈中,可以探测到函数的初始化引用
call [ebp+var_4] 检测不出来,函数的原型信息丢失
IDA中添加代码的交叉引用:AddCodeXref函数,fl_CF-->普通call fl_JF-->跳转
AddCodeXref(交叉引用来源的位置,交叉引用指向的位置,流的类型)
滥用返回指针:retn指令等同于jmp指令加pop指令。
不能显示代码中任何要跳转的交叉引用目标,另一个显著的结果是反汇编器会提前结束这个函数
滥用结构化异常处理:SEH链是一个函数列表,设计的目的是处理线程中的异常(访问无效内存区域,除0操作)。列表中的每个函数有两种选择,一种自己处理异常,另一种把异常传递到列表的下一个函数。
为了查找这个SEH链,操作系统先检查FS段寄存器(包含一个段选择子)-----》得到线程环境块(TEB)-----》TEB的第一个数据结构是线程信息块TIB。--------》TIB中的第一个元素就是SEH链的指针。
mov eax,(offset loc_40106B+1)
add eax,14h
push eax
push large dword ptr fs:0
mov large dword ptr fs:0,esp
xor ecx,ecx
div ecx
eax+14h,构造401080函数指针,通过div ecx的异常操作(除0)。调用了401080的异常代码
栈帧问题:
实验
Lab15-1
在main位置,可以看到有红底的部分和交叉引用的部分都是红色的,说明这里是错误的。其中call BB4C55A0这显然不是一个合法地址。这里利用了插入流氓E8来人反汇编器汇编出了call的指令。代码采用了“固定条件的跳转指令”来对抗反汇编技术。
先把401010地方转化为数据
再把401011地方转化为代码。紧跟着这段代码的指令没有对齐,那么为了对齐指令,从0x00401014开始,遇到的所有db指令都按下键盘上的“c”键,转换成代码,直至一条指令紧挨着另一条指令,它们中间没有数据字节
然后选中main函数的所有代码,按下键盘的P键。让IDA将这部分的代码变成一个函数,这样就可以使用图形的模式来分析这段代码了
Lab15-2
test esp,esp。对于一个正常的程序,ESP寄存器的值一定是非0的
转化
第二处xor eax,eax
第三处,把401215的地方NOP掉
可以看到,这里的jz和jnz都跳转到同一个地方。那么我们这里依旧要采用之前的方法来将0x0040126D位置处的语句进行转换:
因为这里出现的jz跳转是向上进行的(之前的都是向下跳转)。分析跳转的目的地,它会跳到mov语句中间。
这里所出现的对抗反汇编技术与之前的有些不同,因为这里出现的jz跳转是向上进行的(之前的都是向下跳转)。分析跳转的目的地,它会跳到mov语句中间。
这里出现了一处名为sub_401386的函数调用。双击进入这个call来分析一下,可以发现程序在栈上创建了一个字符串:http://www.practicalmalwareanalysis.com/bamboo.html。并且程序还调用InternetOpenUrlA来试图访问这个网站
InternetOpen函数的第一个参数就是User-Agent字符串,这里它被保存在了edx中。而edx的内容是取决于szAgent的。
调用了gethostname来填充szAgent,也就是使用本地计算机的名称来填充szAgent。
Lab15-3
Imports窗口中调用了CreateToolhelp32Snapshot这个API函数,用于给当前的进程拍一个快照,接下来又使用了Process32First以及Process32Next来不断地列举当前的进程。还有URLDownloadToFile和WinExec
0x400000赋值给eax,然后将eax与0x148C进行或运算。结果其实就是0x40148C,保存在eax中。之后将这个值保存进ebp+4的地址位置。这个地址是返回地址,那么这段程序的目的就是要将返回地址
覆盖为``0x0040148C。这样一来,当main函数执行完后,就会跳转到0x0040148C的位置继续执行。
修改这里的对抗反汇编
这里利用对抗反汇编技术是SEH链,因为它上面的五行语句创建了一个异常处理例程
,并且在0x004014AC的位置触发了一个除零异常
(因为经过对ecx自身的异或运算,会使它的值变为0,接下来用它作为除数)。而异常处理的地址是4014C0。
4014C0
把这里的数据转化为code ,目的是从异常处理链中摘除异常处理的例程,并从栈中删除了记录。
并修正代码
可以发现这里调用了URLDownloadToFileA这个函数。这个函数的第二和第三个参数分别是URL和文件名。,这两个参数都作为了sub_401534的参数,所以可以推测,sub_401534就是用于解密的函数
sub_401534
待解密的字符与0x0FF进行异或运算
第三处对抗反汇编位置