常见的干扰逆向分析的技术有花指令,反调试,加壳,控制流混淆,双进程保护,虚拟机保护等技术,下面会简单介绍这几种技术并介绍破解的基本思路。
10.3.1花指令
花指令是代码保护中的一种比较简单的技巧。其原理在原始的代码中插入一段无用的或者能够干扰反汇编引擎的代码,这段代码本省没有任何功能性作用,只是一种扰乱代码分析的手段。
1.基本思路
花指令主要是影响静态分析,在IDA中表现为一些指令无法识别,导致某些函数未能识别,从而无法对这些函数进行反汇编。在IDA中手动将花指令patch成nop空指令,可以去除花指令。如果二进制程序中的花指令较多,那么可以通过分析花指令的特定模式,编写IDAPython脚本对花指令进行自动化搜索和patch。
2。实列分析
有IDA打开程序,发现加入了花指令,可以看出,在0x4010dd处插入了两个无用的字节,影响了IDA的反汇编,将这两个无用的字节修改为nop指令,可以去除该花指令,如图:
d转换为数据:
进一步分析这个程序,可以得到花指令的指令模式,主要是在某些特定的指令序列之后插入一至两个无用的字节。通过IDA脚本自动去除花指令的代码如下:
from idaapi import *
from idc import *
from idautils import *
start_ea = 0x401000
patterns = [('73 02', 2), ('EB 03', 1), ('72 03 73 01', 1), ('74 03 75 01', 1), ('7E 03 7F 01', 1), ('74 04 75 02', 2)]
for pattern in patterns:
ea = start_ea
while True:
ea = FindBinary(ea, SEARCH_DOWN, pattern[0])
if ea == idaapi.BADADDR:
break
ea += len(pattern[0].replace(' ', ''))/2
for i in range(pattern[1]):
PatchByte(ea+i, 0x90)
MakeCode(ea+i)
不清楚,这是别人写到,后面学了发教程。
10.3.2反调试
反调试技术是指在程序运行过程中探测其是否处于被调试状态,如果发现其正在被调试,则使其无法正常运行。Windows下的反调试方法很多,网上也有很多文章对其进行了总结,而且在Windows下通过OD的StringOD插件可以过滤掉大多数的反调试方法。所以,这里主要针对Linux下一些常见的反调试方法进行介绍。
1.Linux下常见的反调试方法
(1)利用ptrace
Linux下的调试主要是通过ptrace系统调用来实现的。一个进程只能被一个程序跟踪,所以如果程序被跟踪之后再来调用ptrace(PTRACE_TRACEM)自然是不会成功的:
非调试状态下:
我们都知道可以通过/proc/ p i d / 来 获 取 指 定 进 程 的 信 息 , 例 如 内 存 映 射 、 C P U 绑 定 信 息 等 等 。 如 果 某 个 进 程 想 要 获 取 本 进 程 的 系 统 信 息 , 就 可 以 通 过 进 程 的 p i d 来 访 问 / p r o c / pid/来获取指定进程的信息,例如内存映射、CPU绑定信息等等。如果某个进程想要获取本进程的系统信息,就可以通过进程的pid来访问/proc/ pid/来获取指定进程的信息,例如内存映射、CPU绑定信息等等。如果某个进程想要获取本进程的系统信息,就可以通过进程的pid来访问/proc/pid/目录。但是这个方法还需要获取进程pid,在fork、daemon等情况下pid还可能发生变化。为了更方便的获取本进程的信息,linux提供了/proc/self/目录,这个目录比较独特,不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/。进程可以通过访问/proc/self/目录来获取自己的系统信息,而不用每次都获取pid。
调试状态下:
(3)父进程检测
通过getppid系统调用获取得到程序的父进程,如果父进程是gdb、strace或者Itrace、
则可以证明程序正在被调用。
2.基本思路
针对这些反调试方法,常用的方法就是定位到反调试代码,然后对进程进行patch(修补),在不影响程序正常功能的情况下,跳过对调试器的检测代码。
3.实例分析
本节所经历的实例来自defcamp quals 2015的r100.bin。直接运行程序时,程序将会提示输入密码。但是在dbg中运行时,不会有任何输出,猜测程序有反调试.
在.ini_array段,调用了sub_4007A8:
__int64 sub_4007A8()
{
__int64 result; // rax
if ( (unsigned int)getenv("LD_PRELOAD") )
{
while ( 1 )
;
}
result = ptrace(0, 0LL, 0LL, 0LL);
if ( result < 0 )
{
while ( 1 )
;
}
return result;
}
可以看到有对调试器的检测:
对代码进行patch可以跳过检测;(即:删除函数或更改判断等)
10.3.3 加壳
加壳是指在二进制程序中植入一段代码,在运行的时候优先取的程序的控制权,这段代码会在执行的过程中对原始的指令进行解密还原,之后再将控制权交还给原始代码,执行原来的代码。
经加过壳的程序,其真正的代码时加密存放在二进制文件中的,只有在执行时才从内存中解密还原出来,因此没法对加壳后的程序直接进行静态分析,所以首先需要进行软件脱壳
1.基本思路
在CTF出现的带壳程序通常为已知的壳,因此大多数可以通过使用专门工具或者脚本进行脱壳。比如upx壳,可以通过"upx -d"命令进行脱壳。
2.实列分析
本节所列举的实例来自2014 ISCC的一个逆向题。首先使用工具PEID进行查询,发现是ASProtect壳:
下载ASProtect 1.2~1.3x,可以找到对应的脱壳脚本,在OD中通过插件ODbfScript运行该脚本。
然后,使用(LordPE、Import REC)或者ODdump插件将内存doump下来。
10.3.4 控制流混淆
对于控制流混淆的程序,没办法直接分析,也无法进行反编译,而调试器调试也会陷入控制流的跳转混乱中。
什么是控制流:就是执行流程。控制流平坦化相关题目
1.基本思路
对于控制流混淆的程序,通常采用Trace的方法。通过Trace工具记录下程序运行的所有指令,然后在运行这些指令的基础上进行数据流分析。常用的Trace方法即可以使用Ptrace的单步执行记录下运行的每一条指令地址。也可以使用动态二进制插桩工具,如Pin来进行记录。