在一个Windows主机上程序可以通过很多方法来连接网络。在逆向一个恶意软件时,关键点在于使用了什么API与它是如何生效的,这样才能明白数据发送与接受以及命令结构和内部协议(如果使用的话)。网络API的选择也影响如何构建你的指标(稍后会详细分介绍)。我将Windows恶意程序命令与控制通信分为4个API类别:Sockets,WinInet,URLMON和COM。这篇文章首要聚焦点是COM,因为它是最罕见的,了解最少并且最难进行逆向工程。
第一部分,sockets,最广为人知因为它与Unix的基本网络API相同。它提供了对TCP或UDP会话的某种原始会话级别的访问。虽然他有一段历史了,但是主要还是由ws2_32.dll
提供。任何想要使用socket API的应用程序都必须手动构建更高级的协议例如HTTP
。通过调用函数socket()
可以创建一个socket对象。在调用过程中就已经指定使用TCP或者UDP。如果一个恶意软件后门使用一个TCP客户端,函数connect()
必须被调用,该函数用来执行TCP三次握手,开辟一条连接用于数据的读写。在另一端的服务端程序通常会调用bind()
和listen()
来等待连接(虽然bind()也会被客户端使用来指定socket的出口端口)。send()
和recv()
函数通常用于进行TCP连接,而sendto()
和recvfrom()
通常用于UDP连接。从恶意软件分析的角度来说这是事情变的简单,如果我需要了解恶意软件期望的beacon
包的响应,我通常可以寻找调用recv()
函数然后查看接下来的代码如何查看它读取到的数据。不过在Windows上,sockets
可以跟大多数操作互换使用如它们是文件句柄一样。例如,一个进程(比如cmd.exe
)能够使用指定其标准输入输出由socket生成,并且该进程将自动通过网络进行通信。为了更深入学习socket API我推荐Richard Stevens的经典《UNIX Network Programming Volume 1》。使用套接字API的缺点是,必须手动与任何高级协议(如HTTP)交互。这使得恶意软件如何处理其请求时具有很大的灵活性,但必须明确地列出所有内容。恶意软件作者经常会在他们的HTTP流量和大多数web浏览器的流量之间引入细微差别。这些小差异使网络特征更明显。
使用WinInet API比使用socket API更简单一些。简化了与高层协议(HTPP,FTP,甚至GOPHER)的交互。要开始使用WinInet API与远程主机对话,首先需要调用InternetOpen()
,然后调用InternetConnect()
或InternetOpenURL()
。一旦internet被打开并建立了连接,为了执行和HTTP请求,您可以调用HttpOpenRequest()
函数来生成请求句柄,HttpSendRequest()
函数来发送请求。然后可以调用InternetReadFile()
来读取来自服务器的任何响应。它还可以用于从FTP会话读取数据。InternetWriteFile()
函数还可以用来代替需要通过网络发送数据的任何协议特定函数。HTTP函数为程序员提供了配置HTTP请求头(如用户代理字符串)中的大多数选项的能力。并不是所有这些值都必须指定,如果没有指定,则使用系统默认值。恶意软件的程序员没有足够的灵活性来在请求结构中引入微妙的异常,尽管他们可以像使用套接字那样,并且保留默认设置,恶意软件的HTTP请求将看起来几乎与网络上合法的Internet Explorer流量一样。
urlmon.dll提供的URL Monikers APi提供另一种网络通信的API。在后端它使用COM但是我选择把它从之后关于COM的讨论里单独列出来,因为使用这个API相对于直接与COM交互来说,是一种丑陋、难以逆向的一种抽象方法。从恶意软件的角度来说,在URLMon的函数中最流行的是URLDownloadToFile()
。在Win32 API中很少有一个函数能实现如此多的功能。您为该功能提供一个URL(IE可以理解的任何协议),一个文件名,并使用COM强制Internet Explorer将资源下载到指定的文件名。这在Dropper恶意软件中非常流行,只需从网站下载EXE并启动它即可。您可能还会遇到URLDownloadToCacheFile()
函数,该函数会将指定的URL下载到浏览器缓存中,并返回下载到的文件的名称。URLOpenStream()
和URLOpenPullStream()
可用于将URL下载到内存中的缓冲区,但是在恶意软件中很少使用这些功能。
对于恶意软件作者而言,使用COM进行恶意软件命令和控制具有许多优势。从实时响应/易失性数据/内存分析的角度来看,它掩盖了恶意流量的来源,因为与远程主机的所有通信都将在iexplore.exe进程而不是恶意软件进程中执行。从逆向工程的角度来看,这使事情变得复杂,因为在首次使用静态分析进行检查时,尚不能立即清楚恶意软件是否正在进行网络通信。COM在当今的许多程序员中已经过时,与现代软件中使用的许多其他技术相比,它的了解还很少。恶意软件分析人员可能尤其不熟悉COM的内部工作原理,这具体取决于Win32世界中的编程背景。
在实例化任何COM对象之前,必须调用函数CoInitialize()
来初始化COM库。一旦成功初始化,就可以调用CoCreateInstance()
来创建特定COM对象(例如Internet Explorer )的实例。为了了解此时要实例化的对象,您必须检查CoCreateInstance()
函数的第一个参数,它将是一个CLSID值,该值是COM对象的唯一标识符。这是使用COM的恶意软件样本中对CoCreateInstance()
的调用:
乍一看,很难判断此函数将实例化哪个对象,因为IDA只是向您显示第一个值的数据类型,而不是任何有意义的解释类型。此示例代码中的第一个参数是全局变量(实际上是一个常数),该变量存在于二进制文件中某个位置,该位置已由IDA Pro赋予标签“ rclsid”。如果双击第一个参数,IDA Pro将带您查看变量,就像在内存中一样: 此CLSID值被IDA识别为数据结构,并在此处显示为其组成部分。表示此CLSID值的方法是“ {0002DF01-0000-0000-C000-000000000046}”。如果有一个IDA脚本自动命名这些值会很好,但是与此同时,您可以在注册表中手动查找它们。通过打开regedit并浏览到键HKEY_CLASSES_ROOTCLSID,您可以看到相当长的子键列表,每个子键都有一个CLSID值命名。通过找到与您在IDA Pro中看到的十六进制值匹配的子项名称,您可以识别程序正在请求的对象名称,该名称存储在密钥的默认值中。这是regedit的屏幕截图,显示了上面示例代码中显示的CLSID的键: 因此,看来我们的恶意软件示例正在构成Internet Explorer对象的实例!为了使用该对象的任何功能,恶意软件必须利用CoCreateInstance()
函数的最后一个参数(标记为“ ppv”)。该参数是一个指针,该指针用于接收新分配的数据结构,该数据结构包含该对象的所有相关数据,最著名的是函数指针。此处记录了可用功能的列表:http://msdn.microsoft.com/en-us/library/bb159694.aspx
。要从源代码级别查看运行中的Internet Explorer对象,请查看以下文章:http://support.microsoft.com/kb/167658
。
作为逆向工程师,我们需要识别对此COM对象的最重要的函数调用是对函数Navigate()
或Navigate2()
的调用。这实际上完成了HTTP请求,该请求可能还包含POST数据或参数化的GET,从而将数据传输到远程命令和控制服务器。以下屏幕片段显示了从IDA Pro中看到的对IE COM对象的Navigate()
方法的调用: 在此片段中,我们看到正在访问ppv值,该值是从对CoCreateInstance()
的调用中填充的。正在从此数据结构中调用一个函数。
该函数与ppv数据结构的起始位置之间的偏移量为2Ch,您可以知道二进制文件正在调用此函数,因为调用指令从结构的起始位置开始访问此特定偏移量(“ call dword ptr [ecx + 2Ch ]” )。没有直接从此COM接口的Microsoft文档直接查看每个成员函数使用的实际内部偏移的明确方法,因此我制作了一个小型测试应用程序来简单地引用每个函数。然后,我反汇编了测试应用程序,可以看到偏移量到成员函数的清晰映射。下表是常用成员函数(特别是恶意软件)及其在调用指令中所示的偏移量的映射:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-12-9 15:50
被limer编辑
,原因: 添加图片
上传的附件: