前言
如果各位读者在Twitter上关注我(@0verfl0w_),那么你们可能已经注意到,我最近正在分析Ursnif/Gozi/ISFB的样本,并且困惑于恶意软件如何能在不进行DLL注入和进程Hollowing的情况下,通过一个单独的进程与C&C服务器进行通信。为解决这一问题,我阅读了Mandiant在2010年发表的一篇很棒的文章,其中说明了如何使用COM来控制某个进程(例如:Internet Explorer)执行某些操作。在本文中,我将探讨最新版本的ISFB所使用的COM机制,从而揭秘该恶意软件是如何暗中与命令和控制服务器进行通信的。后续,我还会发表一篇较长的分析文章,详细分析这一ISFB变种,以及在最后阶段前经历的多个阶段,敬请期待。
关于COM
根据Microsoft的描述,“Microsoft组件对象模型(COM)是一个独立平台、分布式、面向对象的系统,用于创建二进制软件的组件。”总而言之,COM允许程序通过COM对象来实现相互之间的交互。这种交互可以在同一个进程内,也可以在其他进程中,甚至可以在远程计算机上进行。并且,编写该程序的语言并不重要,只要该语言能够创建指针结构,并且能够通过这些指针调用函数即可。这也就是COM的兼容性,意味着像Visual Basic和Java这样的语言可以使用COM。如果各位读者想了解有关COM的更多信息,可以在这里查看Microsoft发布的描述和教程。
随着技术的进步,COM已经不再被频繁使用,因此分析人员如果遇到恶意软件利用了这种不熟悉的通信方法时,可能很难确定恶意软件的工作过程及其原理。静态分析过程甚至会更加复杂,除非我们知道自己在寻找的内容是什么,这也就是本文的意义所在。
COM机制及其在ISFB加载工具中的使用
ISFB恶意样本第二阶段加载工具(Loader)的MD5:5019f31005dba2b410b21c4743ef4e98
我上传了第一阶段恶意样本,并将第二阶段加载工具转储到VirusBay,以便各位读者可以按照本文的步骤进行操作。我将专注于第二阶段的加载工具,因为这是与C&C进行通信的地方。我将使用IDA对其进行静态分析,当然,大家也可以选择动态分析。
恶意软件使用COM功能与其C&C服务器进行通信的第一种方式是调用CoInitializeEx。调用该函数,将会初始化COM库,以调用线程可以利用的功能。如下面示例所示,很明显,如果初始化库过程失败,则会退出。这也就是说,恶意软件严重依赖于成功加载的COM库。
一旦我们发现恶意软件正在初始化COM库,我们就可以搜索对CoCreateInstance的调用,这会产生与特定CLSID相关联类的未初始化对象。这意味着,在我们跳过此调用后,会生成一个新的进程。尽管在此示例中有许多对CoCreateInstance的交叉引用,但我们能够根据在函数调用之前推送的CLSID,来确定具体是哪一个调用了Internet Explorer。IDA将根据它在内存中的实际情况显示CLSID,因此我们可以找到被调用的相应对象。但是,如何进行呢?
不同对象的CLSID,都存储在注册表中。因此,每当调用CoCreateInstance时,系统都会检查注册表,以获取传递的CLSID。从上图中,我们可以看到正在使用的CLSID是{0002DF01-0000-0000-C000-000000000046},我们可以在注册表中进行查找。我们可以在HKEY_CLASSES_ROOT\CLSID中找到所有可用CLSID的列表。找到CLSID后,可以看到其中显示正在创建的进程,在我们的示例中,它是Internet Explorer(版本1)。此外,传递给函数的IE_riid可以表明正在使用的接口,我们的示例中使用的riid是{EAB22AC1-30C1-11CF-A7EB-0000C05BAE0BE}。当在注册表中查找时,显示它是Microsoft Web Browser Version 1。我们使用Google查询这个riid,会找到IWebBrowser的界面。
现在,我们确切地知道正在创建的是什么实例,接下来就可以看看正在调用哪些函数。在IDA Pro中,有一个名为COM Helper的插件,该插件可以检测CLSID,并将名称更改为类似于它们所指向的名称。但对于免费版本的IDA来说,没有这一项功能,因此必须在注册表中查找。在IDA中,当我们看到对COM函数的调用时,我们发现其调用了dword ptr [ecx+2Ch],除非知道里面的函数,否则还是不知道其值的具体内容。这就是为什么我们必须在IDA中创建一个结构,允许我们为这些指针分配可理解的函数的原因。只需要单击“Structures”(结构)选项卡,然后点击“INSERT”(插入)键,即可添加新的结构。然后,我们单击“Add Standard Structure”(添加标准结构)。现在,我们已经知道正在调用Internet Explorer的过程,并且通过迅速搜索“使用COM C控制Internet Explorer”关键字,我们找到了其中一些网页中引用了IWebBrowser2的代码,因此我们要创建的标准结构称为IWebBrowser2Vtbl,可以使用免费版IDA Pro来创建。此外,我们知道IWebBrowser也已经被使用,因此我们要为它创建一个标准结构。
要确定正在使用的其他接口,还有一种方法比较简单,即查找对QueryInterface的调用。这一过程,将会检索该接口中所有可以调用的指针,从而允许我们创建正确的标准结构,并解析对这些函数的调用。
这一标准结构中,包含由IWebBrowser2导出的函数列表,因此我们可以简单地解析任何指向这些函数的指针,例如dword ptr [ecx+2Ch]就可以被解析为IWebBrowser2Vtbl.Navigate()。动态分析在这里变得至关重要,因为我们可以借此开始正确地匹配函数,而不再是假设指针指向该结构中的函数。
在该恶意软件的调试构成中,这些函数将被显示为ObjectStublessClient。有时,我们不得不依赖于Push的值,来确定函数正在执行的操作。一旦我们解决了大部分调用,那么就可以真正了解到其实际发生的事情:
1、Internet Explorer的实例是使用CoCreateInstance创建的。
2、调用IWebBrowser2->Navigate(),将C&C URL和收集到的数据作为参数传递,这将导致IE浏览器导航至这一URL。
3、调用IWebBrowser2->get_ReadyState(),判断返回值是否为4(READYSTATE_COMPLETE)。如果为4,则该函数将继续,否则会在休眠500毫秒后重新尝试该调用。
4、调用IWebBrowser2->get_Document(),并在已经导航到的页面中进行实际加载。
5、调用IUnknown->QueryInterface(),将IHTMLDocument2的CLSID传递给它。
6、调用IUnknown->QueryInterface(),将IHTMLElement的CLSID传递给它。
7、调用IHTMLDocument2->get_Body(),返回指向网站主体的指针。
8、调用IHTMLElement->get_OuterText(),返回C&C服务器的原始数据。
9、恶意软件对数据进行解密和解析。
目前,在恶意软件中,COM被广泛使用,其原因可能是它无法被常用的几个反恶意软件产品检测到,并且容易被一些毫无戒心的研究人员忽略掉。此前,Nocturnus研究小组曾经发表一篇文章,详细介绍了银行木马Ramnit如何利用COM API创建计划任务,以保持持久性。