Daniel Stepanic

使用 GULOADER 进行解密:反混淆下载器

Elastic Security Labs 介绍了更新后的 GULOADER 分析对策。

阅读时间:13分钟恶意软件分析
使用 GULOADER 进行解密:反混淆下载器

Overview

Elastic 安全实验室持续监控活跃威胁,例如 GULOADER(也称为CloudEyE ),这是一种规避性 shellcode 下载程序,在不断发展的同时,多年来一直非常活跃。 这些最新变化之一是在新的活动中向其向量异常处理程序 (VEH) 添加了异常,这为其本来就很长的反分析技巧列表增加了更多复杂性。

虽然 GULOADER 的核心功能在过去几年中并没有发生重大变化,但其混淆技术的不断更新使得分析 GULOADER 成为一个耗时且耗资源的过程。 在本文中,我们将讨论对 GULOADER 进行分类时的以下主题:

  • 回顾初始 shellcode 和脱壳过程
  • 找到解密后的 shellcode 的入口点
  • 讨论对 GULOADER 的 VEH 进行更新,以混淆控制流
  • 提供修补 VEH 的方法

初始 Shellcode

在我们的示例中,GULOADER 预先打包在 NSIS(Nullsoft 脚本安装系统)安装程序中。 安装程序解压后,主要组件包括:

  • NSIS 脚本——该脚本文件概述了各种配置和安装方面。

  • System.dll — 位于$PLUGINSDir下。 该文件被放置在临时文件夹中,以分配/执行 GULOADER shellcode。

  • Shellcode - 加密的 shellcode 被埋在嵌套文件夹中。

一种快速的方法是执行 GULOADER 后,通过监视 SysInternal 的进程监视器中的ReadFile事件来查明托管 shellcode 的文件。 在这种情况下,我们可以看到 shellcode 是从文件 ( Fibroms.Hag ) 中读取的。

GULOADER 使用不同的 Windows API 函数通过回调来执行 shellcode。 这样做的主要原因是为了避免以用于进程注入的传统 Windows API(例如CreateRemoteThreadWriteProcessMemory )为中心的检测。 我们观察到 GULOADER 使用了EnumResourceTypesACallWindowProcW

通过查看EnumResourceTypesA的 MSDN 文档,我们可以看到第二个参数需要一个指向回调函数的指针。 从上面的截图中我们可以看到,新分配的shellcode被放入了这个参数中。

查找主要 Shellcode 入口点

在最近的样本中,GULOADER通过包含许多不同的垃圾指令和跳转增加了初始shellcode开始时的复杂性。 下载器的逆向工程可能需要处理一个漫长的代码混淆过程,该过程旨在破坏某些工具中的反汇编和控制流,这使得找到核心 GULOADER shellcode 的实际启动变得非常困难。

查找初始调用的一种方法是利用 x64dbg 内部的图形视图并使用自下而上的方法来查找call eax指令。

追踪初始控制流的另一种技术是利用逆向工程框架Miasm 下面是一个简单的例子,我们可以传入 shellcode 并反汇编指令来遵循流程:

from miasm.core.locationdb import LocationDB
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine

with open("proctoring_06BF0000.bin", "rb") as f:
    code = f.read()

loc_db = LocationDB()
c = Container.from_string(code, loc_db)

machine = Machine('x86_32')
mdis = machine.dis_engine(c.bin_stream, loc_db=loc_db)
mdis.follow_call = True 
mdis.dontdis_retcall = True
asm_cfg = mdis.dis_multiblock(offset=0x1400)

Miasm 切断 142 jmp指令并浏览垃圾指令,我们已将其配置为在对 EAX 的调用指令(地址: 0x3bde )上停止。

JMP        loc_3afd
->	c_to:loc_3afd 
loc_3afd
MOV        EBX, EAX
FADDP      ST(3), ST
PANDN      XMM7, XMM2
JMP        loc_3b3e
->	c_to:loc_3b3e 
loc_3b3e
SHL        CL, 0x0
PSRAW      MM1, MM0
PSRLD      XMM1, 0xF1
JMP        loc_3b97
->	c_to:loc_3b97 
loc_3b97
CMP        DL, 0x3A
PADDW      XMM3, XMM5
PXOR       MM3, MM3
JMP        loc_3bde
->	c_to:loc_3bde 
loc_3bde
CALL       EAX

瘴气的尾端

GULOADER’s VEH Update

GULOADER 的标志性技术之一以其向量异常处理(VEH) 功能为中心。 此功能使 Windows 应用程序能够在异常通过标准异常流程之前拦截和处理异常。 恶意软件家族和软件保护应用程序使用这种技术,使分析师和工具难以跟踪恶意代码。

GULOADER 通过使用RtlAddVectoredExceptionHandler添加 VEH 来启动此过程。 在 GULOADER shellcode 的整个执行过程中,会特意放置一些代码来触发这些不同的异常。 当触发这些异常时,VEH 将检查硬件断点。 如果未找到,GULOADER 将使用一字节 XOR 密钥(每个样本的更改)和发生异常位置的一字节偏移量直接通过CONTEXT 结构修改 EIP。 我们将在后续章节中回顾该技术的一个具体示例。 以下是我们样本的 VEH 的反编译结果:

虽然这种技术并不新鲜,但 GULOADER 随着时间的推移不断添加新的例外情况;我们最近观察到在过去几个月中添加了这两个例外情况:

  • EXCEPTION_PRIV_INSTRUCTION
  • EXCEPTION_ILLEGAL_INSTRUCTION

随着 GULOADER 中添加新的例外情况,它最终可能会破坏用于加快研究人员分析过程的工具。

EXCEPTION_PRIV_INSTRUCTION

让我们来看看最近添加的两个遵循 VEH 工作流程的例外情况。 第一个异常( EXCEPTION_PRIV_INSTRUCTION )发生在尝试在不允许的特权级别上执行处理器指令集中的特权指令时。 某些指令(例如下面的WRSMR示例)需要内核级别的权限,因此当程序从用户模式运行时,它将由于权限不正确而触发异常。

EXCEPTION_ILLEGAL_INSTRUCTION

当程序尝试执行无效或未定义的 CPU 指令时,会引发此异常。 在我们的示例中,当我们遇到英特尔虚拟化指令(例如vmclearvmxon时,这将触发异常。

一旦发生异常,GULOADER VEH 代码将首先确定哪个异常代码导致了该异常。 在我们的示例中,如果异常与以下五个中的任何一个匹配,则代码无论如何都会采用相同的路径。

  • EXCEPTION_ACCESS_VIOLATION
  • EXCEPTION_ILLEGAL_INSTRUCTION
  • EXCEPTION_PRIV_INSTRUCTION
  • EXCEPTION_SINGLE_STEP
  • EXCEPTION_BREAKPOINT

然后,GULOADER 将通过遍历EXCEPTION_POINTERS结构内的 CONTEXT 记录来检查任何硬件断点。 如果在不同的调试寄存器中发现硬件断点,GULOADER 将向 CONTEXT 记录返回0 ,最终导致 shellcode 崩溃。

如果没有硬件断点,GULOADER 将检索距离导致异常的地址 7 字节的单个字节。 当使用带有vmclear最后一个示例时,它将检索字节( 0x8A )。

然后,使用该字节,它将与不同的硬编码字节执行 XOR 运算。 在我们的案例( 0xB8 )中,每个样本都是唯一的。 现在,通过派生的偏移量0x32 ( 0xB8 ^ 0x8A ),GULOADER 将通过将0x32添加到导致异常的上一个地址 ( 0x7697630 ) 来直接从 CONTEXT 记录修改 EIP 地址,从而导致下一个代码从地址 ( 0x7697662 ) 执行。

由于其间有不同的垃圾指令,并反复出现异常(我们在样本中计算了 229 个唯一异常),不难看出为什么这会破坏不同的工具并增加分析师的时间。

控制流清理

为了更容易地跟踪控制流,分析师可以通过跟踪执行、记录异常以及使用前面讨论的 EIP 修改算法修补 shellcode 来绕过 VEH。 对于这个过程,我们利用了TinyTracer ,这是一个由@hasherezade编写的工具,它利用了动态二进制检测框架Pin 。 这将使我们能够捕获触发异常的不同地址,因此使用上面的vmclear示例,我们可以看到地址为0x7697630 ,生成了一个调用KiUserExceptionDispatcher的异常,该函数负责处理用户模式异常。

一旦收集并过滤了所有异常,就可以将它们传递到 IDAPython 脚本中,我们将遍历每个地址,使用第 7 个字节和 XOR 键( 0xB8 )计算偏移量,然后使用短跳转修补所有产生异常的指令。

下图是在地址0x076976300x0769766C处触发异常的修补指令的示例。

下面的图表表示修补在全球范围内应用之前的控制流图。 带有vmclear指令的基本块以橙色突出显示。 通过实现 VEH,GULOADER 使控制流图变得扁平,使得追踪程序逻辑变得更加困难。

在使用jmp指令修补 VEH 之后,这会通过将基本块连接在一起来转换它们,从而降低 shellcode 流程背后的复杂性。

使用这种技术可以加速清洁过程,但需要注意的是,它并不是万无一失的方法。 在这种情况下,仍然有大量的代码/功能需要分析,但通过删除 VEH 无疑可以大大简化代码。 完整的 POC 脚本位于此处

结论

GULOADER 具有许多不同的功能,可以破坏反汇编,阻碍控制流,并使研究人员的分析变得困难。 尽管该过程并不完善,但我们可以通过不同的静态或动态过程来应对这些特征,以帮助减少分析时间。 例如,我们观察到 VEH 中出现了新的异常,我们仍然可以追踪它们并修补 shellcode。 这个过程将使分析师走上正确的道路,更接近使用 GULOADER 访问核心功能。

通过分享我们的一些工作流程,我们希望在您遇到野外 GULOADER 时提供多种建议。 根据 GULOADER 的变化,未来的行为很可能需要新的和不同的策略。 为了检测 GULOADER,以下部分包括 YARA 规则,此文章中的 IDAPython 脚本可在此处找到。 如需了解最新威胁研究的最新更新,请查看 Elastic Security Labs 团队编写的恶意软件分析部分

雅拉

Elastic Security 创建了不同的 YARA规则来识别此活动。 下面是一个用于识别 GULOADER 的 YARA 规则的示例。

rule Windows_Trojan_Guloader {
    meta:
        author = "Elastic Security"
        creation_date = "2023-10-30"
        last_modified = "2023-11-02"   
        reference_sample = "6ae7089aa6beaa09b1c3aa3ecf28a884d8ca84f780aab39902223721493b1f99"
        severity = 100
        arch = "x86"
        threat_name = "Windows.Trojan.Guloader"
        license = "Elastic License v2"
        os = "windows"
    strings:
        $djb2_str_compare = { 83 C0 08 83 3C 04 00 0F 84 [4] 39 14 04 75 }
        $check_exception = { 8B 45 ?? 8B 00 38 EC 8B 58 ?? 84 FD 81 38 05 00 00 C0 }
        $parse_mem = { 18 00 10 00 00 83 C0 18 50 83 E8 04 81 00 00 10 00 00 50 }
        $hw_bp = { 39 48 0C 0F 85 [4] 39 48 10 0F 85 [4] 39 48 14 0F 85 [7] 39 48 18 }
        $scan_protection = { 39 ?? 14 8B [5] 0F 84 }
    condition:
        2 of them
}

观察结果

所有可观察数据均可采用 ECS 和 STIX 格式下载

本研究讨论了以下可观察的结果。

Observable类型名称参考
6ae7089aa6beaa09b1c3aa3ecf28a884d8ca84f780aab39902223721493b1f99SHA-256Windows.Trojan.GuloaderGULOADER 下载
101.99.75[.]183/MfoGYZkxZIl205.binURL不适用GULOADER C2 URL
101.99.75[.]183IPv4 地址不适用GULOADER C2 IP

参考资料