有时,当你对海量的恶意软件检测结果进行分析时,你可能并不希望一些看似无关痛痒的小细节会对最终的判定造成影响。
前不久,我因为将遇到的恶意软件误认为 Arkei(一款功能强大的窃密木马)而付出了代价。根据当时我设置的Yara规则,显示匹配到的是 Arkei,但是经过逆向分析之后,我发现遇到的这个恶意软件并非Arkei。一些与Arkei特征相关的字符串都被删除了,取而代之的是“Vidar”。经过深度分析后,我发现 它是由Arkei优化改进得到的,除了一些细节之外,其他部分和Arkei区别不大。
这款恶意软件使用C++编写,似乎在2018年10月初就已经开始活动,它具有窃取木马的所有典型功能:
在黑市/论坛中,这款窃密木马以250-700美元的价格进行出售。购买后,可以通过访问C2域名来生成专属的payload,所以没有统一管理端。除此之外,C2域名每4天就会进行更新。
在本文中,我将对4.1版本的Vidar进行深入分析,并介绍其管理面板,说明它和Arkei的差异。
首先,如果受害者机器使用GetUserDefaultLocaleName来配置语言,我们可以使用很经典的方式(改变系统语言)来中止恶意软件。这也是检查恶意软件是否不会对一些特定的国家/地区进行感染最简单的办法之一。
正如MSDN所声明的,“local”中以集合的方式展示用户的语言偏好。窃密软件将检查被入侵主机的是否设置为以下语言:
谷歌一下,我们就能知道这是哪些哪些国家/地区的简称:
LCID Structure – https://msdn.microsoft.com/en-us/library/cc233968.aspx
Language Code Table – http://www.lingoes.net/en/translator/langcode.htm
LocaleName – https://docs.microsoft.com/fr-fr/windows/desktop/Intl/locale-names
Locale – https://docs.microsoft.com/fr-fr/windows/desktop/Intl/locales-and-languages
对于每个受害者,Vidar将生成唯一的特征字符串。它的形成很简单,就是由2个字符串拼接后得到的。
硬件配置ID
GetCurrentHwProfileA用于检索具有szHwProfileGuid值的计算机的当前硬件配置信息。如果执行失败,它将返回“Unknown”。
计算机GUID
通过RegOpenKeyExA,可以在注册表中获取该值:HKEY_LOCAL_MACHINESOFTWAREMicrosoftCryptographyMachineGuid
Windows在安装操作系统时会生成UUID。
以上操作完成后,将生成互斥体,如下图所示:
当Vidar执行main函数时,会先驻存一些必要的字符串,以便后续步骤的正常进行。
当所有字符串的RVA(相对虚拟地址)都存储在.data中后,恶意软件将访问被请求的字符串。
这种做法会给静态分析带来一些难度,但影响不大。
当builder在受害主机生成恶意软件时,随之会硬编码一个唯一ID。在恶意域名上输入该ID,将检索出攻击者想要从受害者计算机上窃取到的指定配置信息。
如下图,展示的是Profile ID为“178”的感染计算机,如果恶意软件没有进行配置,那么其Profile ID默认为“1”。
C2域名只是简单的进行了异或操作。只需要使用异或函数就可以解密出原始数据。
解密可以得到C2域名为“newagenias.com”。
可以使用我GItHub仓库中的脚本izanami.py来完成配置信息的提取。
以下是恶意软件可以从C2获取的默认配置信息:
1,1,1,1,1,1,1,1,1,1,250,Default;%DESKTOP%;*.txt:*.dat:*wallet*.*:*2fa*.*:*backup*.*:*code*.*:*password*.*:*auth*.*:*google*.*:*utc*.*:*UTC*.*:*crypt*.*:*key*.*;50;true;movies:music:mp3;
我使用”;”来区分各个部分,下面是各部分的解释说明:
第一部分
第二部分
第三部分
*.txt:*.dat:*wallet*.*:*2fa*.*:*backup*.*:*code*.*:*password*.*:*auth*.*:*google*.*:*utc*.*:*UTC*.*:*crypt*.*:*key*.*
第四部分
第五部分
movies:music:mp3;
这是一个特殊的部分,在Grabber递归的检索指定文件夹时,以上文件将会直接过滤。
如果直接看代码,这些设置显得很混乱,因为每个变量都存储在byte或dword变量中。
总结一下Vidar可能生成的的文件/文件夹,如下:
\files <- 主文件夹
\files\Autofill <- 自动填充文件
\files\CC <- 信用卡
\files\Cookies <- Cookies
\files\Downloads <- 浏览区下载记录
\files\Files <- 通用配置
\files\History <- 浏览器历史记录
\files\Soft <- 目标软件的主文件夹
\files\Soft\Authy <- 2FA软件
\files\Telegram <- Telegram消息
\files\Wallets <- 加密货币钱包
通用文件:
\filesscreenshot.jpg <- 实时屏幕截图
\filespasswords.txt <- 整合后的密码
\files\information.txt <- 计算机设置 快照
每当我阅读恶意软件说明时,我总希望不需要安装库文件或其他插件,双击该恶意软件就可以直接运行。然而对代码进行深入研究或分析通信数据流,会发现它还是需要下载一些DLL文件以便完成特定的功能。
基于这种情况,针对不同的浏览器,在窃取信息时需要下载以下文件。
执行完成后,这些文件就会被删除。
Vidar支持对以下FTP软件信息的窃取。
我发现Vidar对2FA软件是有针对性的窃密,这种功能并不常见。但可以肯定的是这种情况会越来越普遍。随着各种防护措施的出现,用户需要明白带有2FA并不代表账户就一定安全,这也可能为漏洞的出现开启了另一扇门。
因此,Vidar将认证软件作为了目标……
因为大部分SQLite 文件存放在%APPDATA% 目录下,所以看起来窃密软件想要从那里窃取Discord及Chrome等软件的数据信息。
所以小伙伴们,不要对你的2FA软件掉以轻心。
需要注意的事,Vidar对Tor浏览器也有效。
以下浏览器中的信息将会被窃取:
如果浏览器是基于chromium引擎,那么需要重视起来。
在本文中,我不会介绍这些技术如何实现,因为在我以前的博文中曾对相关技术进行过说明(特别是Telegram部分)。
当然,如果攻击者指定了其他文件夹,对受害者机器特定区域进行搜索,那么这个名单会持续增加下去。
介绍到现在,Grabber可以说是Vidar功能最复杂的模块,也是它在实现上与Arkei区别最大的部分。
首先,它会根据已下载的配置文件来选择是否启用Grabber模块。如果该选项被激活,那它将生成文件夹路径字符串并设置func_grabber何时被调用。
在分析到func_grabber时,现实比我想象的残酷一些:
看到这个,我的内心是拒绝的。我的脑海中已经大概想到了它是如何分配内存的。然而摆在我面前的的是所有恶意软件分析师都想挑战(或者根本不想遇到)的融合了多种技巧的恶意模块:
但实际上,它并没有预想中那么复杂。接下来我会举一个例子进行说明。
在下面的示例中,如果从C2下载的配置文件中存在“%APPDATA%”字符串。它将跳转进入该功能,并进行一系列验证,直到进入最重要的func_VidarSearchFile函数。
在不同的场景下,几乎都会执行以上过程。
以下是Grabber模块可能用到的目录:
屏幕截图功能的实现很简单:
然后使用一个DC对象来创建生成图像所需的兼容位图,通过选择兼容memory DC并使用Bit Block API函数来完成数据传输。完成这些操作后,将进入func_GdipSaveImageToFile函数。
最后从生成的位图中将数据复制到一个缓冲区中,在缓冲区中生成生成屏幕截图。
在这部分中,我只对如何生成日志进行了分析,其他的是一些相关API的调用,通过设置断点跟踪,花一些时间,你也可以轻松的进行分析。
首先,它会说明这是哪个版本的Vidar。
如果你没有在日志文件中看到“Vidar”字符串,这意味着你分析的是之前的版本。
获取操作系统平台及版本时采用了很经典的组合,首先,使用RegOpenKeyExA来获取注册表项的值。
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsNTCurrentVersionProductName
接下来,会对运行的Windows环境为32位还是64位进行检测,该软件会通过IsWow64Process来检测自身是否运行在WOW64 下。
为了获得当前用户所使用屏幕的分辨率。将通过调用CreateDCA来为“Display”创建设备环境,并使用GetDeviceCaps来获取屏幕的长度和宽度。
这部分的源代码如下:
HDC hDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
int width = GetDeviceCaps(hDC, HORZRES); // HORZRES = 0x8
int height = GetDeviceCaps(hDC, VERTRES); // VERTRES = 0x0A
继续进行分析,得到:
在下一部分,将继续针对Vidar的通信、Loader、Killing、管理面板等模块进行介绍,敬请期待…