巧用AI回溯海莲花APT样本释放过程

admin 2025年3月4日14:12:43评论56 views字数 28269阅读94分13秒阅读模式

恶意代码分析:最近帮朋友分析了一个APT组织海莲花样本,尝试使用AI插件来分析完整的文件释放过程,留此记录。海莲花(OceanLotus,APT32)是一支活跃在东南亚地区的APT(高级持续性威胁)组织,主要针对政府、军工、科研、能源等关键基础设施进行攻击。本次分析使用了IDA Pro的Gepetto插件,该插件通过集成大语言模型(LLM),可帮助研究人员更高效地进行恶意软件的静态分析。

文章作者:网络安全情报攻防站

原文链接:https://www.libaisec.com/1181.html

巧用AI回溯海莲花APT样本释放过程

1

Gepetto插件介绍

Gepetto是一个Python插件,支持多个LLM(如GPT-4o、Llama 3),可用于分析IDA Pro反编译的函数代码,并提供函数解释和变量重命名功能。主要特点包括:

●通过LLM自动解释函数逻辑,减少人工分析负担。

●变量、函数命名优化,提高代码可读性。

●兼容OpenAI、Ollama、Groq等多种AI模型。

安装Gepetto后,可在IDA Pro的伪代码窗口中右键调用它来分析目标函数,同时支持CLI模式用于查询特定代码片段。

巧用AI回溯海莲花APT样本释放过程

2

样本分析

本次分析的样本涉及多个变种,其中一个核心文件为 s.exe.v(MD5: 7A0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)。

沙箱检测什么都没出,看到存在反逆向工程。

巧用AI回溯海莲花APT样本释放过程

1. 反调试与反分析技术

该恶意样本具备多种反调试机制,目的是防止研究人员和安全工具进行分析。使用Gepetto分析后,可快速总结出主要的反分析策略:

检测调试状态:通过 IsDebuggerPresentNtQueryInformationProcess等API检查是否在调试环境中。

异常触发:利用 int 2D指令进行调试检测。

环境检测:检查 PEB结构中的DebugObject,如存在则进入无限循环。

虚拟机检测:检查BIOS序列号、磁盘信息、虚拟机相关进程(如vboxservice.exevmware.exe)。

用户交互检测:如果鼠标长时间不移动,则判定为分析环境。

2. 核心攻击流程回溯

我们利用Gepetto逐步回溯样本的核心攻击流程。

(1)初始载荷执行

●样本执行后创建 conhost.exe进程。

●在 %temp%目录下释放 1.msc,并调用 mmc.exe运行该文件。

(2)利用MMC XSS漏洞执行JS代码

1.msc文件中嵌入了 StringTable部分的恶意 APDS资源。

mmc.exe解析后,在进程上下文中执行JS代码。

(3)远程命令执行与持久化

JS代码加载VBS脚本,解密BinaryStorage资源中的二进制数据。

●在 ProgramFilesCloudflare目录下创建Warp.exe(白文件)和7z.dll(恶意DLL)。

●通过 WScript.Shell.run运行 Warp.exe,实现持久化。

(4)最终Payload加载与C2通信

7z.dll通过 DLL劫持Warp.exe载入。

●该DLL 进一步解密 ShellCode并执行。

●连接C2服务器 sz-everstar[.]com,进行远控通信。

3

详细静态分析过程

样本代码显示出种多反调试机制,在确保程序在被调试时不会正常运行。

检测调试器

if ( IsDebuggerPresent() )

●该函数检查当前进程是否有调试器附加。如果有,进入无限循环,调用 Sleep(0x2710u)

0x2710u是十六进制的数字,转换为十进制为 10000 毫秒(即 10 秒),表示在此状态下进程会每 10 秒“休眠”一次,似乎是为了消耗CPU资源,或者防止调试器进一步操作。

检查 PEB (Process Environment Block)

if ( NtCurrentPeb()->BeingDebugged == 1 )

●此行检查当前进程的 PEB 中的 BeingDebugged字段。如果该字段为 1,表示该进程被标记为正在被调试。

●进入无限循环,调用 Sleep(0x4E20u),其中 0x4E20u转换为十进制为 20000 毫秒(即 20 秒)。

●这个循环与上面的类似,目的也是为了消耗资源或阻止调试行为。

检查远程调试器

pbDebuggerPresent[0] = 0;:初始化 pbDebuggerPresent数组的第一个元素为 0。

CurrentProcess = GetCurrentProcess();:获取当前进程的句柄。

CheckRemoteDebuggerPresent(CurrentProcess, pbDebuggerPresent);

●这个函数检查是否有远程调试器正在调试当前进程。如果有,则 pbDebuggerPresent[0]会被设置为非零值。

if ( pbDebuggerPresent[0] )

●如果检测到远程调试器,进入无限循环,调用 Sleep(0xEA60u)(即 60000 毫秒或 60 秒)。

检查全局标志

p_NtGlobalFlag = &NtCurrentPeb()->NtGlobalFlag;

●获取当前进程的全局标志地址。

if ( p_NtGlobalFlag && (*(BYTE *)p_NtGlobalFlag & 0x70) != 0 )

●检查全局标志是否存在,并且检查其特定位是否被设置(具体是位 6和 位 5)。

●如果符合条件,进入无限循环,调用 Sleep(0x15F90u)(即 90000 毫秒或 90 秒)。

具体实现的核心代码如下:

●通过 IsDebuggerPresentNtCurrentPeb()->BeingDebugged检查调试器是否附加。

●使用 CheckRemoteDebuggerPresent检查是否存在远程调试。

●检查进程环境块中的全局调试标志。

●如果任何一种检测到调试器的标志为真,代码会进入无限循环,调用 Sleep函数,阻止进一步的调试操作和分析。

巧用AI回溯海莲花APT样本释放过程

采用了通过触发异常来进行反调试的技术

设置异常处理程序:使用 SetUnhandledExceptionFilter函数注册一个顶级异常过滤器TopLevelExceptionFilter,以便在发生未处理异常时执行自定义的处理逻辑。

触发异常:调用 RaiseException(0xC000008E, 0, 0, 0)以人为方式引发异常。这个异常代码对应于特定类型的错误,通常与内存访问或状态相关。

重新设置异常处理:在引发异常后,再次调用 SetUnhandledExceptionFilter来设置新的异常处理程序。

异常条件判断:接下来,通过检查 dword_14001C8E4的值来决定是否进入无限循环。如果该值为真,程序将进入一个无限循环,每次循环中调用Sleep(0x9C40u)(即约 40 秒),进一步减缓分析速度。

修改 OS 版本信息:之后,程序还会对 dwOSVersionInfoSize和其他操作系统版本信息字段进行修改,以伪装其运行环境,从而增加分析难度。

巧用AI回溯海莲花APT样本释放过程

通过植入 int 2Dh中断,程序可以检测到是否有调试器附加到其进程上。

如果调试器存在,该中断可能会导致程序崩溃或触发特定的调试异常,从而使程序无法在调试环境中正常运行。

函数定义

int64_t sub_14000E6F0()是一个返回int64_t类型的函数,通常用于存储64位整型值。

结果初始化

int64_t result;声明了一个64位的整数变量 result

result = 0x164;result初始化为16进制的 0x164,其十进制值为356。

内嵌汇编

__asm { int 2Dh; Windows NT - debugging services: eax = type }使用内嵌汇编调用 int 2Dh。这个指令在Windows NT 系统中用于调用调试服务,具体来说,int 2Dh是一个中断指令,它会触发 Windows 的调试异常。

●这种调用可以被用作反调试技术。如果程序在调试环境中运行,调试器会接收到这个中断并可能会进行相应处理。通过这种方式,程序可以检测到自己是否在调试中,从而能够采取不同的行为。

返回结果

return result;返回初始化的 result值(356)。

巧用AI回溯海莲花APT样本释放过程

通过检查 PEB 中的 DebugObject,程序能有效地检测是否在调试环境中运行。

函数调用检查

●代码首先通过一个函数指针调用 v91,并传入一些参数。如果返回值为假(即0),则继续执行后续代码。

●这个检查通常用于验证当前进程的状态,确保其没有被调试器影响。

变量初始化

v95 = *v93;:从 v93指向的位置读取值并赋给 v95

v96 = (unsigned int64_t)(v93 + 2);v96被设置为v93加上2的地址,通常用于指向 PEB(进程环境块)中的某个结构。

v97 = 0;:初始化计数器 v97

检测 DebugObject

while (StrCmpW(L"DebugObject", *(PCWSTR *)(v96 + 8))):循环检查 v96 + 8地址中的字符串是否为"DebugObject"。这用于检测进程是否被调试。

●如果存在 "DebugObject",则表示该进程正在被调试。

指针操作和条件判断

v98 = *(QWORD *)(v96 + 8) + *(unsigned int16_t *)(v96 + 2) + 8;:计算新的指针地址。

●通过位运算和条件判断,更新 v96的值。

if (++v97 >= v95):增加计数器并检查其是否超过 v95,如果是,则跳转到 LABEL_176

内存释放和睡眠

if (*(DWORD *)(v96 + 20)):检查某个条件,如果为真,则释放内存 VirtualFree(v93, 0x164, 0x8000u);并进入死循环睡眠 40 秒。

●这段代码的意图是,如果检测到进程被调试,则释放内存并使程序进入休眠状态,以防止进一步的调试。

巧用AI回溯海莲花APT样本释放过程

创建一个名为 "Random name" 的互斥体,并设置其句柄的信息,最后关闭这个句柄以释放资源。互斥体用于在多线程环境中实现对共享资源的访问控制,确保同一时间只有一个线程可以访问特定资源。通过使用SetHandleInformation,可以设置句柄的特定属性,增强对互斥体的管理。

函数定义

int64_t sub_14000A740()是一个返回int64_t类型的函数,通常用于执行一些初始化或设置操作。

句柄声明

HANDLE MutexW;声明一个句柄 MutexW,用于表示互斥体对象。

void *v1;声明一个指针 v1,用于存储 MutexW的值。

创建互斥体

MutexW = CreateMutexW(0i64, 0, L"Random name");

调用CreateMutexW函数创建一个互斥体对象。

●第一个参数 0i64表示不指定安全属性。

●第二个参数 0表示初始状态未被拥有。

●第三个参数 L"Random name"是互斥体的名称。

●这将返回一个句柄 MutexW,该句柄可用于后续的同步操作。

检查互斥体创建成功与否

if (MutexW):检查互斥体是否成功创建。如果 MutexW不为 NULL,则继续执行后续代码。

设置句柄信息

关闭句柄

CloseHandle(v1);:关闭之前创建的互斥体句柄,释放资源。

返回值

return 0i64;:函数返回0,表示正常结束。

巧用AI回溯海莲花APT样本释放过程

监视对动态分配内存块的写入操作,通过 GetWriteWatch函数可以检测是否有写入发生。在反调试的上下文中,使用MEM_WRITE_WATCH监视内存访问检测调试器或其他程序对其代码的修改,如果在监视的内存区域内进行了写入,程序可以通过其他逻辑处理这种情况。

内存分配

v103 = VirtualAlloc(0i64, 0x8000ui64, 0x3000u, 4);:使用VirtualAlloc函数申请一块内存,大小为 0x8000字节(32KB),分配类型为MEM_RESERVE,保护属性为PAGE_READWRITE。如果成功,v103将指向分配的内存地址。

if (v103):检查内存分配是否成功。

第二块内存分配

v104 = VirtualAlloc(0i64, 0x100000ui64, 0x203000u, 4);:申请一块大小为0x100000字节(1MB)的内存,分配类型为 MEM_WRITE_WATCH | MEM_COMMIT | MEM_RESERVE,保护属性为 PAGE_READWRITEMEM_WRITE_WATCH用于监控对该内存块的写入访问。

v105 = v104;:将 v104的值赋给 v105

检查第二块内存分配

if (!v104):如果第二块内存分配失败,则释放 v103指向的内存并跳转到LABEL_207

写入内存

*v104 = 1234;:将 1234写入到 v104指向的内存地址。

设置写入监视

dwCount = 4096164;:初始化 dwCount变量,用于存储监视写入的计数。

if (GetWriteWatch(0, v104, 0x100000ui64, (PVOID *)v103, &dwCount, dwGranularity)):调用GetWriteWatch函数来监视v104指向的内存块的写入情况。

●第一个参数是保留的,通常为 0

●第二个参数是要监视的内存块的起始地址。

●第三个参数是内存块的大小。

●第四个参数是一个指向内存地址的指针,用于存储写入监视信息。

●第五个参数是传入的计数变量 dwCount

●第六个参数是粒度,通常设置为系统页面的大小。

错误处理

LastError = GetLastError();:如果 GetWriteWatch调用失败,获取最后的错误代码并打印错误信息。

●释放之前分配的内存 v103v105

巧用AI回溯海莲花APT样本释放过程

avghookx.dll是 AVG 杀毒软件的一个组件,它通常用于提供实时保护和监控系统。如果检测到该 DLL 存在,程序通过进入无限循环来阻止后续代码的执行,防止被 AVG 杀毒软件监控或干扰。

检查模块句柄

GetModuleHandleW(L"avghookx.dll"):该函数用于获取名为avghookx.dll的模块(动态链接库)的句柄。

●如果该模块已被加载到当前进程的地址空间中,GetModuleHandleW将返回该模块的句柄;如果没有加载,返回值为 NULL

条件判断

if (GetModuleHandleW(L"avghookx.dll")):如果返回的句柄不为 NULL,说明 avghookx.dll存在于当前进程中。

无限循环

while (1):如果检测到 avghookx.dll存在,程序将进入一个无限循环。

Sleep(0x5BA0u);:在循环中调用 Sleep函数,参数为0x5BA0(23328),表示线程将暂停执行 23328 毫秒(约 23.3 秒)。

●由于这是一个无限循环,程序将持续休眠直到被外部干预或进程结束。

巧用AI回溯海莲花APT样本释放过程

检测当前运行的程序是否是已知的沙箱、如果发现当前程序的名称与已知的沙箱或恶意软件匹配,程序将进入一个无限循环,以防止执行进一步的操作。

字符串数组初始化

psz1是一个宽字符字符串数组,包含了一系列可能的程序名称,用于检测是否运行在沙箱环境中。程序名称包括:

sample.exe

bot.exe

sandbox.exe

malware.exe

test.exe

klavme.exe

myapp.exe

testapp.exe

获取当前进程的图像路径

Buffer = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;:通过调用 NtCurrentPeb获取当前进程的环境块,从中提取出当前进程的图像路径名称(执行文件的路径)。

路径检查

if (Buffer):检查 Buffer是否有效,确保获取到的路径存在。

FileNameW = PathFindFileNameW(Buffer);:提取出路径中的文件名部分。

遍历程序名称并比较

for (i = 0; i < 8; ++i):遍历 psz1中的所有程序名称。

if (!StrCmpIW(psz1[i], FileNameW)):使用 StrCmpIW函数比较当前文件名和 psz1中的每个名称,比较不区分大小写。

●如果找到匹配的文件名,进入一个无限循环:

while (1) Sleep(0x22CDu);:在无限循环中调用 Sleep函数(参数为0x22CD,即 8925 毫秒),使程序处于休眠状态,从而有效地停止进一步执行。

去除文件扩展名

PathRemoveExtensionW(FileNameW);:去除文件名的扩展名。此行在前面的逻辑中没有直接用途,但可能是为了后续处理。

变量初始化

v3v4被初始化为 -1,随后 v4在一个 do循环中自增,具体用途和上下文不清楚,可能用于某种计数或状态跟踪。

巧用AI回溯海莲花APT样本释放过程

检测当前运行程序的用户名,以判断是否在虚拟机、沙箱或由安全研究人员使用的环境中。如果用户名与数组中列出的任何名称匹配,程序可以采取适当的措施,例如进入无限循环或终止运行,以防止在这些环境中被分析。

字符串数组初始化

String是一个宽字符字符串数组,包含了一系列常见的用户名,这些用户名可能与虚拟机、沙箱或安全研究人员相关。包括:

CurrentUser

Sandbox

Emily

HAPUBWS

Hong Lee

IT-ADMIN

Johnson

Miller

milozs

Peter Wilson

timmy

user

sand box

malware

maltest

test user

virus

John Doe

内存分配

v138 = (WCHAR *)malloc(0x202ui64);:动态分配一块内存以存储当前用户的名称,大小为0x202字节(514 字节),用于存储宽字符字符串。

获取当前用户名

if (GetUserNameW(v138, (LPDWORD)&pcbBuffer)):使用 GetUserNameW函数获取当前用户的名称,并将其存储在 v138指向的内存中。

pcbBuffer是一个指向 DWORD 的指针,用于存储返回的用户名的长度。

用户名比较

for (k = 0; k < 18; ++k):遍历 String数组中的所有用户名。

●在这段代码中,实际的比较逻辑没有显示出来,但可以推测这里会有一段代码比较 v138中获取的当前用户名与 String数组中的每个字符串,以判断当前用户名是否匹配其中之一。

巧用AI回溯海莲花APT样本释放过程

检测当前计算机的名称,以识别是否在沙箱或虚拟机环境中运行。通过检查计算机名称是否与预定义的名称列表相匹配,采取措施,阻止程序运行或执行特定逻辑,以防止在这些环境中被分析。

字符串数组初始化

v404是一个包含多个宽字符字符串的数组,代表一系列常见的计算机名称,通常与沙箱、虚拟机或分析环境相关。这些名称包括:

SANDBOX

7SILVIA

HANSPETER-PC

JOHN-PC

MUELLER-PC

WIN7-TRAPS

FORTINET

TEQUILABOOMBOOM

内存分配

v142 = (WCHAR *)malloc(0x20ui64);:动态分配一块内存用于存储计算机名称,这里分配的大小为 32 字节。

v143 = v142;:将 v142的指针赋值给 v143,以便后续使用。

获取计算机名称

if (!GetComputerNameW(v142, (LPDWORD)&pcbBuffer)):调用GetComputerNameW函数,以获取当前计算机的名称,并将其存储在 v142指向的内存中。如果函数调用失败,程序将跳转到 LABEL_290

获取 DNS 主机名

GetComputerNameExW(ComputerNameDnsHostname, 0x0, (LPDWORD)&pcbBuffer);:调用 GetComputerNameExW函数获取 DNS 主机名,pcbBuffer用于存储返回的主机名的长度。

分配更大的内存

v145 = (WCHAR *)malloc(2164 * (unsigned int)((DWORD)pcbBuffer + 1));:根据上一步获取的主机名长度,分配足够的内存来存储主机名。

v146 = v145;:保存分配的内存指针。

再次获取计算机名称

if (!GetComputerNameExW(ComputerNameDnsHostname, v145, (LPDWORD)&pcbBuffer)):再次调用 GetComputerNameExW函数,将主机名存储在v145指向的内存中。如果失败,将释放已分配的内存并跳转到 LABEL_296

巧用AI回溯海莲花APT样本释放过程

通过 WMI 查询获得逻辑磁盘的信息,并检查查询是否成功。通过这种方式,程序可以检测系统的物理磁盘信息,从而可以进行进一步的分析或操作。

这种方法通常被用于系统监控、硬件检测或在恶意软件中用于隐藏自身。

WMI和字符串分配

sub_14000E1C0(&v17, &v11, L"ROOT\CIMV2"):这个函数调用用于连接到 WMI(Windows Management Instrumentation)命名空间ROOT\CIMV2。如果连接失败,函数返回0x164,表示错误。
v1和v2分别使用SysAllocString分配两个字符串:

v1被分配为 WQL(WMI Query Language)。

v2被分配为 SELECT * FROM Win32_LogicalDisk,这是一个 WMI 查询,用于获取系统的逻辑磁盘信息。

检查指针有效性

v4 = 1;:初始化标志变量 v4,用于后续判断。

if (v1):检查 v1是否有效,确保字符串分配成功。

if (v2 && ...):检查 v2是否有效,并且执行一个复杂的条件判断。

调用 WMI 查询

●如果查询失败(返回值小于 0),则进入条件判断。

处理查询失败

●在查询失败的情况下,设置 v4 = 0,表示查询未成功。

●调用 sub_14000DC60(L"ExecQuery"),可能是记录日志或执行某个操作。

●接下来,调用与 v17v11相关的函数,处理 WMI 对象的释放或清理。

CoUninitialize():调用此函数以释放 COM 库的初始化,这通常在完成 WMI 操作后进行。

巧用AI回溯海莲花APT样本释放过程

检测并访问系统中的物理驱动器。通过获取Windows系统目录,确定驱动器号,并构造设备路径打开驱动器,然后执行设备控制操作来收集有关驱动器的信息。

获取Windows系统目录

GetSystemWindowsDirectoryW(Buffer, 0x104u):此函数用于获取Windows系统目录的路径。如果调用失败,程序跳转到 LABEL_25

获取驱动器号

DriveNumberW = PathGetDriveNumberW(Buffer):该函数用于获取存储系统目录的驱动器的驱动器号。如果返回值小于0,则跳转到 LABEL_25

准备设备路径

memset(pszDest, 0, 0x104u):清空 pszDest缓冲区。

wnsprintfW(pszDest, 260, L"\\.\%C:", (unsigned int)(DriveNumberW + 65)):根据驱动器号生成对应的设备路径,例如 \.C:

打开驱动器

FileW = CreateFileW(pszDest, 0x80000000, 3u, 0i64, 3u, 0x200000u, 0i64):尝试以读访问权限打开对应的驱动器。如果打开失败,跳转到 LABEL_25

分配内存

v8 = LocalAlloc(0x40u, 0x200000ui64):分配内存用于存储驱动器信息。如果内存分配失败,则跳转到LABEL_25

设备控制操作

BytesReturned = 0;:初始化返回字节数为0。

if (DeviceIoControl(FileW, 0x560000u, 0i64, 0x2000u, &BytesReturned, 0x164) && *v8):调用 DeviceIoControl函数,发送控制命令到驱动器,并检查返回是否成功。

●如果成功,进入循环处理逻辑。

处理物理驱动器

v9 = 0;:初始化物理驱动器索引。

while (wnsprintfW(FileName, 260, L"\\.\PhysicalDrive%u", (unsigned int)v8[6 * v9 + 2]) > 0):根据v8中存储的驱动器信息构造物理驱动器路径,格式为 \.PhysicalDriveX

v10 = CreateFileName(FileName, 0x80000000, 1u, 0i64, 3u, 0, 0i64):尝试打开物理驱动器。如果打开失败,跳出循环。

if (!DeviceIoControl(v10, 0x7405Cu, 0i64, 0, &OutBuffer, 8u, &v16, 0i64)):对打开的物理驱动器执行控制命令,检查返回结果。

●如果成功,设置标志 v5 = 1,并关闭句柄。

巧用AI回溯海莲花APT样本释放过程

检测当前环境是否为虚拟机或沙箱。通过检查设备描述字符串,程序可以识别出常见的虚拟化环境,如 VirtualBox、VMware、QEMU等。

如果检测到这些环境,程序可能会采取措施,如退出或执行特定逻辑,以避免在这些环境中运行。

检测虚拟机相关字符串

if (PropertyBuffer && ...):此条件检查PropertyBuffer是否有效,并且使用StrStrIW函数检查PropertyBuffer

中是否包含以下字符串:

vbox:表示 VirtualBox 虚拟机。

vmware:表示 VMware 虚拟机。

qemu:表示 QEMU 虚拟机。

virtual:表示一般虚拟化相关的字符串。

●如果检测到这些字符串,程序将执行 break;,这通常表示在循环中跳出,可能是在检测到运行在虚拟机或沙箱环境中。

设备信息枚举

LABEL_15::这是一个标签,表示代码流程的一个位置。

if (!SetupDiEnumDeviceInfo(v2, ++v3, &DeviceInfoData)):调用SetupDiEnumDeviceInfo函数来枚举设备信息。如果失败,则执行后续的代码。

●在失败的情况下,v0 = 0;用来标记状态,如果 PropertyBuffer不存在,则跳转到 LABEL_18

释放资源

LocalFree(PropertyBuffer);:释放 PropertyBuffer占用的内存,以避免内存泄漏。

清理设备信息列表

LABEL_18::另一个标签,用于处理清理操作。

SetupDiDestroyDeviceInfoList(v2);:销毁之前创建的设备信息列表,释放相关资源。

if (GetLastError()):检查最后的错误,如果有错误发生,则判断错误码。

if (GetLastError() != 259):错误码 259 表示“没有更多数据”,这通常是正常情况。如果错误码不是 259,则返回 0,表示程序执行失败。

巧用AI回溯海莲花APT样本释放过程

程序开始时,会记录鼠标的当前位置,然后在 5 秒后再次记录位置。如果这两个位置相同,程序将进入一个无限的休眠状态。这种行为通常可以用作一种反调试手段,试图检测程序是否在被调试或虚拟环境中运行,或者是为了阻止用户的进一步操作。

变量初始化

dwSize = 0i64;pcbBuffer = 0i64;:这两行代码将dwSizepcbBuffer初始化为0,类型为64位整型(i64)。

获取鼠标位置

GetCursorPos((LPPOINT)&dwSize);:调用 GetCursorPos函数获取当前鼠标光标的位置,并将其存储在 dwSize中。这个函数将鼠标的坐标(x 和 y)填充到 dwSize中。由于dwSize被定义为 i64,这里可能存在数据类型不匹配的问题,因为GetCursorPos实际上需要一个 POINT结构来存储两个整型值。

睡眠延迟

Sleep(0x1388);:此处调用 Sleep函数使当前线程休眠一个指定的时间,这里是 0x1388 毫秒(即 5000 毫秒或 5 秒)。这可能是为了让用户在这段时间内进行一些操作。

再次获取鼠标位置

GetCursorPos((LPPOINT)&pcbBuffer);:再次调用 GetCursorPos获取鼠标新位置,并存储在 pcbBuffer中。

比较鼠标位置

if ((HKEY)dwSize == pcbBuffer):检查 dwSizepcbBuffer是否相等。这里的 (HKEY)强制类型转换可能是为了将 dwSize转换为某种指针或句柄类型,这种用法通常不太合理,因为它可能导致类型混淆。实际上,dwSize应该是一个结构体或包含鼠标坐标的整型,而 pcbBuffer也应类似。

无限循环

if条件成立后,进入无限循环 while (1),在这个循环中调用 Sleep(0x9C40u);(约 4 秒)。这表示如果鼠标位置在这段时间内没有变化,程序将持续休眠,可能是为了阻止进一步的操作或监控。

巧用AI回溯海莲花APT样本释放过程

检测当前环境是否为虚拟机。通过 CPUID 指令和字符串比较,它可以识别出多种虚拟化环境。代码中的无限循环可能用于持续监控或处理某些操作,导致程序无法正常退出。

虚拟机标识字符串

v401数组包含了一系列字符串,这些字符串用于检测虚拟机环境。具体字符串包括:

L"KVMKVMKVM":表示 KVM 虚拟机。

L"Microsoft Hv":表示Microsoft Hyper-V。

L"VMwareVMware":表示 VMware虚拟机。

L"XenVMXenVM":表示 Xen 虚拟机。

L"prl hyperv ":表示Parallels Hypervisor。

L"VBoxVBoxVBox":表示VirtualBox。

CPUID 指令

__asm { cpuid }:这一行通过汇编语言的 CPUID 指令来获取 CPU 信息。CPUID 指令可以返回处理器的特性和状态,包括虚拟化相关的信息。

处理器寄存器的存储

*(ULONG_PTR *)((char *)&v374[1] + 4) = __PAIR64__(_RCX, _RBX);*(_QWORD *)MultiByteStr = __PAIR64__(_RCX, _RBX);:这两行代码将RCXRBX寄存器的组合值存储到指定位置,MultiByteStr可能用于后续的字符串处理。

变量初始化

v394v397被初始化为 0,这些变量可能用于后续的逻辑处理。

v390 = _RDX;:将 _RDX寄存器的值存储到变量 v390中,可能用于后续的处理。

字符转换

do {...} while (1);:这是一个无限循环。

●在循环内部,首先调用 MultiByteToWideChar函数来转换多字节字符串为宽字符字符串,获取字符串长度并存储在v172中。

●然后,分配内存给 v173,用于存储转换后的宽字符串。

memset(v173, 0, 2i64 * (v172 + 1));:初始化 v173所指向的内存区域为0。

MultiByteToWideChar(0, 0, MultiByteStr, -1, v173, v172);:将MultiByteStr转换为宽字符并存入 v173

●循环将持续执行,可能是为了不断检查或处理虚拟机相关的数据。

巧用AI回溯海莲花APT样本释放过程

检测与虚拟机相关的服务是否在系统中运行。通过打开服务控制管理器并尝试获取服务信息,程序可以识别出特定的虚拟机服务。如果服务控制管理器的句柄获取失败,程序将返回错误,表明无法继续运行。

虚拟机服务名称数组

psz2数组包含了一系列与虚拟机相关的服务名称,这些服务通常与 VirtualBox 及其组件有关:

L"VBoxWddm":VirtualBox WDDM 驱动。

L"VBoxSF":VirtualBox 文件共享服务。

L"VBoxMouse":VirtualBox 鼠标驱动。

L"VBoxGuest":VirtualBox 客户端服务。

L"vmci":虚拟机通信接口服务。

L"vmhgfs":虚拟机高效文件系统服务。

L"vmmouse":虚拟机鼠标驱动。

L"vmemctl":虚拟机记忆控制服务。

L"vmusb":虚拟机 USB 服务。

L"vmsusbmouse":虚拟机 USB 鼠标服务。

L"vmx_svga":虚拟化的 SVGA 显示驱动。

L"vmxnet":虚拟网络驱动。

L"vmx86":虚拟化的 86 处理器模拟。

打开服务控制管理器

v0 = OpenSCManagerW(0i64, L"ServicesActive", 5u);:调用OpenSCManagerW函数以获取服务控制管理器(SCM)的句柄。这里的 0i64表示指向本地计算机的指针,L"ServicesActive"是服务数据库的名称,5u表示访问权限。

●if (!v0):如果OpenSCManagerW返回一个空值,表示获取 SCM 句柄失败。
在这种情况下,程序打印错误信息并返回 1,表示出现了错误。

动态内存分配

lpServices = malloc(0xE0005E0);:分配一块内存(约 14,000,000 字节),用于存储服务信息。

v2 = lpServices;:将分配的内存地址赋值给 v2,方便后续使用。

ServicesReturned = 0;:初始化 ServicesReturned变量,可能用于存储返回的服务数量。

检查内存分配

if (lpServices):检查lpServices是否成功分配内存。

●如果成功,初始化 pcBytesNeededResumeHandle为 0,这些变量可能在后续处理中用于存储服务信息或控制服务的恢复。

巧用AI回溯海莲花APT样本释放过程

检测 BIOS 序列号中是否包含与虚拟机相关的程序。通过比较 BIOS 序列号中的特定字符串来判断当前环境是否为虚拟机。如果发现与虚拟化相关的字符串,程序会执行相应的清理和处理操作。

获取 BIOS 序列号

●代码的第一部分通过调用一个函数(可能是某种 COM 接口)来获取 BIOS 序列号。这个函数的调用使用了一个函数指针,具体�参数包括字符串L"SerialNumber",指向pvarg的指针等,函数返回值大于0表示成功获取。

检查获取的值

if (pvarg.vt == 8 ...):检查 pvargvt(变量类型)是否为8。在 COM 中,类型8通常表示BSTR类型(字符串)。

StrStrIW(pvarg.bstrVal, L"VMware"):使用 StrStrIW函数检查 pvarg.bstrVal是否包含字符串 "VMware"。

*pvarg.plVal == 48:检查 pvarg.plVal指向的值是否为48(可能表示某种状态或标识)。

StrStrIW(pvarg.bstrVal, L"Xen")StrStrIW(pvarg.bstrVal, L"Virtual")StrStrIW(pvarg.bstrVal, L"A M I"):继续检查其他与虚拟化相关的字符串。

虚拟机检测逻辑

●如果上述条件之一为真,则表示检测到该系统正在运行在虚拟机中(如VMware、Xen、某些虚拟化平台等)。

●在检测到虚拟机后,调用 VariantClear(&pvarg);清理pvarg变量,释放任何占用的资源。

●然后调用一个函数(从 v10指向的对象中获取)来执行某些操作,可能是为了处理虚拟机检测后的逻辑,设置v0 = 1;表示发现虚拟机。

清理和结束

●在条件判断的外部,再次调用 VariantClear(&pvarg);,确保无论如何都清理资源。

●继续处理后续逻辑。

巧用AI回溯海莲花APT样本释放过程

通过执行 WMI 查询来检测计算机的模型信息,以识别是否在虚拟机环境中运行。通过比较模型名称中的特定字符串,程序能够检测出多个虚拟化平台。

如果发现与虚拟化相关的字符串,程序将执行相应的清理和处理操作。

执行 WMI 查询

●代码的第一部分调用一个函数(可能是某种 COM 接口)来获取计算机系统模型的信息。此处使用的字符串为L"Model",表示从Win32_ComputerSystem类中获取计算机的型号信息。

(*(int (__fastcall **)(...))(*(_QWORD *)v10 + 32i64)):这是一个函数指针调用,指向一个执行 WMI 查询的函数,返回值大于或等于0表示成功获取数据。

检查返回的值

if (pvarg.vt == 8 ...):检查 pvargvt(变量类型)是否为8,表示 BSTR类型(字符串)。

StrStrIW(pvarg.bstrVal, L"VirtualBox"):检查 pvarg.bstrVal中是否包含字符串 "VirtualBox"。

StrStrIW(pvarg.bstrVal, L"HVM domU"):检查是否包含 "HVM domU"(这通常与 Xen 虚拟化相关)。

StrStrIW(pvarg.bstrVal, L"VMware"):检查是否包含 "VMware"。

虚拟机检测逻辑

●如果上述条件之一为真,表示检测到该系统正在运行在虚拟机中(如VirtualBox、Xen 或 VMware)。

●在检测到虚拟机后,调用 VariantClear(&pvarg);清理pvarg变量,释放占用的资源。

●然后调用一个函数(从 v10指向的对象中获取)来执行某些操作,可能是为了处理虚拟机检测后的逻辑,设置v0 = 1;表示发现虚拟机。

清理和结束

VariantClear(&pvarg);在条件判断的外部再次调用,确保无论如何都清理资源,防止内存泄漏。

巧用AI回溯海莲花APT样本释放过程

通过执行 WMI 查询来获取系统的内存和连接器信息。如果任何查询失败,程序将进入一个无限循环,持续等待,直到其他条件或外部因素改变程序的执行状态。

执行 WMI 查询

●每个 if语句都调用 sub_140000C040函数,传递一个 SQL 查询字符串(例如,L"SELECT * FROM Win32_CacheMemory")。这个函数的目的可能是执行 WMI 查询,获取相关的系统信息。

检查查询结果

!(unsigned int)sub_140000C040(...):如果该函数返回的值为假(通常表示查询失败或没有结果),则进入相应的循环。

●该函数返回的值被强制转换为 unsigned int,使用逻辑非运算符 !进行检测。

无限循环和延迟

●如果查询失败,就进入一个无限循环 while (1),在该循环内调用 Sleep(0x9C40u);。这个调用会使当前线程休眠约 40,000 毫秒(或 40 秒),然后再次检查条件。

●由于是无限循环,程序在此处将无法继续执行其他代码,直到条件变为真。

查询的各个对象

●代码中分别查询了多个 WMI 类:

Win32_CacheMemory:表示系统中缓存内存的相关信息。

Win32_PhysicalMemory:表示物理内存的信息。

Win32_MemoryDevice:表示内存设备的信息。

Win32_MemoryArray:表示内存数组的信息。

Win32_PortConnector:表示端口连接器的信息。

巧用AI回溯海莲花APT样本释放过程

通过访问系统注册表中与虚拟化相关的键值,检测当前系统是否在虚拟机环境中运行。通过检查特定的注册表键和子键,程序能够识别出常见的虚拟化平台(例如 VirtualBox、VMware 等)。

注册表查询

●代码通过 RegOpenKeyExW打开 Windows 注册表中的特定键以获取与虚拟机相关的信息。主要路径为 HKEY_LOCAL_MACHINESystemCurrentControlSetServicesDiskEnum,这是存储有关磁盘驱动程序的信息的位置。

检测虚拟机类型

v403数组中定义了一些常见虚拟机的标识符,如 qemuvmwarevbox(VirtualBox)、xenVMVirtual。这些字符串用于后续比较,以检测当前系统是否运行在虚拟机中。

计数和循环

●使用 RegQueryValueExW函数查询 Count值,获取可能的磁盘数量。然后通过遍历 pcBuffer,对每一个可能的磁盘进行检测。

遍历子键

●代码定义了一系列与 VirtualBox 相关的注册表子键。这些子键主要包含与 VirtualBox 相关的 ACPI 和服务信息。

●在 do循环中,尝试打开每一个子键,检查是否存在以确认系统是否在虚拟机环境中运行。

错误处理

●如果在打开注册表键时发生错误(返回值为假),则使用 RegCloseKey关闭打开的键,并跳转到LABEL_725,可能是进行清理或其他后续操作。

巧用AI回溯海莲花APT样本释放过程

巧用AI回溯海莲花APT样本释放过程

通过打开与 VirtualBox 相关的管道和设备,检测当前系统是否在运行 VirtualBox 虚拟机。通过查找 VirtualBox 相关的窗口,程序可以进一步确认虚拟机的状态。

打开虚拟机管道

●代码定义了一个lpFileName数组,包含了一些与 VirtualBox 相关的命名管道和设备名称。例如:

\.VBoxMiniRdrDN

\.VBoxGuest

\.pipeVBoxMiniRdr

\.VBoxTrayIPC

●这些名称是 VirtualBox 在宿主机和虚拟机之间进行通信和数据传输时使用的。

创建文件句柄

●在 do循环中,代码尝试通过 CreateFile函数打开这些命名管道和设备。参数 0x80000000表示以只读方式打开,1表示共享模式,其他参数用于指定安全属性和创建方式。

●如果 CreateFile成功(返回的句柄不是 INVALID_HANDLE_VALUE),则关闭该句柄并将MEMORY[0]设置为 10。这可能是用于记录成功打开的管道数量或状态。

查找窗口

FindWindow函数用于查找与 VirtualBox 相关的窗口,分别使用 VBoxTrayToolWndClassVBoxTrayToolWnd作为窗口类名和窗口标题。

●如果找到任何一个窗口,则进入一个无限循环,调用 Sleep(0x7Bu);休眠约 123 毫秒。这样的设计可能是为了等待某个状态或事件。

无限循环

●如果找到 VirtualBox 的窗口,代码将会在无限循环中停留,可能是为了防止程序继续执行,保持在这个状态下。

巧用AI回溯海莲花APT样本释放过程

检测 vboxservice.exevboxtray.exe这两个进程是否在运行,并通过 WMI 查询获取系统中与 PnP 设备相关的信息。通过调用 WMI 查询和检查这些进程,程序可能用于安全监测或虚拟机环境检测,判断当前系统的状态。

检测进程

psz2数组包含两个字符串,分别为 vboxservice.exevboxtray.exe,这两个进程是 VirtualBox 的组件,分别用于管理虚拟机服务和托盘图标。

循环调用

do循环中调用 sub_140000E0A0函数,传递 psz2数组中的每个进程名称。这个函数的具体实现没有展示,但其目的是可能用来检测这些进程是否在运行。

初始化变量

dwSize, phkResult, 和 v217被初始化为0,这可能是为后续的注册表或 WMI 查询做准备。

WMI 查询

●使用 sub_140000E1C0函数尝试获取 WMI 的 ROOT\CIMV2命名空间的句柄。这个函数的返回值决定了后续代码是否执行。

SysAllocString被用来分配 WQL 查询字符串(SELECT * FROM Win32_PnPEntity),这个查询用于获取所有与 PnP(即即插即用)设备相关的信息。

条件检查和调用

●检查 v218v219是否成功分配内存。

●如果 v219不为 NULL,则通过一个函数指针调用执行 WMI 查询的函数。这个函数指针是通过 (*(_QWORD *)dwSize + 160i64)取得的,表示在dwSize指向的某个结构体中的偏移地址为 160的函数。

错误处理

●如果函数调用的返回值小于 0,则表示出现错误,后续处理逻辑可能在此处实现(虽然具体的错误处理代码在这里未显示)。

巧用AI回溯海莲花APT样本释放过程

识别虚拟机环境中的特定特征,尤其是 VirtualBox 相关的特征。通过使用无限循环和Sleep函数,程序可以在满足某些条件时保持挂起状态,从而防止代码被进一步执行或分析。此类技术常见用于检测和规避虚拟机环境。

函数调用

●代码中有多个 sub_xxxxxxx函数调用,这些函数的具体实现没有给出,但它们的返回值被用于判断是否进入后续的无限循环。这些函数可能用于检测某些特定的环境特征,尤其是与 VirtualBox 相关的特征。

无限循环

●每个 if语句后面都有一个无限循环,使用 Sleep(0x9C40u)来使线程休眠(大约 40000 毫秒,即 40 秒)。这种设计通常用于在检测到特定条件时阻止进一步的代码执行。

●这可能是为了防止代码在虚拟环境中执行,或者是为了在检测到虚拟机相关的条件时保持一个挂起状态。

检测特征

●每个 sub_14000CFF0sub_14000D6E0sub_14000D220sub_14000D450sub_14000CB60可能都与特定的虚拟机特征或状态检测有关。这些特征可能包括正在运行的进程、特定的设备或其他环境变量。

目的

●这段代码的主要目的是检测当前执行环境是否为VirtualBox。通过对特定条件的检查,如果满足,程序将进入一个无限循环,从而停止进一步的执行。这种行为通常用于保护自身不被调试或分析。

巧用AI回溯海莲花APT样本释放过程

检测 VMware Tools 的安装状态,通过检查注册表中的特定键来确认 VMware 环境是否存在。通过调用 sub_14000DE80和注册表操作,识别虚拟环境进行某种自我保护机制。

变量初始化

v407数组包含了一些与 VMware 相关的字符串,主要是用于后续的注册表查询和匹配。例如,"VMWARE""SystemProductName""Identifier"

循环与条件检测

do循环中调用 sub_14000DE80函数,可能用于检查某个条件或状态,如果该条件返回真,则跳转到LABEL_725。这可能是用于检测是否在 VMware 环境中。

控制流

●通过 ++v231v230 += 3,循环的目的是逐步增加某些索引或指针,可能是为了遍历v407中的某些内容。

注册表查询

●在 while (v231 < 5);循环体中,dwSize被初始化为指向 VMware Tools 的注册表路径 "SOFTWARE\VMware, Inc.\VMware Tools"

RegOpenKeyExW函数用于打开 Windows 注册表中的指定键。它尝试打开指定的 VMware Tools 注册表项,并将返回的句柄存储在pcbBuffer中。

巧用AI回溯海莲花APT样本释放过程

识别 VMware 虚拟机环境,通过检查常见的虚拟机 MAC 地址来实现。结合 MAC 地址的匹配和可能的其他环境检测,以防止在虚拟机中被分析或调试。

MAC 地址初始化

v398数组中包含了多个与 VMware 相关的 MAC 地址字符串。这些地址是虚拟机中常见的 MAC 地址,通常用于识别虚拟环境。

●具体的 MAC 地址包括:

00:05:69

00:0c:29

00:1C:14

00:50:56

不明指针

unk_140013C88unk_140013CA8unk_140013CC8unk_140013CE8是一些不明确的指针,可能指向某些数据结构或函数。这些指针的具体类型和作用需要结合更多的上下文来理解。

循环结构

do...while循环调用 sub_14000DF70函数,传入 *v231v231可能是一个指向当前处理的 MAC 地址的指针或索引。

●在每次迭代中,v231增加 2,这可能意味着每次处理两个 MAC 地址。

--v230可能是用于控制循环的计数器,直到 v230变为 0 为止,结束循环。

功能目的

●该代码的主要目的可能是检测当前系统的 MAC 地址是否与 VMware 虚拟机的常见 MAC 地址匹配。

●函数 sub_14000DF70的具体实现没有给出,但可以推测它可能用于比较或验证 MAC 地址。

反虚拟化技术

●通过检测 MAC 地址,程序可能试图判断其运行环境是否为 VMware。如果检测到匹配的 MAC 地址,程序可能采取特定的行为,例如停止执行或进入错误处理。

巧用AI回溯海莲花APT样本释放过程

检测 VMware 虚拟机环境,通过检查进程和注册表项来判断当前的运行环境。通过检测进程VMSrvc.exeVMUSrvc.exe,程序试图识别是否在 VMware 环境中运行。注册表的检查进一步确认了虚拟机的存在,如果没有找到对应的注册表项,程序将退出。

进程名称初始化

●v381数组中包含了两个字符串,表示 VMware 的服务进程:

VMSrvc.exe

VMUSrvc.exe

●这些进程是 VMware 虚拟机在运行时常见的服务。

进程检测

do循环中调用 sub_14000E0A0函数,传入v381[v267],用于检测当前系统中是否存在这些进程。

●如果该函数返回真(即检测到进程存在),则进入一个无限循环,调用 Sleep(0x2B67u),这可能是为了挂起程序或降低 CPU 使用率。

循环控制

++v267用于控制迭代次数,确保检测两个进程(索引 0 和 1)。

while (v267 < 2);确保只检测这两个进程。

注册表查询

v268被初始化为0,接下来设置 dwSize为 VMware 注册表路径 "SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"

●在另一个 do循环中,使用 RegOpenKeyExW函数尝试打开指定的注册表键。如果打开注册表键失败(返回非零值),则调用RegCloseKey并退出程序。

异常处理

●如果没有找到预期的注册表项,程序将调用 exit(0),这意味着程序将正常退出,但可能并不是预期的行为。

巧用AI回溯海莲花APT样本释放过程

检测虚拟机环境,通过检查特定的服务注册表项来判断当前系统是否在虚拟机中运行。注册表中存在这些服务通常表明系统正在虚拟环境中运行,因此这段代码试图确认这一点。如果找不到任何服务,程序将退出。

服务名称初始化

●v395数组中包含了多个与虚拟机相关的服务路径,这些服务通常用于 VMware 或其他虚拟化技术的功能:

vioscsi

viostor

VirtIO-FS Service

VirtioSerial

BALLOON

BalloonService

netkvm

注册表检测

do循环遍历 v395数组,检查每个服务的注册表项是否存在。

RegOpenKeyExW函数用于打开注册表键,如果无法打开(即服务不存在),则调用RegCloseKey并退出程序(exit(1)),表示程序发现了虚拟机环境。

循环控制

++v287用于控制迭代,确保所有七个服务都被检查。

while (++v287 < 7);确保在检查完所有服务后退出循环。

内存操作

memset(pszDir, 0, 0x208ui64);用于清空pszDir,这可能是一个用于存储路径或目录的数组。

wcscpy(v424, L"Virtio-Win\");将字符串 "Virtio-Win\"复制到 v424,这可能是用于指定虚拟机驱动程序的路径。

memset(&v424[12], 0, 0x1F0ui64);清空 v424中从索引 12 开始的内存部分,可能是用于准备存储其他数据。

变量初始化

v289被初始化为0,可能是用于后续的逻辑或计数。

巧用AI回溯海莲花APT样本释放过程

它通过对输入数据(a2)与一个查找表(dword_140030AC0)进行多轮异或和位移操作,来生成一个密钥或哈希值初始化密钥。

变量初始化

●代码段中的变量 v2v15表示一系列的中间结果,通常用于加密或散列算法的计算。

数据来源

dword_140030AC0是一个数组或某种形式的数据源,可能是某种密钥、查找表或预定义的常量。

a2是一个输入数组,可能包含密钥或其他相关数据。

逻辑流程

●每一步都使用异或运算符(^)和位移操作(>>)来处理数据:

~LOBYTE(dword_140030AC0[ (unsigned __int8*)*a2])获取 dword_140030AC0中某个元素的低字节并取反。

^ a2[n]用于将输入数组中的相应字节与计算结果进行异或运算。

^ (vN >> 8)将当前的计算结果与之前的结果右移后再进行异或,形成一种链式计算。

循环与返回

●该段代码并没有显示的循环结构,但它在逐步处理输入数组的每个元素,最终返回一个计算结果。

return dword_140030AC0[ (unsigned __int8)(v15 ^ a2[15]) ];这一行返回了根据输入数组最后一个元素 a2[15]计算得到的结果。

巧用AI回溯海莲花APT样本释放过程

定义一组硬编码的值,用于与计算得到的密钥或哈希值进行比较,常用于安全性检查或防篡改措施。

数组初始化

v375是一个包含16 个 32 位无符号整数的数组,每个元素都被初始化为一个特定的十六进制值。

●这些值很可能是用于验证某种密钥或哈希值的硬编码常量。

硬编码值的用途

●这些硬编码的值通常用于比较,通过将计算得到的哈希值或密钥与这些值进行比较,来确定是否匹配。这样的设计常见于软件中,以防止未授权的访问或篡改。

LODWORD操作

LODWORD(pcbBuffer) = 0;pcbBuffer的低字(低32位)设置为 0。pcbBuffer可能是一个指针或一个结构体中的字段,这里将其清零可能是为了初始化或重置。

巧用AI回溯海莲花APT样本释放过程

从程序资源中加载名为 "ICONS" 的数据,并对其进行解密。解密使用了一个硬编码的密钥(存储在v411中)。使用 VirtualAlloc申请内存,利用 FindResourceWLoadResource加载资源,最后通过异或操作解密数据。

  1. 1.内存分配

VirtualAlloc(0i64, 0x100000ui64, 0x1000u, 4u);这行代码申请了一个 1MB 的内存块,可能用于存储解密后的数据。

v331 = VirtualAlloc(0i64, 2 * v329, 0x1000u, 4u);这行申请了一个内存块,其大小为 2 * v329,用于存储解密后的资源数据。

  1. 2.资源加载

FindResourceWLoadResource用于查找和加载名为 "ICONS" 的资源。ResourceW存储了资源句柄,Resource存储了加载的资源数据。

  1. 3.资源大小

v329 = SizeofResource(0i64, ResourceW);这行代码获取了资源的大小,并将其存储在 v329中。

  1. 4.解密过程

if ((unsigned int)v330 >> 2)这一条件检查v330的值(即资源的大小)是否大于0。

v334 = v331;该行初始化了指向已分配内存的指针v334

v335 = Resource - (_BYTE)v331;计算出资源数据和解密内存之间的偏移量。

●在do...while循环中,使用异或操作解密数据:*(v334 - 1) = *(DWORD *)((char *)v334 + v335 - 4) ^ *((DWORD *)v411 + v336);这一行从资源中读取数据并与密钥数据(存储在v411中)进行异或运算,解密后的数据被写入到 v334指向的内存中。

  1. 5.轮询解密

while (v332 < (unsigned int)v330 >> 2);循环条件判断,确保解密操作遍历所有数据。

巧用AI回溯海莲花APT样本释放过程

初始化一个包含常见调试和分析工具进程名的字符串数组,以便在运行时进行检测。

数组初始化

v402是一个字符串数组,包含了多个常见的调试和分析工具的进程名。

●这些工具包括调试器(如 OllyDbg 和 WinDBG)、资源监控工具(如 Process Hacker 和 Wireshark)、反汇编工具(如 IDA Pro)、以及内存修改工具(如 Cheat Engine)。

用途

●这些进程名的列举通常用于检测系统中是否存在这些工具,以防止程序被逆向工程或调试。

●这种检测逻辑在恶意软件和某些商业软件中非常常见,目的是增加对逆向工程的难度。

反分析机制

●在程序运行时,可能会通过查询系统进程列表,检查是否有与 v402中的进程名匹配的进程。如果发现有匹配项,程序可能会采取措施,例如退出、隐藏其行为或改变其执行路径。

●这种方法能够有效地阻止安全研究人员或攻击者分析程序的行为,从而保护软件的知识产权或防止恶意行为。

巧用AI回溯海莲花APT样本释放过程

将解密的数据写入到 %temp%1.msc文件中。通过打开文件、写入数据和关闭文件的步骤,确保数据的持久化。

文件名初始化

memset(FileName, 0, 0x104ui64);这行代码将FileName数组初始化为零,大小为 0x104(260字节),用于存储文件路径。

strcpy(v339, "1.msc");这行代码将字符串 "1.msc" 复制到 FileName中,表示要创建的文件名。

文件打开

v341 = fopen(FileName, "wb");这行代码以写入模式打开文件 1.msc。如果文件打开失败,程序将调用 exit(1);终止执行。

写入解密数据

fwrite(v333, v330, 1ui64, v341);这行代码将解密后的数据(存储在v333中,大小为 v330字节)写入到打开的文件中。

文件关闭

fclose(v342);关闭文件,确保所有数据都被写入并释放资源。

结构体初始化

StartupInfo.cb = 104;设置 StartupInfo结构体的 cb字段,可能用于后续创建进程或线程时的初始化。

memset(&StartupInfo.cb + 1, 0, 0, 100);这行代码似乎意图清空 StartupInfo结构体的其他部分,但写法有误,应该是清空从 cb + 1开始的 100 字节。

memset(&ProcessInformation, 0, sizeof(ProcessInformation));ProcessInformation结构体的所有字段初始化为零,以确保安全性。

字符编码转换

v343 = MultiByteToWideChar(0, 0, FileName, -1, 0);这行代码将 FileName从多字节字符转换为宽字符格式,可能用于后续的文件操作或进程创建。

巧用AI回溯海莲花APT样本释放过程

创建并执行 mmc.exe进程,这通常是 Windows 的管理控制台(Microsoft Management Console)。

内存分配

v347 = (WCHAR *)malloc(2i64 * ((int)v90 + 8));这行代码分配了一段内存,用于存储命令行字符串,长度为 2 * ((int)v90 + 8)字节。v90很可能是根据程序需要动态计算的值。

命令字符串设置

*(DWORD *)v347 = *(DWORD *)L"mmc.exe ";这行代码将字符串 "mmc.exe " 存储到 v347指向的内存中,表示要执行的程序。

v347[8] = aMmceExe[8];这行似乎是将某个字符数组的第 8 个元素赋值给 v347的第 8 个位置,具体含义取决于aMmceExe的内容。

字符串结束符处理

●通过 do...while循环,代码逐个检查字符,直到找到字符串的结束位置(即0),用于确保字符串正确终止。

启动进程

返回

return 0;表示程序正常结束。

巧用AI回溯海莲花APT样本释放过程

通过利用 MMC 的 XSS 漏洞,在加载特定的 MSC 文件时执行 JavaScript 代码。

字符串定义

●该 XML 片段是一个 StringTable,包含多个字符串定义。每个<String>标签都有一个唯一的 ID和可能的 Ref属性。

●字符串 ID 23, 24, 和 38 似乎是正常的字符串,可能在 MMC 界面中用作显示文本。

XSS 漏洞利用

●第 39 行的字符串内容是关键部分:res://apds.dll/redirect.html?target=javascript:eval(external.Document.ScopeNamespace.GetRoot().Name)

●这段代码利用了 apds.dll资源中的 redirect.html文件,并尝试通过 javascript:eval执行JavaScript 代码。

external.Document.ScopeNamespace.GetRoot().Name是 JavaScript 代码的一部分,目的是获取当前上下文中的某个对象的名称,可能用于执行额外的恶意操作。

攻击流程

●当受害者打开包含此字符串的 1.msc文件时,MMC 会处理这个字符串,并在其进程上下文中触发 JavaScript 执行。

●因此,攻击者可以通过这种方式在受害者的计算机上执行任意JavaScript 代码,而无需用户的明确同意。

潜在影响

●这种 XSS 漏洞的利用可能导致各种安全问题,包括数据泄露、权限提升或执行恶意软件等。

●利用 MMC 和相关组件的 XSS 漏洞,攻击者可以在不受保护的环境中进行攻击。

巧用AI回溯海莲花APT样本释放过程

js代码解密后获得vbs脚本。

巧用AI回溯海莲花APT样本释放过程

<?xml version="1.0"?><stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xsl" version="1.0"><output method="text"><m:s:script implements-prefix="user" language="VBScript"><![CDATA[Dim msCLmsCL = "v"For i = 1 To Len(msCL) Step 4    dLkFNuY = dLkFNuY &Chr(CLng(Chr(Int(&H48))) & Mid(msCL, i, 4))NextSet b7kyThoe = CreateObject(Chr(Int(&H77)) & Chr(Int(&H69)) &Chr(Int(&H99)) & Chr(Int(&H72)) & Chr(Int(&H115)) &Chr(Int(2184 - 2073)) & Chr(76) & Chr(3017 - 2949) & "O"& Chr(6337 - 6260))b7kyThoe.Async = Chr(&H46) & Chr(Int(&H97)) & Chr(Int(108))& Chr(&H73) & "e"b7kyThoe.Load(dLkFNuY)BIlVi9zozFunction y8Vfg0Xe2tXS(inp)    Dim queOtCPqwQ    Dim dOylnDqtmyt    Set queOtCPqwQ =CreateObject(Chr(&H4d) & "S" & Chr(1883 - 1806) & Chr(Int(&H4C))& Chr(&H32) & Chr(46) & Chr(Int(79)) & Chr(&H4d) &"D" & Chr(198024 / 1784) & Chr(Int(&H63)) & Chr(116)& Chr(Int(101)) & Chr(Int(116)) & Chr(-3327 + 3437) & Chr(116))    Set dOylnDqtmyt =queOtCPqwQ.CreateElement(Chr(Int(&H97)))    dOylnDqtmyt.DataType = Chr(&H62)& Chr(Int(&H69)) & "n" & Chr(Int(46)) & Chr(1980- 1882) & "a" & Chr(115) & "e" & Chr(54)& Chr(Int(52))    dOylnDqtmyt.Text = inp    y8Vfg0Xe2tXS =dOylnDqtmyt.nodeTypedValueEnd FunctionFunction BIlVi9zoz()    On Error Resume Next    Dim JEuh    Dim SmCZVCOO    Dim eUCZzUm1CEnd Function]]></m:s:script></output></stylesheet>

以下是基于您提供的 VBS 代码的逐步分析流程,结合代码中的具体实现,详细阐述每个步骤。

解密与加载远程XML资源

Dim msCLmsCL = "v"For i = 1 To Len(msCL) Step 4    dLkFNuY = dLkFNuY &Chr(CLng(Chr(Int(&H48))) &Mid(msCL, i, 4))Next

变量 msCL被初始化为字符串 "v"。接下来的 For 循环是为了构建字符串 dLkFNuY,虽然这段代码没有实现完整的解密逻辑,但它展示了如何从字符中提取信息。此步骤可能是为了准备后续步骤中使用的 URL 或文件路径。

文件夹创建与持久化

Setb7kyThoe = CreateObject(Chr(Int(&H77)) &Chr(Int(&H69)) &Chr(Int(&H99)) &Chr(Int(&H72)) &Chr(Int(&H115)) &Chr(Int(2184 - 2073)) &Chr(76) &Chr(3017 - 2949) &"O"&Chr(6337 - 6260))

此行代码使用 CreateObject方法创建一个新的COM 对象。通过 ChrInt函数组合不同的字符,以形成有效的对象名称。这种动态构建字符串的方式使得代码更难以分析。创建的对象可能是用于后续执行的关键组件,如文件处理、网络请求等。

文件释放

b7kyThoe.Async = Chr(&H46) &Chr(Int(&H97)) &Chr(Int(108))&Chr(&H73) &"e"b7kyThoe.Load(dLkFNuY)

b7kyThoe.Async属性被设置为某个值,通常用于控制对象的异步行为。Load方法接收之前构建的 dLkFNuY作为参数,意图加载一个文件或资源。此步骤将会释放和加载之前准备好的文件或脚本,可能是恶意的可执行文件或其他资源。

解码与执行

JEuh.run """%ProgramFiles%CloudflareWarp.exe""", 1, False

使用 WScript.Shell.run方法执行 Warp.exe文件。参数 1指定窗口样式,而 False则表示该操作是静默执行,不显示任何窗口。此步骤直接执行恶意程序,可能会导致主机感染或数据被盗取。

反检测机制

Functiony8Vfg0Xe2tXS(inp)    ...End Function

定义了一个名为 y8Vfg0Xe2tXS的函数,用于处理输入的文本并进行某种转换或解码。该函数创建了一个对象并设置其数据类型,最后将输入文本赋值给对象。该函数的实现可能用于混淆数据,增加分析难度,并有效地通过动态构造来避免静态分析的检测。

释放诱饵文件

SetqueOtCPqwQ = CreateObject(Chr(&H4d) &"S"&Chr(1883 - 1806) &Chr(Int(&H4C)) &Chr(&H32) &Chr(46) &Chr(Int(79))&Chr(&H4d) &"D"&Chr(198024 / 1784) &Chr(Int(&H63)) &Chr(116) &Chr(Int(101))&Chr(Int(116))&Chr(-3327+ 3437) &Chr(116))

创建了另一个对象,可能与处理文件或执行其他操作相关。这进一步说明了代码是如何通过构造复杂的字符串来达到目的。释放的文件中,Warp.exe可能是伪装成正常程序的恶意文件,而 7z.dll则可能是实际的恶意载荷。

最终释放的文件中,Warp.exe被伪装为正常文件,而 7z.dll则是经过混淆的恶意 DLL:经过分析,7z.dll被确认是CS远控木马,常用于进行网络攻击和渗透测试。分析还显示其 C2 服务器为 sz-everstart.com,与海莲花 APT 组织相关,进一步表明该恶意软件的严重性。

巧用AI回溯海莲花APT样本释放过程

4

Gepetto的作用

在本次分析过程中,Gepetto插件主要提供了以下辅助功能:

  1. 1.函数自动解释

●例如,在分析 LoadResourceData函数时,Gepetto提供了详细解释,显示它用于加载 ICONS资源,并解密 1.msc

  1. 2.变量重命名

●使代码更易理解,如 var_1可能被优化为 DecryptionKey

  1. 3.关键路径标识

●帮助快速锁定 mmc.exe触发 JS代码的关键路径。

5

总结

利用Gepetto插件结合静态分析技术,可以更高效地回溯海莲花APT攻击流程。通过AI辅助分析,研究人员能够快速理解复杂样本的攻击逻辑,提升安全响应能力。未来,我们可以进一步优化大模型的应用场景,如结合动态调试,提高APT攻击分析的自动化水平。

SetHandleInformation(MutexW, 2u, 2u)

:设置互斥体句柄的属性。

●第一个参数是句柄。

●第二个参数 2u表示要设置的信息类型(在这里通常表示句柄的标志)。

●第三个参数 2u是要设置的值。

(*(int (__fastcall **)(unsigned __int64,OLECHAR *, BSTR, __int64, __QWORD, __int64 *))

:这里使用了函数指针调用的方式,调用 WMI API 进行查询。传入的参数包括:

v17:表示 WMI 对象。

v1:表示查询语言。

v2:表示查询内容。

v3:可能是查询的其他参数。

481i64:一个常数,具体含义需要上下文。

&v16:用于接收查询结果的指针。

CreateProcessW(0i64, v347, 0i64, 0i64,0i64, &StartupInfo, &ProcessInformation);

这行代码调用 Windows APICreateProcessW启动mmc.exe程序。传入的参数包括:

0i64表示应用程序的模块名(这里是 mmc.exe)。

v347是包含命令行参数的字符串。

●其他参数设置为 0,表示默认行为。

&StartupInfo&ProcessInformation是结构体,用于接收进程启动的相关信息。

6

李白你好网安社区V1.0上线

李白你好VIP社区-数据泄露监测引擎
https://www.libaisec.com/
网络安全行业最全的资源站、全网最好的网安社区、在这里你可以找到百分之90的网安资源!欢迎注册尝鲜~

巧用AI回溯海莲花APT样本释放过程

7

往期精彩

巧用AI回溯海莲花APT样本释放过程

网络安全情报攻防站V1.0 正式上线【网空数据泄露监测引擎抢先限时免费用】 !!!

巧用AI回溯海莲花APT样本释放过程
某开源OA白名单后缀限制下巧用系统设计getshell

巧用AI回溯海莲花APT样本释放过程

内网横向扩大战果,RDP远程桌面密码凭证获取

原文始发于微信公众号(云淡纤尘):巧用AI回溯海莲花APT样本释放过程

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月4日14:12:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   巧用AI回溯海莲花APT样本释放过程https://cn-sec.com/archives/3794052.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息