一种恶意研究

图片

我遇到了一个最近的恶意文档文件,该文件随网络钓鱼电子邮件一起发送。我认为这是练习逆向工程并在Habr上编写新东西的好理由。在猫之下-解析恶意宏删除程序和恶意dll的示例。

巨集


来自文件abb256d9b0660f90bcf5fc394db0e16d6edd29f41224f8053ed90a4b8ef1b519的 Sha256 。在doc文件本身中,第一页上有一张图片,通知该文件受到保护,并说明了如何启用宏;文件中有两个带有数字的大表。数字以十进制形式编写,最长为十位数字,正负都有。

当受害者允许宏执行时(默认情况下是否启用了宏执行?),将触发一系列操作,最终执行updatedb_network函数,它将当前目录更改为临时目录,并在其中创建文件“ icutils.dll”,在该文件中,它将行中第一张表中的数字记为带符号的32位整数。结果是正确的dll。从此dll导入克隆功能

Declare PtrSafe Function clone Lib "icutils.dll" _
(ByVal Saved As String, ByVal Time As Integer) As Boolean

它以两个参数开头:

R1 = Module1.clone("Cream", 0)

如果克隆调用返回False,则icutils.dll文件将被第二个表中的数据覆盖,并使用相同的参数再次调用克隆。

展望未来,我会说第一个dll是64位,并且不会在32位系统上运行。因此,宏选择正确的二进制代码体系结构。

有趣的是,updatedb_network函数具有一段没有功能目的的代码:

Sub updatedb_network()
...
Dim query_to_change As Variant
    Set query_to_change = CurrentDb.QueryDefs("query_name")
    
    query_to_change.SQL = "SELECT * FROM Table ORDER BY ID Asc"
    query_to_change.SQL = "SELECT Field1, Field2 FROM Table ORDER BY ID Asc"
    query_to_change.SQL = "SELECT Field1, Field2 FROM Table WHERE Field LIKE Fashion"
    query_to_change.SQL = "SELECT Field1, Field2 FROM Table WHERE Field LIKE '" & something & "'"
...
End Sub

也许他在这里为那些快速浏览代码,看到SQL中的几行并且认为一切都还可以的人提供了有用的作品。我不知道。同样,大多数函数和变量具有随机或非真实名称(例如,updatedb_network不与数据库或网络交互)。尽管有例如dump_payload函数,该函数在icutil.dll中存储4个字节。但是无论如何,Document_Open函数的存在应立即提醒,恶意软件的作者不能随意重命名(尽管他们可以使用另一个自动启动的函数)。

因此,宏功能或多或少很清楚,是时候卸载dll并继续进行分析了。

第一个dll


第一个dll(sha256 7427cc4b6b659b89552bf727aed332043f4551ca2ee2126cca75fbe1ab8bf114)64位。

进口功能列表所包含的功能CreateProcessW(节目开始),CreateRemoteThread的(创建在一个线程另一个过程),VirtualAllocEx来(在分配的存储器的块的另一过程),WriteProcessMemory的(写入的存储器的另一过程),这立即建议的代码注入到另一处理。现在,让我们看看她使用IDA Free和Ghidra到底做了什么。
主入口点仅返回1,不执行其他任何操作。第二个导出的函数是clone,它由宏调用并包含恶意代码。
调用它的参数似乎没有任何影响。该应用程序解密两个数据块。具有以下内容(已解密)的第一个0x78数据块:

https://pastebin.com/raw/Jyujxy7z\x00\x00\x00\x00\x00\x00\x00\xf2i\xe0\x1d\x95h\xbc\x03\xe4#\xe0\x1d<\x04\xe0\x1d\xe6\x00\xde\x01\xa4\x17\xbc\x03x\x01\xe0\x1d\xe2\x16x\x07Qy\xbc\x03@Fx\x07Df\xbc\x03\x89a\xde\x01q\x11\xe0\x1d|Ix\x07D@\xbc\x03\x8a\x01\xde\x01^9\xde\x01\xf2i\xe0\x1d\x95h\xbc\x03\xe4#\xe0\x1d\xab

第二个数据块的长度为0x1D4C,并包含可执行代码。

此外,还将指向kernel32模块的指针,GetTickCount()函数的结果以及来自kernel32 ZwDelayExecution()函数的地址写入0x90字节结构

然后,创建进程(CreateProcessW)“ cmd.exe”。使用VirtualAllocEx可以在其中分配两个缓冲区:RW权限的长度为0x108,RWX权限的长度为0x1D4C。 RW缓冲区以0x90的长度复制上述数据块和上述结构。该结构还向解密的数据块写入一个指针(在子进程(cmd.exe)的地址空间中)。在RWX中,缓冲区被复制(WriteProcessMemory)用代码解密的数据块。
然后,在cmd.exe进程中,在RWX缓冲区的开头创建带有入口点的流(CreateRemoteThread),并将指向RW缓冲区的指针作为参数传递。这样就完成了克隆功能,该操作在cmd.exe进程中继续。

有趣的是,克隆函数似乎就像一段无法实现的代码,它导入(LoadLibraryW)“ WorkPolyhistor

将代码注入到cmd.exe中


它执行以下操作:

  • kernel32.dll查找必要功能的地址(其地址从父进程获取)
  • 加载ntdllOle32User32库
  • 在这些库中查找必要功能的地址。

有趣的是,对于代码中的大多数函数而言,没有函数名称,而仅代表CRC32(搜索已加载库中的所有函数名称,直到找到一个具有所需CRC32的函数为止)。也许这是防止通过字符串实用工具获取导入函数列表的保护,尽管以加密形式存储的代码具有这种保护很奇怪,而dll本身只是简单地按名称导入函数。总共检测到以下功能:

kernel32:

  • GetProcAddress
  • 负载库
  • 全局分配
  • GetTempPath
  • GetFileAttributesW
  • CreateProcessW
  • 全球免费
  • GlobalRealloc
  • 写文件
  • CreateFileW(按名称查找)
  • 写文件
  • 关闭手柄
  • Gettickcount
  • 读文件
  • 获取文件大小

ntdll:

  • RtlCreateUnicodeStringFromAsciiz
  • ZwDelayExecution
  • ZwTerminateProcess
  • swprintf

ole32:

  • CoInitialize(按名称查找)
  • CoCreateInstance(按名称查找)

msvcrt:

  • 兰德
  • rand

接下来,使用GetTempPath的进程获取临时目录的路径,在其中创建文件格式为26342235.dat的文件,其中文件名是从父进程收到的TickCount的十进制记录,并在每次新尝试时进行迭代(即如果无法下载有效负载)第一次尝试,然后再次尝试,将创建一个文件名为26342236.dat的文件。之后,将加载wininet库,并且有指向以下函数的指针:

  • InternetCloseHandle(crc32:0xe5191d24)
  • InternetGetConnectedState(crc32:0xf2e5fc0c)
  • InternetOpenA(CRC32:0xda16a83d)
  • InternetOpenUrlA(crc32:0x16505e0)
  • InternetReadFile(crc32:0x6cc098f5)

通过InternetGetConnectedState检查是否存在网络-如果不存在,则应用程序调用不存在的地址并掉线(此类保护功能确定了使用与机器网络隔离的方式将peyload转换为该地址的情况,这是应用程序异常终止的唯一情况,其余部分-。进行了3次尝试,然后使用ZwTerminateProcess终止cmd.exe )。如果存在网络,则使用找到的功能,从从父进程传递的URL(https://pastebin.com/raw/Jyujxy7z)下载有效负载,并将其保存到扩展名为.dat的先前创建的文件中。

接下来,从.dat文件中读取有效负载,进行解码(base64),然后使用URL中的CRC32与XOR进行XOR解密,检查解密数据的前2个字节是否为'MZ',如果是,则将结果保存到具有相同名称但扩展名的文件中。可执行程序

Python解密代码
from binascii import crc32
from base64 import b64decode


def decrypt_payload(payload_b64: bytes, url: str):
    payload_bin = b64decode(payload_b64.decode())
    key = str(crc32(url.encode())).encode()
    decrypted = bytearray()
    for i, b in enumerate(payload_bin):
        decrypted.append(b ^ key[i % len(key)])
    return bytes(decrypted)

使用CreateProcessW函数启动保存的文件。如果一切顺利,则使用ZwTerminateProcess退出cmd.exe进程如果出了点问题(缺少网络除外),则重新进行所有操作,最多尝试3次,dat和exe文件的名称每次都增加1。

第二个dll


第二个dll(sha256 006200fcd7cd1e71be6c2ee029c767e3a28f480613e077bf15fadb60a88fdfca)32位。

其中,主要的恶意功能是在clone功能中实现的它还解密2个缓冲区。第一个缓冲区的大小为0x78(120)字节,此类数据被解密并写入(以解密形式):

https://pastebin.com/raw/Jyujxy7z\x00\x00\x00\x00\x00\x00\x00\x1e(\xf0\x0e\xc5r\xc0;\x12)\xc0;Jr\xc0;Y4\xbc\x03/Mx\x07\x038\xde\x01\x9e\x05\xe0\x1d#\x08\xbc\x03\xeeU\xf0\x0e\x18{x\x078\x1a\xf0\x0e\xccg\xf0\x0eze\xde\x01\x89&\xe0\x1d\xf6\x1f\xe0\x1d

可以看出,开头是与x64版本相同的URL。

大小为0x4678字节的第二个缓冲区分配有RWX权限。将代码解密到其中,然后从缓冲区开始以0x4639的偏移量从中调用函数。

我没有详细分析此代码。他还可以在CRC32上找到功能,启动notepad.exe,在其中注入代码,然后从pastebin上的同一URL下载有效负载。

使用pastebin的有效载荷


使用pastebin解密的有效负载是一个32位exe文件(sha256 9509111de52db3d9a6c06aa2068e14e0128b31e9e45ada7a8936a35ddfaf155f)由于时间不足,我没有对其进行详细分解。

结论


总的来说,该恶意软件给我留下了深刻的印象,其中包含很多错误(我在这里不故意称呼它们)。好像他们在鞭打。
dll在内存功能中找到以后不再在任何地方使用的功能。也许此代码就像宏一样,每次被防病毒软件检测后,都会被网络犯罪分子定期重写,其结果是这些伪像仍保留在代码中。

有趣的是,在“拖放”到x64磁盘上的dll的“ dll”版本中,“危险的”导入函数的名称没有被屏蔽(您至少可以看到它们的字符串),并且在内存中解密且不适合磁盘的代码中,它们位于CRC32上。名称,而不仅仅是名称。

几天后删除了pastebin有效负载。

PS KDPV从这里拍摄

All Articles