Between Windows 11 and Windows 10 AMSI bypass - Corrupting structures and variables

8 minute read

Published:

alt text

Disabling the Antimalware Scan Interface (AMSI) by locating and corrupting vital structures and variables for both Windows 11 and Windows 10.

Whaaaat!

In recent years, many (not all) antivirus products have begun to rely on Antimalware Scan Interface (AMSI) to detect more advanced malicious activity. This means, the content passed by AMSI is only analyzed if one of those antivirus products is installed.

To protect against the increased malicious PowerShell scripts, Microsoft introduced the Antimalware Scan Interface (AMSI) in 2015 with the release of Windows 10. The Antimalware Scan Interface captures every (all) PowerShell, Jscript, VBScript, VBA (added in MS Office 2019), or .NET (added in .NET framework 4.8) command or script at run-time and passes it to the Microsoft’s own Windows Defender antivirus or any other local antivirus products for inspection.

Let’s see how AMSI interacts with the local antivirus product, which in this case is Windows Defender.

alt text

The amsi.dll which is an unmanaged dynamic link library is loaded into every PowerShell (32-bit/64-bit) and PowerShell_ISE (32-bit/64-bit) process. The amsi.dll provides several APIs that PowerShell/PowerShell_ISE takes advantage of. The information (PowerShell commands or scripts) captured by these APIs is forwarded to Windows Defender through the Remote Procedure Call (RPC). After the local antivirus product (Windows Defender in this case) analyzes the captured data, the result is sent back to amsi.dll inside the PowerShell process.

Antimalware Scan Interface is essentially a set of APIs that allow antivirus products to scan PowerShell, Jscript, VBScript, VBA or .NET commands or scripts when they are executed, of course, even if they are never written to disk.

AMSI APIs

The AMSI exported APIs include AmsiInitialize, AmsiOpenSession, AmsiScanString, AmsiScanBuffer, and AmsiCloseSession.

alt text

When PowerShell is launched, it loads amsi.dll and calls AmsiInitialize before we can invoke any commands, which means we cannot influence AmsiInitialize in any way. The AmsiInitialize is the API responsible for populating the Context Structure, which is used in every subsequent AMSI-related APIs.

Once the AmsiInitialize is done and the Context Structure is created, AMSI can now parse the typed commands. The moment we execute a PowerShell command, the AmsiOpenSession is called. The AmsiOpenSession is the API responsible for accepting the Context Structure created by calling AmsiInitialize and creating a Session Structure to be used in all calls within that session.

Then, we have the AmsiScanString and AmsiScanBuffer, which are the ones responsible for the actual capture of command or script content either as a string or as a binary buffer respectively. The Windows Defender scans the string or buffer passed to AmsiScanString and AmsiScanBuffer respectively and returns the result value. A return value of “1” indicates a clean scan, and “32768” indicates the presence of malware.

Finally, a calling to AmsiCloseSession, once the scan is complete. The AmsiCloseSession is the API responsible for closing the current AMSI scanning session.

Let’s hook the AMSI APIs using Frida and see the AMSI process in practice:

alt text

The issued command is “cd” as you can you see in the buffer parameter, which is the one that containing the content to be scanned. Windows Defender scans the buffer passed to AmsiScanBuffer and returns the result value. The result value is “1” which indicates that the “cd” command is clean. However, the scanned “AmsiUtils” returns a value of “32768”, indicating that AMSI has flagged “AmsiUtils” as malicious, and there is no doubt that the warning we received in PowerShell prompt came from Windows Defender (in our case):

alt text

Splitting the “AmsiUtils” in two strings and concatenating them, will return the result of “1” indicating that AMSI has flagged it as non-malicious:

alt text

We don’t know why AMSI has flagged “AmsiUtils” as malicious, yet. However, we easily bypassed it by splitting and concatenating the string.

Wait! Where is the AmsiScanString? Microsoft has stopped using the AmsiScanString which was vulnerable to a trivial bypass technique and is now using AmsiScanBuffer instead.

Windows 10 AMSI Bypasses

amsiContext and Forcing an Error

We said that the Context Structure that is created by calling AmsiInitialize, is found to be used in all the AMSI APIs. If we can force some sort of error in this undocumented structure, we may be able to discover a way to bypass AMSI:

alt text

From the above screenshot, we can see the memory address of the Context Structure. Let’s see its content with the help of WinDbg:

alt text

As the Context Structure is undocumented, we don’t know the size of it, but we found that the first four bytes equate to the ASCII representation of “AMSI”. The real question, is this string static between processes? To confirm this, we’ll launch another PowerShell prompt and use Frida to interact with it and hook the AMSI APIs. After that we’ll re-read the content at the memory address of amsiContext:

alt text

alt text

From the above screenshots, we can confirm that the string “AMSI” is static between processes. Next thing is to see the Context Structure in action in the AMSI APIs, this way we can determine if the string “AMSI” is referenced in any way:

alt text

The fourth line of assembly code is comparing the content of RCX register, which is the one contains the function’s first argument, to the four static bytes “49534D41”. The first argument of AmsiOpenSession is exactly the Context Structure according to its function prototype, which means that a comparison is performed to check the header of the buffer.

The fifth line of assembly code is jne (jump if not equal), which means if the header bytes are not equal to this static DWORD - “AMSI”, a conditional jump to an exit of the function is triggered:

alt text

The static value 0x80070057 corresponds to the message text E_INVALIDARG. The message text indicates that an argument – amsiContext – is invalid. So, this error occurs if the Context Structure has been corrupted.

Let’s try to enforce this error and see if we can bypass the Antimalware Scan Interface. To do that, we’ll try to modify the first four bytes of the Context Structure:

alt text

alt text

We have effectively bypassed AMSI by corrupting the amsiContext header.

Instead WinDbg, we’ll try to use PowerShell to interact with System.Management.Automation.AmsiUtils class as it the one that stores information about AMSI, corrupting the Context Structure and helpfully bypassing AMSI:

alt text

Very nice! AMSI bypassed.

Converting the very large number “1960613452080” to hexadecimal produces 0x1C87DAB1930. Which is the memory address of the amsiContext buffer. By overwriting the amsiContext header with zeros, we were able to bypass the Antimalware Scan Interface:

alt text

amsiInitFailed and Forcing an Error

We can use another technique to bypass the Antimalware Scan Interface, which is based on the manipulation of a result variable set by AmsiInitialize through the amsiInitFailed (true/false). This field is verified by AmsiOpenSession in the same manner as the amsiContext header, which leads to an error:

alt text

As we can see, by setting the value to true we were able to bypass AMSI. However, the AMSI start working once again when we set the value to false.

Windows 11 AMSI Bypasses

With the release of Windows 11 in 2021, a lot of things changed but is AMSI protection changed as well, or our techniques are still valid? Let’s try to bypass AMSI by corrupting the Context Structure from PowerShell:

alt text

This is not working anymore, but why? To know why, we need to see the Context Structure in action in the AMSI APIs once again:

alt text

There is no check on the header of the buffer to be perform as we saw on Windows 10. That’s why our method to bypass the AMSI is not working anymore. However, enforcing an error using the amsiInitFailed is still working:

alt text

The techniques that we discussed here are tested on fully updated Windows 10 and Windows 11 systems.

In summary, the discussed techniques are known by security professional for years, but still can be used with a small modifications.