在现实世界中,恶意软件的作者会设法利用各种技术手段来隐匿自己的非法行踪,从而绕过相应的安全防御措施。其中,一种常用的手段就是将恶意代码隐藏在可信进程的上下文中。一般来说,采用这种隐身技术的恶意软件通常会将自身的代码注入到诸如explorer.exe之类的系统进程中去。此外,还有些样本会采用其他更加有趣的方法,本文中所讨论的恶意软件就是属于这种情况。
最近,某些.NET恶意软件样本引起了我们的极大兴趣,因为这些样本使用的是来自Microsoft .NET Framework的可信应用程序InstallUtil.exe(根据Microsoft官方网站的介绍:“该安装程序工具使您得以通过在执行指定程序集中的安装程序组件来安装和卸载服务器资源。此工具与 System.Configuration.Install 命名空间中的类一起工作。”)。
本文介绍的这种技术,最初是由信息安全研究员凯西•史密斯又名subTee(POC)公布的。简单来说,就是利用该控制台实用程序InstallUtil.exe运行恶意的.NET程序集,来绕过程序集的入口点;这样的话,就能将所有的恶意活动都隐藏在可信进程的上下文中了。
通常情况下,恶意样本的传播都遵循这样一个标准模式:恶意代码以受密码保护的文档的形式传递给用户,并且大多数情况下,该可执行文件的图标都是经过精心挑选的,以便让受害者将其误认为是正常的文档或照片。此外,我们还遇到过伪装成通用软件的序列码生成器的可执行文件。首先,该生成器的恶意内容会被保存到%TEMP%文件夹中,之后,它会通过后文中描述的方式来运行恶意代码。
用户通常会被可执行文件的图标所蒙骗
样本分析
我们遇到的所有恶意文件,通常都是经过了严格的混淆处理的,这极大地提高了手动分析的难度。这里,我们将以样本263dc85de7ec717e8940b1ccdd6ee119为例进行介绍,首先,我们要对该样本的字符串、类、方法和字段进行去混淆处理。在去混淆之前,该文件的内容看起来像下面这样:
去混淆之前的样本代码
前面说过,InstallUtil.exe允许人们在执行文件的时候,不从.NET程序集入口点开始执行,例如,可以从继承自System.Configuration.Install.Installer的类开始执行。在我们的这个样本中,为了便于手动分析,我们将这个类重命名为InstallUtilEntryClass。也就是说,在程序集加载到内存中时,可以首先执行静态类构造函数中的代码——恶意软件作者就是利用了这一特性。
下面,我们将按照方法执行的顺序来检查该恶意文件的行为。首先执行的方法是FirstMainClass,因为它的构造函数带有关键字“static”,那么程序集自然就会从它开始执行:
FirstMainClass类的静态构造函数(将在加载程序集时被触发)
这个构造函数执行下列函数:
· CheckSandboxieEnvironment(),它会通过尝试加载SbieDll.dll库来确定文件是否在Sandboxie中运行。如果可以加载这个库的话,那么该恶意进程就会自动终止;
· CheckVirtualBoxEnvironment(),它会搜索隶属于VitrualBox的vboxmrxnp.dll库。如果找到这个库的话,这个恶意进程也会终止;
· AddResourceResolver(),它将添加一个方法来处理资源加载事件。该方法的作用,是对来自特定资源的(通过Deflate算法进行加壳的)程序集进行脱壳处理,然后将脱壳后的程序集加载到内存中;
负责从资源加载程序集的方法
程序集经过脱壳后被加载到内存
AssemblyResourceLoader类的UnpackAllAssemblies()方法会遍历所有程序集资源,当找到名称中含有字符串“+ ||”的资源的时候,就对这些资源进行脱壳处理,从而得到相应的程序集。由这个方法获取的程序集,是该恶意文件正常运行所不可或缺的组成部分,同时它们也都是合法的程序库:Interop.MSScript.Control、Interop.TaskScheduler、SevenZipSharp;
RemoveZoneIdentifier()会通过命令行删除NTFS备用流Zone.Identifier,以防止启动时出现警告——如果该文件是从Internet下载的话。不过,该恶意软件的作者在命令行(“cmd.exe /c (echo. > file path:Zone.Identifier) 2 > Null”)中的字符2和>之间留下一个空格,这个小小的过失将会导致控制台输出下列内容:
删除Zone.Identifier时发出警告
ElevatePrivilegesProxy()方法是ElevatePrivileges()方法的封装器,而该方法使用了Matt Nelson(又名enigma0x3)给出的一种著名的UAC绕过技术。
然后,控制权会传递到传统的入口点——位于Form5类中的Main()方法:
传统的入口点为Main()方法
我们看到,WMI对象在挂起30秒后重新开始执行。接下来,会对ScriptControlClassInstance对象进行定制,其中使用的语言(Visual Basic脚本)和脚本的主体被转移到:
使用InstallUtil.exe运行可执行文件的脚本
AddCode()方法会添加并执行一个使用InstallUtil.exe运行当前程序集的VB脚本。之后,通过调用Environment.Exit(0)结束当前进程。
在下一阶段,将使用InstallUtil工具运行恶意对象,并再次执行前面讲过的FirstMainClass类的静态构造函数;然后,将控制权传递给InstallUtilEntryClass类的静态构造函数,我们曾经说过,该类继承自System.Configuration.Install.Installer:
InstallUtil.exe调用的静态类构造函数
这个类的功能包括:
· 将恶意文件复制到 %APPDATA%programmsexcel.EXE,为“program”文件夹设置Hidden+System属性,运行msexcel.EXE,并终止当前进程;
· 将复制的文件添加到自动运行注册表项中(HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRun or HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionRun);
· 创建一个名为“filesqmaepq0d.tnk”的任务,每分钟运行一次msexcel.EXE,以确保它始终在受害者的计算机上运行;
· 检查恶意进程是否已经处于运行状态。创建名为“78759961M”的事件,如果系统中已经存在这样的事件,则终止新进程;
· 创建Form5类并调用其析构函数。
让我们总结一下:实际上,上述所有行动(系统的巩固、特权的提升、可信应用程序的启动)都是为将来的主要任务做好准备工作。下面,我们会继续分析下一步的准备活动,这将使我们离恶意活动的核心部分更近一步。
除此之外,该恶意程序集还包含5个继承自System.Windows.Forms.Form的类。之所以从Form类进行继承,这绝不是偶然的:在其继承层次结构中,这个类实现了多个接口,其中之一就是IDisposable,该接口允许我们根据自己的需要来重写Dispose()方法。垃圾收集器会调用Dispose()方法,以便在关闭或卸载程序集时释放这个类占用的资源。现在,我们来考察Form5类的Dispose()方法的源代码:
重写的Form5类的Dispose()方法
正如我们所看到的那样,在循环语句的每次迭代中,都会执行各个方法,并保存相应的结果,具体来说:
· 在第一次迭代中,将得到.NET框架中的RegAsm.exe实用程序的完整路径;
· 通过调用一系列的嵌套方法,对存储在另一个类中的Base64编码的字符串进行解码,并使用SevenZipExtractor库对解码后得到的数组进行脱壳处理。这样,我们就会得到一个数组,它实际上是一个远程管理工具NanoCore Client;
· 从之前从资源脱壳后放入内存的程序集中加载PERun.dll库;
· 在这个库中查找一个名为“RunPE”的类及其Run方法;
· 在最后一次迭代中,传递相应的参数并调用Run方法。
我们知道,legalProgramPath变量存放的是合法实用程序RegAsm.exe的完整路径,PEFileByteArray用于保存字节数组形式的可执行文件,而类名称为RunPE;同时,我们也不难看出,Run()方法则会将恶意代码隐藏到可信进程RunPE的地址空间中。这种技术是广为人知的,并可以从这里找到详细的介绍。
在Run()方法内部,会创建一个处于CREATE_SUSPENDED状态下的合法实用程序进程(第6个参数为4u):
创建处于CREATE_SUSPENDED状态下的合法程序进程
最后,RegAsm.exe进程被加载到相应的地址空间,并启动payload,即远程管理工具NanoCore Client。由于只有可信进程出现在当前运行的进程列表中,所以,即使是经验丰富的用户,通常也想不到系统已经被感染:
在当前运行的进程列表中只能看到合法的实用程序
这里,之所以将RegAsm.exe作为我们的“载体”,是因为(a)它是来自Microsoft的合法实用程序,(b)它与InstallUtil.exe位于同一个目录中,以及(c)与其让.NET Framework中的实用程序调用同一个框架中的另一个实用程序,不如让它调用notepad.exe,因为前者更容易引起人们的怀疑。事实上,是否选用RegAsm.exe并不重要:这里的“载体”可以是不容易引起安全软件和用户怀疑的任何程序。重要的是,涉及恶意模块的所有操作都是在内存中执行的,这样就能够绕过文件扫描程序。
如前所述,这个样本包含NanoCore Client,我们可以用它来控制受害者的计算机、截图、记录击键、下载文件,等等。需要注意的是,这里的payload可以是任何东西:从“时髦”的加密程序和挖矿程序,一直到高级木马,全都可以。
结束语
一般来说,恶意软件的作者会通过各种技巧来隐藏其恶意行为,比如就像本文中介绍的那样,通过在两个合法程序的上下文中执行恶意代码来达到这一目的。为了检测这种隐藏方法,必须对程序进行相应的行为分析。卡巴斯基实验室的安全解决方案将这种行为标识为PDM:Trojan.Win32.Generic和PDM:Exploit.Win32.Generic。
IOC (MD5)
263DC85DE7EC717E8940B1CCDD6EE119
payload: EF8AF3D457DBE875FF4E3982B34F1DE9
3E4825AA1C09E27C2E6A1309BE8D6382
payload: 82709B139634D74DED404A516B7952F0
7E3863F827C1696835A49B8FD7C02D96
payload: D1A9879FFCB14DF70A430E59BFF5EF0B
8CB8F81ECF1D4CE46E5E96C866939197
payload: D8652841C19D619D2E3B5D7F78827B6E
FDF4086A806826503D5D332077D47187
payload: BF4A3F4B31E68B3DE4FB1F046253F2D0