原文:https://www.securityartwork.es/2018/04/09/reversing-of-malware-network-protocols-with-angr/

在分析恶意二进制程序时,最困难的任务之一就是找出程序提供的所有功能。此外,如果程序具体执行哪些功能完全由攻击者通过其控制中心进行遥控的话,局面就会变得更加复杂。由于某些原因,很多时候根本就无法进行全面的动态分析,例如恶意软件基础架构的崩溃或样本的隔离导致恶意软件无法与C&C进行通信,等等。在这些情况下,攻击者的服务器与样本之间的交互分析通常非常耗时,因为我们必须创建一个伪装的服务器或不断修补/欺骗样本代码,才能考察所有不同的执行路径。根据所分析代码的大小和复杂程度或分析目标的不同,这项任务的难度和广度也会随着时间的推移而不断发生变化。

在本文中,我们以一个虚构的RAT为例,讲解如何找出它的各种功能。其中,这个RAT会根据C&C面板的命令来执行某些功能。我们的目标是创建一个模拟攻击者的服务器。为此,我们必须了解服务器和安装在受害者设备上的恶意软件之间的通信协议。

在本文中,我们不会使用常见的反汇编和调试工具来分析样本的内部工作机制,而是借助于一个新工具,即Angr来完成部分分析工作。Angr是一个分析二进制文件的工作环境,可用来对代码进行静态和动态符号分析。这个工具的用法也很丰富,具体请参考其网站的介绍,同时,该网站也提供了很多具体的分析示例。在本例的分支分析中,我们将重点关注符号执行,即通过分析程序,以确定出执行代码的各个分支时必须满足哪些分支条件。

由于该工具非常复杂,为了便于理解,请参考下列链接,它对用于演示其用法的代码进行了简要的分析:

https://gist.github.com/halos/15d48a46556645ae7ff2ecb3dfc95d73

上面的代码模拟了一个通过函数call_home接收C&C命令的RAT。在该代码中,首先会初始化全局变量c2_resp的值,该变量用于存放假想的C&C命令。然后,执行exec_order函数,而该函数的作用,就是根据保存在c2_resp结构中的信息来执行相应的操作。

该结构不同字段的取值,已经在代码开头部分以常量的形式给出了相应的定义。其中,包含了某些随机值,目的是扰乱视听,提高恶意软件分析人员的工作难度。

但是,我们在实验室中分析恶意软件时,手头上通常没有对应的源代码,只有编译后的二进制文件。如果我们编译前面的C代码,得到的exec_order函数如下所示:

通过进一步的分析,可以将汇编代码组织成更容易理解的形式:

如图所示,经过适当的组织,代码已经展现出更容易理解的结构,但它仍然还是一些代码,由于比较冗长,分析起来还是比较困难,例如当我们深入了解函数时,将会面对:

然而,在平常的恶意软件中,程序的逻辑通常没有这么清晰,这倒不是因为恶意软件作者不知道如何编程,而是因为他们总是设法提高恶意软件的分析难度。

为了用Angr来研究这个样本,我需要知道4个内存地址的值,以告诉该工具:

  1. 目标代码是从哪里开始的?
  2. 它在哪里结束?
  3. 到底要抵达哪些位置?
  4. 可以使用哪些变量?

其中,前两个问题用于为Angr划定待考察的所有路径所在的范围,这样就可以避免将时间浪费在对本研究无用的路径上了。对于第三个问题,用于确定那些需要仔细研究的内存区域的起始地址,然后将研究的重点放在这些区域就行了。第四个问题涉及存放服务器数据的“缓冲区”,对于该恶意软件来说,当缓冲区的取不同的值时,它将去往第三个问题对应的不同区域。

从第一幅图可以看出,待分析的函数的起始地址为0x0804844d,因此,该地址将会赋值给常量START_ADDR。此外,待寻找的地址将存放到FIND_ADDRS列表中。例如,“push str.Creando_file:__ s”指令的地址0x8048483已经添加至该表中,该指令来自创建文件的执行分支(地址为0x804847b的内存块)。

对于其他代码,我们不做深入介绍,只需注意的是,这里用C代码编译得到的可执行文件a.out来初始化分析器,从而为其传递起始地址。此外,这里也标出了服务器的响应缓冲区(BUFF_ADDR),这段内存将用于工作变量,同时,我也标出了从哪里开始停止分析。最后,让它探索所有带有这些标识的代码,并以一种易于理解的方式输出相应的结果:

出现的第一个条目的意思是说,如果C&C想要给这个bot发布命令,它必须删除一个文件(在地址0x80485050处执行该操作),这时会发送一个字节内容为“00 E9 BB 64 D4 D4 01 1F AF 78 09 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00”的“缓冲区”。

接下来的输出结果,解释了如何通过BUFF_ADDR处的内容抵达该地址。应该注意的是,Angr是在比特级别上工作的,因此表示只有20个字节的缓冲区的时候,只用高位索引就行了(‘c2_resp_0_160[159:128]’)。

第一个约束条件表明,第四个DWORD必须包含值0x64bbe900(T_FILESYSTEM,可以从C源代码中看出来)。但是,第三个字节的内容有三个约束条件:它不可以是0xaff80c17和0xc6e6ef6b,并且还必须包含值0x1f01d4d4。不难看出,这里只要有第三个约束条件就足够了,但是,之所以提出三个约束条件,自然有其道理:在模拟执行时,Angr必须避免进入某些分支,所以第三个字节不得出现使其进入条件分支的值。如果我们查看相应的C源代码就会发现,对应于‘fs_order’字段的第三个字节,首先会与常量FSO_CREATE(第55行)和FSO_WRITE(第67行)进行比较,当它与常量FSO_DELETE(第71行)相等的时候,就会进入删除分支。

这些信息能够帮助我们理解通信协议,一旦了解了该协议,我们就可以进一步获得新IOC,搭建伪装成攻击者的服务器,实时修改示例缓冲区来直接了解某些功能,等等。

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖