译者:WisFree
预估稿费:160RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
介绍
在我们之前针对64位CCleaner的分析文章中,我们跟大家介绍了关于攻击者如何修改一个合法可执行程序(赛门铁克产品)的方法。攻击者所修改的文件名为EFACli64.dll,修改过程发生在运行时代码之中,更准确地说,攻击者修改的是__security_init_cookie()函数。攻击者修改了该函数中最后一个指令并成功控制程序跳转到了恶意代码之上。但是,著名的反汇编工具IDA Pro却没办法正常显示出代码的修改情况,我们在本文中会跟大家介绍这部分信息。最后,我们还会给大家介绍如何来识别这种恶意形式的代码修改操作,以及相应的限制措施。
IDA Pro与修改后的运行时代码
在我们的对修改后的可执行程序的分析过程中,我们在发现IDA Pro在显示修改后的运行时代码(已编译版本)遇到了一些困难,因为IDA Pro无法使用可视化视图正确地显示已编译版本的运行时代码:
我们可以从上图中看到,最后一条指令为“pop rdi”。如果我们切换到文本视图的话,我们就可以立刻看到,最后一条指令其实应该是“JMP”(跳转到恶意代码):
我们在对开源反汇编工具Radare2的源代码进行了检查和分析之后,我们发现这个函数的结尾确实是有一个jmp指令:
得到了这些信息之后,我们就开始思考了:为什么IDA Pro没有给我们显示这最后一条指令(这是最重要的一条指令)呢?
由于我们所用的这款软件并不是一款开源软件,因此我们就无法直接去查看程序源代码了。但我们可以假设IDA Pro使用了pdata数据域来获取从开始到结束的运行时函数,我们待会儿会在下一章节对这部分内容进行介绍。
那么第二个问题就来了:攻击者难道是故意利用这种机制来干扰安全研究人员的分析的吗?攻击者是运气比较好碰巧遇到了这个功能,还是说他们就是专门利用这一技巧来在IDA Pro中隐藏他们的跳转命令呢?我们现在也无法百分之百地下定论…
PDATA数据域
微软对pdata数据域的描述和介绍可以参考这篇文章。这个数据域中包含一个存储了函数条目的数组,这些函数均是用来处理程序异常的。在我们的测试环境中,pdata数据域中包含以下数据结构:
+0x000: Begin Address: The RVA of the corresponding function.
+0x004: End Address: The RVA of the end of the function.
+0x008: Unwind Information: The RVA of the unwind information.
下面给出的是与我们的__security_init_cookie()函数有关的数据:
+0x000: 0000F620 -> RVA of the beginning of __security_init_cookie()
+0x004: 0000F6D3 -> RVA of the end of __security_init_cookie()
+0x008: 00010464
函数的结尾地址(0xF6D3)位于跳转指令的中间位置,通过修改函数的结尾地址(将原来的0xF6D3修改成了0xF6D7),IDA Pro就可以正确显示最后一条指令“JMP”了。这也就是我们为什么可以假设IDA Pro使用pdata数据域来检索运行时函数的原因了。
Python脚本检测异常的运行时代码
根据我们刚才所发现的信息,我们开发出了一个能够基于pdata数据域来检测异常运行时代码的简单Python脚本。这个脚本的实现机制如下:它可以根据pdata数据域以及函数最后一条指令的地址来扫描运行时代码,如果扫描到的指令并不是本脚本所定义的指令(我们的脚本中定义的是validInstructions = [ "ret", "retn", "jmp", "int3" ]),那么脚本将会提醒用户扫描到了可疑的运行时函数。下面是我们对CCleaner的分析输出:
user@lab:$ ./pdata_check.py sample.exe
{ 'ASM': [ u'mov qword ptr [rsp + 0x18], rbx',
u'push rdi',
u'sub rsp, 0x20',
[...redacted…]
u'mov qword ptr [rip + 0x3ac8], r11',
u'mov rbx, qword ptr [rsp + 0x40]',
u'add rsp, 0x20',
u'pop rdi'],
'StartRaw': '0xea20',
'StartVA': '0x0000f620',
'StopRaw': '0xead3',
'StopVA': '0x0000f6d3',
'end': 'KO',
'lastASM': u'pop rdi'}
从上面给出的输出结果中我们可以看到,地址0x0000f620的运行时函数是以一个“pop”指令结束的,这就非常可疑了。
限制
本文所介绍的这种特殊的对抗反编译技术的方法其实并不是一种完美的解决方案,我们用这种方法对大量拥有pdata数据域的64位测试样本集以及很多的合法代码进行了测试和分析,并且测试结果的假阳性非常不理想。除此之外,攻击者可以通过向pdata数据域中引入额外的字节数据来干扰我们的分析。在本文所讨论的分析场景中,我们没有发现任何的异常,而且IDA Pro还可以在可视化视图中正确显示额外的操作代码。我们认为,虽然本文所设计的方法并不完美,但这种方法对于恶意软件分析人员来说,也许可以给他们提供一种额外的代码分析工具、方法或思路。
总结
对于从事恶意软件分析的研究人员而言,想要对那些已被非法修改的合法代码进行安全分析,其实是一个非常巨大的挑战。近些年来,针对产品供应链的攻击事件也层出不穷,即便是你向厂商申请获取“看似合法”的原始代码,你拿到手上的也不一定真的是安全的源代码。当一个合法的应用程序遭到入侵之后,恶意Payload可以隐藏在合法代码的“海洋”之中,想要找到这些恶意Payload就如同大海捞针一样。在本文所讨论的特殊场景中,分析人员还会遇到额外的挑战:即IDA Pro的输出信息并不是完全可信的。我们并不清楚这是攻击者故意用来扰乱分析人员的,还是说只是我们碰巧遇到这个“Bug”,但无论怎样,这种技术会让分析人员一不小心就漏掉了影响严重的恶意代码。我们所提供的这个脚本可以帮助安全分析人员识别可疑的运行时函数,但是对于更普遍的场景而言,我们的技术就不一定能够完美适用了,但这毕竟也是一种新的工具和分析恶意代码的思路。