最近,在SAS会议上,我谈到了“时髦恶意软件格式”- 仅由专有加载器加载的恶意软件使用的可执行格式。恶意软件作者使用它们才能使静态检测更加困难,因为自定义格式不会被AV扫描仪识别为可执行文件。
使用非典型格式也可能会减慢分析过程,因为无法通过典型工具将文件从框中解析出来。相反,我们需要写自定义加载器为了自由分析它们。
去年,我们描述了一种这样的格式关于隐藏蜜蜂的帖子。这次,我们想向您介绍在SAS会议上讨论的另一个案例。它是海洋莲花的样本,也称为APT 32,是与越南相关的威胁组。
样本
49A2505D54C83A65BB4D716A27438ED8F065C709.- 主要可执行文件
特别感谢Minh-Triet Pham Tran提供材料。
概述
该示例包含两个元素—blob和cab—它们都是以相同的未知格式执行的。自定义格式是通过从PE格式转换来实现的(我们可以通过观察一些典型的PE文件工件来猜测它,即manifest)。然而,头部是完全自定义的,并且它的加载方式与PE不相似。典型PE中的一些信息(例如,节的布局)没有保留:节被打乱了。
起源
这个样品是2017年6月10日的,来自以下邮件:
标题“SổTayVấnđềPháplýchocácnhàcnạtđộngnhânquyền”转换为:“人权活动家的法律问题手册。”它是针对越南活动家的矛网络钓鱼活动的主题行。
恶意样本作为附件交付给电子邮件:压缩可执行文件。图标试图模仿PDF(Foxitpdf Reader)。
行为分析
运行后,将样本复制到%TEMP%,解压缩并启动诱饵PDF。
虽然用户正忙于阅读推出的文档,但下降器解压缩真正的有效载荷。它被删除了C:\ programdata \ Microsoft帮助:
之后删除Dropper可执行文件。
恶意软件管理以默认级别绕过UAC。我们可以看到申请sporder.exe跑步升高的特权。
持久性由一个简单的运行密钥提供,导致丢弃的脚本:
有趣的因素是,样本有一个“到期日”,之后安装人员不再运行。
内部
主要可执行的sporder.exe与UPX打包。它导入dll sporder.dll:
sporder.dll导入另一个丢弃的dll,HP6000.dll.:
但是,密钥恶意软件功能由任何丢弃的PE文件提供。它们刚用作装载机。
事实证明,核心隐藏在两个未知的文件中:Blob和Cab。
自定义格式
扩展名为BLOB和CAB的文件用XOR混淆。解码后,我们注意到一些可读的代码串。然而,它们都不是有效的PE文件,我们也找不到任何典型的头文件。
斑点
blob文件由xor混淆。我们可以看到重复模式并将其用作XOR键:
结果,我们得到以下清晰版本:2E68AFAE82C1C299E886AB0B6B185658
Blob的标题:
Blob文件看起来像一个已处理的PE文件,但其部分似乎是交换顺序。第一部分似乎是.data,而不是.text。
我们可以看到来自的可见伪像Bzip库和C ++标准库。
出租车
CAB文件以类似的方式与XOR混淆,但具有不同的键:
当我们应用密钥时,我们得到一个类似的清晰版本:B3F9A8ADF0929B2A37DB7B396D231110
此示例还具有自定义标题,它不会类似于PE标题。但是,我们发现内部的部分是PE文件的典型,例如清单。
装载机
事实证明,两个文件都由HP6000.dll加载:67年b8d21e79018f1ab1b31e1aba16d201
加载函数以混淆方式执行:执行DLLMain时,它会修补加载DLL的主要可执行文件。
首先,检索当前模块的文件名。然后,读取文件并获取入口点的地址。然后,将在内存中加载的模块设置为可执行文件:
最后,修补字节,以便输入点将重定向到加载DLL中的相应功能:
这就是应用程序修补程序后主模块的入口点如何关注:
我们看到DLL内函数的虚拟地址(RVA 0x1210 + DLL加载基础)移动到EAx,然后将EAx用作跳转目标。
从RVA 0x1210开始的功能是Blob和Cab的装载机:
这个重定向是有效的,因为当可执行文件被加载到内存中时,在主模块的Entry Point被命中之前,它的Import Table中的所有dll都会被加载,并且每个dll的DllMain都会被调用。加载dll之后,就开始执行主可执行文件。在我们的例子中,修补过的入口点重定向回DLL。
加载BLOB和CAB的函数内部:
如你所见,CAB文件首先被加载:
此外,我们看到此功能检索某些环境变量。此变量用于存储应用程序的状态,并在连续的执行之间共享。根据此状态,可以采取多个执行路径中的一个。
通过连接创建变量的名称:
- 硬编码字符串:l“本地\\ {076b1db0-2c01-45a5-bd0a-0cf5d6410dcb}”
- 可执行文件的名称
- 本地用户名
内容变量可以是' @ ',' * ',':'。如果为空,则设置第一个值“@”。这些变量被转换为控制流的特定状态。
- '@' - >状态1
- ' * ' ->状态2
- ': ' ->状态3
主要过程在每个状态更改上重新启动。最后,状态3创建互斥锁并使用BLOB扩展加载文件。
互斥锁名称与变量名称相同,但使用后缀“_m”添加:
当应用程序运行时,我们可以看到BLOB在主模块的内存中以可执行的形式加载:
通过比较加载在内存中的格式和存储在磁盘上的格式,我们可以看到,在加载过程中跳过了BLOB的开始和结束。因此,我们可以猜测,这些部分是一些头文件,包含加载所需的信息,但不包含执行所需的信息。位于文件开头的头文件将被引用为Header1,位于文件末尾(footer)的头文件将被引用为Header2。
Memory中的Header2文件与其等效于磁盘:
我们还发现重新安置了一些地址(添加了新的图像基础)。
反转反转PE
具有扩展速度驾驶室和BLOB的文件由相同的功能加载:
装载机的核心处于以下功能:
这是我们需要分析的函数,以便从自定义格式中进行意识。
让我们来看看加载过程本身。
头部的第一个DWORD是校验和(稍后将用于验证解码模块)。然后,我们有两个用作XOR键的DWORD。一旦它们被获取,标题的其余部分被解码。
应用键后,我们以其清晰的形式获得文件的内容。但在模块继续加载之前,必须将头文件中的校验和与实际校验和进行比较,并使用自定义公式进行计算:
来自标题的下一个值用于计算用于加载模块的可执行部分的大小。在目前分析的情况下(驾驶室文件),它是0x17000:
因此,0x17000 + 0x2000是将为有效载荷分配的内存的大小。
示例(来自CAB文件):
然后,复制负载的0x17000字节,但是跳过包含Header1的开始部分(前16字节)。
复制模块内容后,Header2用于继续加载。
看看Header2,我们可以看到一些与Header1的相似之处。
初始DWORD是模块(DllMain)的入口点。它将在完整模块加载后很快加载:
然后,我们有一个值在计算要分配的存储器大小的公式中使用的值。正在分配此时间的新存储区域用于将加载的导入(将进一步解释完整过程)。
从概念上讲,我们可以将Header 2分为两部分。
首先是包含两个DWORD值的序言。来自当前分析的CAB文件的示例:
- val [0] = 0x21a0 - > dllmain的RVA
- val [1] = 0x013d - > val [1] * 8 + 0x400 - >下一个区域的大小分配
然后有自定义类型的记录列表。每个记录代表加载模块所需的不同信息。它们由由记录开头的DWORD表示的类型ID标识。
搬迁
类型1代表搬迁。它有一个DWORD作为参数。这是一个需要重新安置的地址。
typedef struct {dword reloc_field;} Reloc_t;
我们可以看到该字段如何用于重新定位地址。示例:在0x8590填写地址:
出口
2类型代表导出功能。尖头地址存储在列表上,以便在加载完成后稍后调用。此记录有三个DWORD参数。
typedef struct {
DWORD计数;
DWORD entry_rva;
dword name_rva;
} entry_point_t;
类型2的记录示例:
存储地址:params[1] = 0x00001030
通过观察执行流程,我们可以确认在加载过程完成后正在调用存储的函数:
导出的功能可以与他们的名称一起存储。
进口
类型3代表进口。它有四个dword参数。
typedef struct {
DWORD类型;
dword dll_rva;
dword func_rva;
DWORD IAT_RVA;
import_t;
负责编码导入的块示例:
类型:params [0] = 0x00000002 - 表示函数将按名称导入,含义本记录的所有可能类型。
DLL的地址:params [1] = 0x0107da
导入地址:params[2] = 0x010774
与PE格式相比,导入函数的地址未加载到主模块中。相反,它被写入单独的可执行区域(在给定的示例中,它写入VA:0x00240001):
然后,填充导入的地址填写在主模块中。需要填充的主模块中的地址由此记录的最后一个参数指定。在给定的示例中,块[3] = 0x0000E014填充0x00240001:
非典型IAT.
嵌入式列表中的函数用于加载器,但是,如前所述,地址不会填充在正常IAT中,典型的PE格式。相反,所有都填写为存储在新分配的内存页面中的跳转列表。
import loading函数不仅填满地址,还发出必要的跳转代码:
类型字段的含义
导入记录具有字段类型,可以具有以下值之一:1,2,3,4。
1和2是最重要的:它们用于加载导入。1表示按序号装载,2表示按名称装载。剩下的3和4用于清除不再需要的字段。3擦除导入名称,4擦除DLL名称。
当发生类型3或4的记录时,IAT区域中的指针仍递增,因此我们可以在函数记录之间看到一些间隙:
自定义文件的功能
CAB文件是另一个安装程序,通过创建服务来为整个包提供持久性:
“c:\ windows \ system32 \ wscript.exe”/ b / nologo“c:\ users \ tester \ desktop \ mod \ sporder.vbs”
我还生成丢弃的vbs脚本:
首先加载CAB文件,只是为了安装恶意软件,然后删除。
所有的间谍相关功能由稍后加载的BLOB执行,并在加载器的内存中保持持久性。
除了以自定义格式而言,Blob也很大困扰。
我们可以观察其连接到其中一个CNC的尝试:
png.eirahrlichmann.com.AndyChroEder.com:9091 png.eirahrlichmann.com:3389
其中一些域从以前的Ocean Lotus报告中已经知道,例如[天空白皮书]。
海洋莲花:创意APT
海洋莲花经常让研究人员惊喜,具有创造性的混淆技术。最近,发现使用隐写术来隐藏其可执行文件的不同样本(您可以阅读更多信息以下是网站ThreatVector的报道).我们所描述的这种形式只是其中一种不寻常的植入方式。
附录
解析器的描述格式:https://github.com/hasherezade/funky_malware_formats/tree/master/lotus_parser
SAS会议的介绍:
评论