带有“天堂之门”的矿工病毒

大家好! 预期在逆向工程课程中将有新的流派开始,我们正在与您分享非常有趣的材料的翻译。 享受阅读




最近两年可以称为勒索软件黑客的年份。 毫无疑问,勒索软件是最受欢迎的恶意软件类型。 但是,在去年年底,我们开始观察到他们的受欢迎程度下降,并且对矿工的支持增加。 这种趋势有可能在2018年只会增长。

从受害者的角度来看,这是一种解脱,因为矿工没有勒索软件那么危险。 是的,它们会降低系统速度,但是一旦您摆脱它们,便可以像以前一样继续使用计算机。 您的数据不会像勒索软件病毒那样被盗或丢失。

从恶意软件研究人员的角度来看,矿工令人失望。 它们没有提供足够的新材料来进行更深入的分析,主要是因为它们基于众所周知的开放源代码组件,几乎没有混淆或隐蔽。

但是,我们不时发现使用有趣技巧的矿工。 我们最近观看了一种称为“天堂之门”的技术,该技术允许从32位引导加载程序注入到64位进程中。 这个想法并不是什么新鲜事,它的第一个实现可以追溯到2009年,但是有趣的是,它是如何以一种新的形式实现的,可以直接从野外获得。

病毒分析初学者可以阅读有关什么是天堂之门以及如何进行分析的指南。

分析材料



这种模式是在Ngay运动的延续中找到的(在此处有更多信息 )。 查看此类样本的传记后,我看到了@_qaz_qaz 文章 ,该文章描述了具有类似样本的早期运动。 但是,他的分析不包括“天堂之门”技术。


行为分析


要查看所提到的注入,我们必须在64位系统上运行该示例。 我们看到它通过特定于加密货币挖掘的参数启动了笔记本的本质:



通过查看ProcessExplorer中的内存行,我们看到这不是真正的笔记本,而是XMRig Monero 矿工



因此,目前,我们确定内存中笔记本的图像很可能已被RunPE(过程镂空)方法所取代。

主删除器是32位的,但是将有效负载转移到了64位的笔记本电脑上:



最有趣的是,官方的Windows API不支持这种类型的注入。 我们可以从64位应用程序(使用WoW64 API)读取/写入32位进程的内存,但反之则不行。

但是,有一些非官方的解决方案,例如称为“天堂之门”的技术。

天堂之门评论


天堂之门技术最早是由一位绰号为Roy G.Biv的黑客于2009年描述的。 后来,创建了许多实现,例如Wow64ext库或基于它的W64oWoW64 。 Alex Ionescu在2015年的博客中描述了针对这项技术的措施
让我们看看它是如何工作的。

在64位Windows上运行32位进程


在64位版本的Windows上运行的每个32位进程都在模拟32位环境的特殊WoW64子系统上运行。 您可以使用在64位进程中创建的32位沙箱进行类比。 因此,首先,创建一个64位进程环境。 并且已经在其中创建了32位环境。 该应用程序在此32位环境中运行,但无法访问其64位部分。

如果我们使用64位扫描程序从外部扫描32位进程,则将看到内部具有32和64位DLL。 最重要的是,它具有两个版本的NTDLL:32位(从SysWow64目录加载)和64位(从System32目录加载):



但是,32位进程本身看不到64位部分,并且仅限于使用32位DLL。 要注入64位进程,您需要使用相应功能的64位版本。

代码段


要访问环境的受限部分,我们需要了解隔离是如何完成的。 事实证明,一切都非常简单。 可通过不同的代码段地址执行32位和64位代码执行:32位-0x23和64位-0x33。

如果我们以通常的方式调用该地址,则默认情况下会设置用于解释该地址的模式。 但是,我们可以使用汇编代码显式请求更改。

矿工内部:天堂之门的实现


我不会对这个矿工进行全面的分析,因为这里已经对此进行了描述。 让我们直接去有趣的地方。 该恶意程序检查其环境,并且如果检测到它在64位系统上运行,则使用另一种方式注入64位进程:



经过一些反分析检查后,它将创建一个新的暂停的64位进程(在本例中为记事本):



这是将要实施恶意负载的目标。
如前所述,为了将有效负载嵌入到64位进程中,我们需要使用适当的64位函数。

首先,引导程序通过64位NTDLL处理:



get_ntdll函数内部发生的情况需要更详细的说明。 作为说明,我们还可以看一下ReWolf库中的类似代码

要访问流程环境的64位部分,我们需要使用段选择器。 让我们看看恶意软件如何进入64位模式。



似乎这段代码是直接从开放库中复制的: https : //github.com/rwfpl/rewolf-wow64ext/blob/master/src/internal.h#L26

段选择器0x33被压入堆栈。 然后,恶意软件调用以下行:(通过这种方式,下一行的地址也被压入堆栈。)



retf堆栈的地址通过添加5个字节来固定,并在retf之后设置:



最后,将调用RETF语句。 RETF是“远期回报”,与常规RET不同,它允许您不仅指定要继续执行的地址,还指定一个段。 作为参数,它从堆栈中取出两个DWORD。 因此,当执行RETF时,返回的返回地址变为:

0x33:0x402A50

由于更改了段,因此将从指定地址开始的代码解释为64位。 因此,调试器看到的代码是32位...



...实际上是64位。

为了快速切换视图,我使用了PE-bear功能:



如果这段代码被解释为64位,则如下所示:



因此,此处执行的代码负责将寄存器R12的内容移至堆栈上的变量,然后切换回32位模式。 这样做是为了获得64位线程信息块(TEB) ,从这里我们从中获得64位进程环境块(PEB) -我们看一看类似的代码

64位PEB用作查找64位版本的NTDLL的起点。 这部分的实现非常简单 (使用此方法的“原始”实现可以在此处找到),使用指向已加载库的指针,该库是PEB结构中的字段之一。 因此,从PEB中,我们得到一个名为Ldr的字段:



Ldr_PEB_LDR_DATA类型的结构。 它包含一个名为InMemoryOrderModuleList的条目:



此列表包含正在研究的进程的内存中存在的所有已加载库。 我们遍历列表,直到找到我们感兴趣的库,在本例中为NTDLL。 这正是上面的get_ntdll函数get_ntdll 。 为了找到合适的名称,它调用以下函数,指定为is_ntdll_lib ,该函数通过字符对照ntdll.dll检查库名称。 相当于这段代码。



如果名称匹配,则库地址将返回到几个寄存器:



找到NTDLL后,我们只需要获取相应函数的地址即可。 我们可以通过查看库导出表来做到这一点:



检索以下功能:

  • NttUnmapViewOfSection
  • NtGetContextThread
  • NtAllocateVirtualMemory
  • NtReadVirtualMemory
  • NtWriteVirtualMemory
  • NtSetContextThread。

众所周知,这些功能是RunPE技术的典型功能。 首先,NtUnmapViewOfSection用于取消映射原始PE文件。 然后,在远程过程中,将分配内存并写入新的PE。 最后,更改过程上下文,以便从嵌入式模块开始执行。

函数地址被存储并在以后调用(类似于代码)以控制远程进程。

结论


到目前为止,矿工的作者还没有表现出太多的创造力。 他们依靠开源组件来实现自己的目标。 所描述的情况很好地反映了这种趋势,因为使用了现成的实现。

天堂之门已经存在好几年了。 一些恶意程序使用它来增加隐身性 。 但是对于这种矿机,作者可能希望通过使用最适合目标体系结构的有效负载来最大化性能。

仅此而已。 您可以在这里找到有关我们课程的更多信息。

Source: https://habr.com/ru/post/zh-CN467193/


All Articles