针对一个红队病毒样本逆向分析

打印 上一主题 下一主题

主题 691|帖子 691|积分 2077

近日翻到一个比较新奇的样本,在最终后门载荷释放前运用了不少免杀手段,包括堆栈诱骗,实现反射性调用API,以及DLL侧加载、DLL挖空、HOOK规避等手法,对其执行流程和部门手法做具体分析纪录。
样本概述



  • 初始载荷
初始载荷如下,其中loader.exe是作者编译的一个shellcode加载器。



  • 执行流程
有合法签名可执行文件(taskhost.exe)侧载恶意 DLL (sbiedll.dll)。这个恶意DLL作为中心载荷,解密密文载荷DAT文件(sbiedll.dat)获取二阶段有用负载。解密的有用负载MoonWalk充当后门,滥用Google Drive进行命令和控制(C2) 通讯。流程图如下:



  • 经心构造的设置信息
样本主要使用“AES-CFB”算法解密载荷,多次使用MD5 hash算法做载荷校验或将hash值作为AES算法的KEY、IV值。主要设置信息如下:



  • 较为丰富的杀软规避
  • DLL 侧加载执行恶意载荷
  • 指定特定的执行参数,期望参数“--type driver”。
  • FNV1a hash动态解析 API。
  • 堆栈诱骗调用win API,规避win API调用过程检测(构造伪造堆栈、修改堆栈指针、调用 API、规复原始堆栈)
  • 使用了大量的windows底层函数(如内核函数NtCreateFile等)。
  • 使用当前植入主机的GUID md5值作为AES IV值,天生唯一、绑定载荷。
  • hook规避、断点查抄。
  • MD5 hash算法和AES-CFB算法进行解密,MD5hash算法进行完备性查抄
样天职析

侧加载

1. “白加黑”侧加载执行初始恶意载荷。由Sandboxie签名的合法可执行文件 (taskhost.exe) 侧载恶意 DLL (sbiedll.dll)。

“sbiedll.dll”中初始化了三个导出函数,但实际上都指向相同的地址,函数名称“SbieDll_Hook”。

2. 编写一个加载器执行恶意导出函数“SbieDll_Hook”,同步假造内存地址,动态、静态联合调试主要功能。

设置信息解密

3. 使用MD5校验加密设置信息,确保设置的完备性。计算密文段的MD5 hash来于硬编码在样本中的正确hash值做比对。

两段密文hash值:
  1. FE93E8E1C5C3032A26D783A78A820587
  2. 1E8EE70F02D60E389D8F721E8CE6DF1F
复制代码

4. AES-CFB算法进行解密,获取解密设置信息入下,其中包括明笔墨符“sbiedll.dat”、“--type”以及其他设置信息或密钥供后续使用。
杀软规避

5. 执行历程是否使用正确的参数启动,验证期望参数包含“--type driver”,如果此验证查抄失败,则终止历程。计参数的MD5哈希值,多次计算效果与硬编码的哈希值进行比较。
硬编码hash值:
  1. E2D45D57C7E2941B65C6CCD64AF4223E
复制代码
6. 使用加盐的FNV-1a哈希算法来躲避针对WINAPI的静态检测。在哈希计算过程中添加盐值不同样本的哈希值不同,提高了躲避静态检测的能力。

上图中伪代码通过指针运算和类型转换访问内存,还原C代码,所需API地址通过结构体成员访问。
  1. sImportTable->ntdll_LdrLoadDll = ResolveImport(L"ntdll", 0xFE0B07B0, 0xCA7BB6AC);
复制代码
函数体内部关键步骤入下:


  • 初始化哈希值。
  • 对输入字符串(DLL名或函数名)进行哈希计算。
  • 对盐值进行哈希计算。

首先,它对输入字符串(代表 DLL 或函数名称)进行哈希处理。然后,它单独对盐值进行哈希处理。此两步哈希处理过程相当于对输入字符串和盐的毗连进行哈希处理。
  1. while ( 1 )
  2.   {
  3.     Fun_FNV1a_Hash = 0x811C9DC5;                // FNV-1a 初始哈希值
  4.     InputString = (unsigned __int8 *)(a1 + *v12);
  5.     v18 = -1i64;
  6.     do
  7.       ++v18;
  8.     while ( InputString[v18] );                 // 输入字符长度计算
  9.     for ( i = &InputString[(unsigned int)v18]; InputString < i; Fun_FNV1a_Hash = 0x1000193 * (Fun_FNV1a_Hash ^ v20) )// 计算输入字符串FNV-1a哈希
  10.       v20 = *InputString++;
  11.     v21 = (unsigned __int8 *)&unk_7FFFBEAD7D78; // Salt value: CB 24 B4 BA
  12.     do
  13.     {
  14.       v22 = *v21++;
  15.       Fun_FNV1a_Hash = 0x1000193 * (Fun_FNV1a_Hash ^ v22);// 对盐值进行哈希计算
  16.     }
  17.     while ( v21 < byte_7FFFBEAD7D7C );
复制代码
盐值,CB 24 B4 BA

最终将API函数地址放置与连续的内存地址中,即结构体成员变量中。下图以API函数“LookupAccountSidw”为例。

别的ResolveImport中另有内置了一些API函数调用相干功能,此样本中暂时没用到。
7. DodgeBox在完成API初始化后,它就会扫描并解除从System32目次加载的 DLL。此过程包括遍历 .pdata每个 DLL 的部门,检索每个函数的起始和结束地址,并计算每个函数字节的 FNV1a 哈希值。计算存储在磁盘上的相同函数字节的相应哈希值。如果两个哈希值不同,则可以检测到潜在的篡改,将用磁盘中的原始版本替换内存中的函数。

此过程包括遍历 .pdata每个 DLL ,步骤方法入下:
  1. p_InMemoryOrderModuleList = &NtCurrentTeb()->ProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList;
复制代码
当火线程的线程环境块(TEB)->历程环境块(PEB)->已加载模块的信息链表InMemoryOrderModuleList。
获取链表信息后再循环遍历加载模块列表的每个节点。
  1. p_InMemoryOrderModuleList = &NtCurrentTeb()->ProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList;  for ( i = p_InMemoryOrderModuleList->Flink; i != p_InMemoryOrderModuleList; i = i->Flink )  {    Flink = (__int64)i[2].Flink;    v3 = (const wchar_t *)i[4].Flink;    if ( ((__int64)i[5].Blink & 0x60000000) != 0x20000000      && (*(_WORD *)(*(int *)(Flink + 60) + Flink + 22) & 0x2000) != 0 )
复制代码
DAT文件有用载荷解密及加载

8. 在当前历程堆中开辟内存,读取“sbiedll.dat”文件流。

在完成路径等相干字符初始化后,使用NtReadFile读取文件流至当前历程的堆空间中。
9. DAT文件有用载荷解密
读取计算机唯一标识符GUID,计算MD5。检索注册表“SOFTWARE\Microsoft\Cryptography MachineGuid”值获取体系GUID,计算其MD5值,作为后续解密AES算法的IV值。

查抄文件的前四个字节。如果这些字节非零,则表示 DAT载荷投递在了特定目标上,如果DAT文件不是特定于机器的,DodgeBox将继承使用 AES-CFB 加密解密文件,使用存储在设置文件中的密钥参数。从“sbiedll.dat”载荷的第五个字节开始解密,解密获取一个隐藏PE头的PE文件。

使用前机器GUID的MD5哈希作为AES IV重新加密载荷。
在完成有用载荷解密后,样本将载荷与当前植入机器绑定,使用原有的AES密钥key,但是将 GUID 的 MD5 哈希作为 AES IV。这种方法包管了解密的 DAT 文件无法在任何其他机器上解密,从而加强了有用载荷的安全性。

10. 关于堆栈调用诱骗可以再做一些更具体的说明。这里鉴戒原始报告的描述。
首先设置堆栈,经心构造堆栈的内容,包括插入返回地址和所需的参数,确保API调用能按预期进行。
真实API调用,在准备好堆栈和寄存器后,执行jmp指令,将控制流重定向到目标 API。这种方式使得 API 调用看起来像是从正常位置发起的。

这种方法联合了堆栈伪造和 API 调用技术,通过控制堆栈和寄存器的状态来确保 API 调用能够乐成并达到隐蔽的效果。这种复杂的技术可以有用地绕过静态分析和动态监控,增长了恶意代码的隐蔽性。
样本的加盐 FNV1a 哈希的 Python 实现如下所示:
  1. func fnv1aSalted(data, salt []byte, seedValue uint32) uint32 {
  2.     combinedData := append(data, salt...)
  3.     hash := seedValue
  4.     prime := uint32(0x01000193)
  5.     for _, byteValue := range combinedData {
  6.         hash ^= uint32(byteValue)
  7.         hash *= prime
  8.         hash &= 0xFFFFFFFF
  9.     }
  10.     return hash
  11. }
  12. func main() {
  13.     ntdll := []byte("n\x00t\x00d\x00l\x00l\x00")
  14.     salt := []byte{0xba, 0xb4, 0x24, 0xcb}
  15.     hash1 := fnv1aSalted(ntdll, salt, 0x811c9dc5)
  16.     fmt.Printf("Hash for ntdll: 0x%08x\n", hash1)
  17.     ldrLoadDll := []byte("LdrLoadDll")
  18.     hash2 := fnv1aSalted(ldrLoadDll, salt, 0x811c9dc5)
  19.     fmt.Printf("Hash for LdrLoadDll: 0x%08x\n", hash2)
  20. }
复制代码
团体样本尤其是一些免杀首发相对复杂,因为中途快照出现了些问题,注释等信息缺失,以是纪录思绪显得有点混乱,不过照旧根本描述扫除了相干手法。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王國慶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表