在这篇文章中,我们将会跟大家讨论目前恶意软件在隐藏其Windows API访问痕迹时所采用的常用技术。在本文所给出的分析样例中,为了确定恶意软件的功能,分析人员必须计算要计算出API的起始地址并对运行时进程进行符号解析。
在介绍完这些技术之后,我们会给大家演示一款我们自行开发的开源工具,在IDA脚本的帮助下,它可以对虚拟机中正在运行的进程进行符号解析操作。这样一来,它便给我们提供了一种能够快速提升反汇编代码可读性的有效方法。
技术分析
在执行一次分析时,我们通常可以看到恶意软件会尝试掩盖(通过模糊处理等技术)它所要使用的API。作为一名恶意软件分析人员,如果想要确定待分析的恶意软件会使用哪一个API,首先我们要做的就是对其进行符号解析,这样才能确定恶意代码真正的功能。
在这篇文章中我们所要讨论的两种常见的混淆技术为Encoded Function Pointer Tables和Detours Style Hook Stubs。在这两种场景中,API的入口点是无法直接从源代码中找出来的。
比如说,请大家先看下面这张图片中的代码,这部分代码来自于xdata加密勒索软件样本C6A2FB56239614924E2AB3341B1FBBA5的内存数据中提取出来的:
在上面这张图片中,我们可以看到一个数字值被加载进了eax,然后再与另一个数字值进行异或运算,最后作为一个函数指针被加载调用。需要注意的是,这些数字值只有在一个正在运行的进程中才有意义。我们可以根据内存导出数据中的这些数字值来计算出最终的数字结果,但我们还需要想办法弄清楚这个特定进程中所解析的API地址。除此之外我们还要考虑到,首选基地址冲突或开启了ASLR的系统都将有可能引起DLL重定位。
下面这张图片中显示的是数字值的初始化设置地址:
在我们此次的分析场景中,初始值是通过一次API哈希查询来完成加载的,这样一来,我们现在就有很多种方法可以来解决目前所面临的问题了。我既可以搜索一个公开的哈希列表,然后提取出其中的哈希值来构建一个我们自己的数据库,或者也可以想办法对已解码的API地址进行动态解析。
在我们真正开始之前,让我们先来看一看另外一个例子。下图所显示的代码来自于Andromeda样本(3C8B018C238AF045F70B38FC27D0D640):
上图所示的是恶意软件注入在内存中的代码,我们可以看到其中的第一个指令是从实际的Windows API中窃取来的,并存储在一个stub之中。在这种情况下,恶意软件可以通过这些stub访问所有的API。我们也可以从反汇编代码中看到,窃取来的指令是可变长度的指令。
为了对这些功能函数进行深入解析,我们需要完成以下几个步骤:
1.枚举出所有的stub;
2.计算第一条指令占有多少个字节;
3.提取出jmp地址;
4.减去窃取来的指令所占字节,得到API的入口点(entrypoint);
5.对计算出来的地址进行解析,找出指定的进程实例;
6.将stub重命名为有意义的值;
在这个例子中,我们尝试搜索了相关值的交叉引用,但并没有得到什么有意义的结果。现在我们面临的主要是两个问题:首先,我们如何才能更好地对计算出的API地址进行解析?;其次,如何才能将解析数据与我们的IDA数据库联系起来或添加进数据库中?
我们所尝试的第一种技术首先要计算出所有的最终地址,将它们写入到代码文件中,然后将数据注入到进程中,最后在下图所示的调试程序中检查数据表。由于调试程序中已经有一个API地址查询表了,所以我们可以更加方便快速地得到我们所需要的信息。
这样一来,我们就可以提取出相关的符号解析然后通过一个脚本来将其整合进我们的IDB中。
我们的工具
我们真正要做的是为每一个进程构建一个我们自己的符号查询表,并通过我们的脚本来将这类表的访问操作流程化。那么现在首先需要解决的问题是:我们如何才能构建出API地址的查询表?为了解决这个问题,我们可以按照以下步骤进行操作:
1.枚举出一个进程所加载的所有DLL;
2.对于每一个DLL,遍历输出表并提取出函数名和RVA;
3.根据DLL基地址计算出API的入口地址,然后提取出RVA;
4.根据上述所有信息构建出一个查询表;
虽然上述步骤听起来好像很麻烦的样子,但我们已经给大家提供了能够自动完成上述操作的代码库了。下面这张图片展示的是我们针对这种特殊场景所开发出来的一款远程查询工具。
为了充分释放这种类型的工具所能带来的便捷性,这种工具必须具备高效性。那么我们怎样才能更好地访问这些数据呢?以下几个因素是我们需要考虑的,例如数据如何提交、工具可接受的是哪种输入格式、以及工具如何更好地整合到我们的分析过程之中。
我们首先得考虑如何与该工具进行交互。为了最大程度地实现灵活性和可扩展性,我们可以选择下面这三种方法:
1.查询请求通过textbox单独提交;
2.查询请求通过批量文件提交;
3.查询请求通过网络和远程客户端提交;
对于输入格式,我们可以选择以下几种:
1.十六进制内存地址
2. 不区分大小写的API名称
3.dll_name@ordinal4.dll_name.export_name
工具的输出是一个CSV列表,其中包含有地址、名称、序数和DLL。虽然该工具的基本功能已经足够强大,但是在我们的分析过程中,我们仍然需要一种更加高效的方法来使用这款工具。该工具虽然可以很好地处理单独的查询请求和测试,但对于批量查询还不能够很好地支持。批量文件查询有时是非常方便的 ,但它需要将数据输出/导入与IDA数据库进行整合。
实际上,我们真正需要的是在IDA中运行我们的脚本,计算API地址,然后在IDA脚本的运行过程中解析这些地址,它将允许我们在进程的运行过程中对函数和指针进行重命名。为了实现这个目标,我们可以在IDA Jscript中整合一个网络客户端。IDA Jscript是一款开源的IDA脚本工具,它具备语法高亮、智能感知、函数原型提示工具和调试器等组件。
在这个例子中我们可以看到,脚本解码了xdata指针表,通过网络对API地址进行了解析,然后生成了一个IDC脚本并在IDA中对指针进行了重命名。运行该脚本之后,反编译输出结果的可读性大大增加了。
接下来,让我们回到刚才Andromeda的那个例子。我们可以通过下图所示的idajs脚本恢复出恶意软件所使用的API相关信息。
注:对于IDAPython用户,推荐使用一款python远程查询客户端。
总结
本文对恶意软件常用的Windows API模糊技术进行了分析,由于这些技术的存在,使得恶意软件分析人员必须提取出程序的运行时数据,计算出入口地址,然后将特定运行进程中提取出的数据解析成可读性较高的数据。除此之外,本文还介绍了一款简单的开源工具,这款工具可以整合多种IDA脚本语言,并允许分析人员绕过恶意软件所使用的模糊技术。
【工具下载】
|