AMSI 绕过之.Net API Hook
2023-4-26 18:0:41 Author: M01N Team(查看原文) 阅读量:20 收藏

简介

反恶意软件扫描接口 (AMSI) 是对动态恶意脚本执行进行深入检查的 Microsoft Windows 组件。AMSI 可以被不同的防病毒软件调用,提供对PowerShell 脚本、JavaScript 和 VBA 宏等恶意脚本的扫描。Practical Security Analytics提出了一种通过Hook .Net Api绕过AMSI的新技术,本文主要对此技术进行分析与复现。

01 背景

反恶意软件扫描接口 (AMSI) 的开发旨在为 Windows 环境中执行恶意脚本提供安全防护支持。目前,主流对抗AMSI的技术主要有编码混淆、内存补丁、强制AMSI初始化失败、amsi.dll劫持、修改注册表项等。其中,内存补丁通过Hook windows API AmsiScanBuffer() 函数,使其始终返回AMSI_RESULT_CLEAN值以达到绕过的目的。而目前Hook的实现多针对于asmi.dl中的AmsiScanBuffer函数,实际上,powershell是.Net程序集,在执行命令或脚本之前,powershell会调用AmsiUtils.ScanCotent静态方法,该方法将命令发送到amsi接口进行检查,如下图所示。AmsiUtils是一个内部类,位于System.Management.Automation.dll中。如果修补ScanCotent方法,就可以阻止对amsi.dll中 AmsiScanBuffer 的调用,从而实现asmi绕过。

AmsiUtils.AmsiNativeMethods.AMSI_RESULT result = AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_CLEAN;fixed (char* chPtr = content) {    IntPtr buffer = new IntPtr((void*)chPtr);    hresult = AmsiUtils.AmsiNativeMethods.AmsiScanBuffer(AmsiUtils.amsiContext, buffer, (uint)(content.Length * 2), sourceMetadata, AmsiUtils.amsiSession, ref result);}

02 技术分析

该技术的核心是Hook .Net API。由于.Net程序集运行在CLR环境中,因此.Net API Hook 与常规windows API Hook不一样。

.Net API Hook 的步骤有6步:

  1. 确定要hook的目标函数

  2. 定义具有相同函数签名的函数

  3. 利用反射找到函数

  4. 编译目标函数和自定义函数

  5. 找到目标函数和自定义函数在内存中的地址

  6. 修补目标函数,该步骤与Hook windows API一致

可以看到,与windows hook相比,重点在于编译函数和定位函数地址,这是由.Net的特性决定的。.NET 编写的代码经编译后,会得到一个由通用中间语言(CIL)构成的二进制文件,CIL构成的二进制文件会交由CLR进行接管, 只有在运行时才会由CLR进行编译(JIT),生成可以直接运行的native code。

我们可以通过RuntimeMethodHandle.GetFunctionPointer()方法获取编译后的native code地址。但在.Net中,如果函数没有实际被调用,那么该函数可能不会被编译,也就无法定位到函数地址。幸运的是,RuntimeHelpers类可以手动触发JIT编译。如下代码所示。

//反射找到函数MethodInfo ori = typeof(CmdletInfo).Assembly.GetType("System.Management.Automation.A"+"ms"+"i"+"Ut"+"ils").GetMethod("ScanC"+"ontent", BindingFlags.NonPublic | BindingFlags.Static);MethodInfo rep = typeof(Program).GetMethod("ScacnConte"+"ntStub", BindingFlags.NonPublic | BindingFlags.Static);
//JIT 编译函数RuntimeHelpers.PrepareMethod(ori.MethodHandle);RuntimeHelpers.PrepareMethod(rep.MethodHandle);
//获取函数地址IntPtr originalSite = original.MethodHandle.GetFunctionPointer();IntPtr replacementSite = replacement.MethodHandle.GetFunctionPointer();
//修补目标函数.....

这里多说一句,未编译前MethodHandle.GetFunctionPointer()获得的地址指向PreJitStub块,大小为5个字节,该块的作用是调用JIT进行编译。

另外,在自定义函数这一步,由于函数总是返回1,因此c#编译器认为函数不是完整的函数调用,从而优化整个函数代码,无法hook。可以通过向函数添加属性来告诉编译器不要优化或内联该方法。

[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]private static int ScanContentStub(string content, string metadata) {    return 1; //AMSI_RESULT_NOTDETECTED}

03 利用

为了在 PowerShell 中安装Hook,需要把程序集加载到powershell中,作者提出了两种方法,一是使用Add-Type动态编译c#代码并加载到session中;二是将已编译的程序集作为 Base64 嵌入脚本中,并以反射方式将该 DLL加载到内存中;还有其他的利用思路,比如未托管代码使用CLR Hosting技术来加载Hook程序集,未托管代码可以做持久化,注入到启动项当中。

该技术针对.Net API进行Hook,可以较好规避杀软,但需要对代码中的一些静态特征做混淆,如"System.Management.Automation.Amsiutils"字符串。

04 总结

本文介绍了利用Hook .Net API进行amsi绕过的一种新技术,对其中关键技术点进行了分析,并简要介绍了Hook .Net API的其他利用思路。

附录 参考链接

[1] https://practicalsecurityanalytics.com/new-amsi-bypass-using-clr-hooking/

[2] https://learn.microsoft.com/en-us/archive/msdn-magazine/2005/may/net-framework-internals-how-the-clr-creates-runtime-objects

绿盟科技天元实验室专注于新型实战化攻防对抗技术研究。

研究目标包括:漏洞利用技术、防御绕过技术、攻击隐匿技术、攻击持久化技术等蓝军技术,以及攻击技战术、攻击框架的研究。涵盖Web安全、终端安全、AD安全、云安全等多个技术领域的攻击技术研究,以及工业互联网、车联网等业务场景的攻击技术研究。通过研究攻击对抗技术,从攻击视角提供识别风险的方法和手段,为威胁对抗提供决策支撑。

M01N Team公众号

聚焦高级攻防对抗热点技术

绿盟科技蓝军技术研究战队

官方攻防交流群

网络安全一手资讯

攻防技术答疑解惑

扫码加好友即可拉群


文章来源: http://mp.weixin.qq.com/s?__biz=MzkyMTI0NjA3OA==&mid=2247491311&idx=1&sn=ab66215596c860e6661db6526fc01aaf&chksm=c187defef6f057e841e01a85c3389bfee590162d86368786e5c875a3229b540ec8dbd7468077#rd
如有侵权请联系:admin#unsafe.sh