AMSI Bypass Using Memory Patching

Dynamic in-memory AMSI bypass

Blog AMSI Bypass Using Memory Patching

| 3 min read

Table of contents

Contact us

Most of us have faced AMSI (Antimalware Scan Interface) and suffered the constraints it poses whenever we want to load a fancy PowerShell module like PowerView or Invoke-Mimikatz in the middle of a Red Team engagement.

AMSI is a programmatic resource offered by Microsoft to enable an interface to any application for interacting with any anti-malware product available on the machine. AMSI is EDR-agnostic and can be integrated with any vendor. When AMSI appears on stage, something like this should be familiar:

AMSI in action

Programmatically, AMSI can be included in an application using Win32 API functions and the IAmsiStream COM interface.

As a result, if an application was built with AMSI, amsi.dll will become part of the runtime modules of the application. Hence, it is seen as a DLL that is loaded at runtime when the application starts. The basic architecture of AMSI is the following:

AMSI Architecture

Source: Microsoft.

As you can see, the functions responsible for checking the content for malicious content are AmsiScanBuffer() and AmsiScanString(). These functions act as the entry point that the application uses to send the suspected tainted input to the underlying antivirus software.

Using a tool like Process Hacker, it is possible to check the runtime modules on any process in the system. Checking the process of our PowerShell session, we can see the AMSI DLL loaded in memory:

AMSI DLL

We can also check the exported symbols, which are the functions provided as the high-level interface with AMSI. Here we can see all the exported functions that compose AMSI, including AmsiScanBuffer() and AmsiScanString().

AMSI Exports

However, these two functions are not really different. In fact, AmsiScanString() is a small function which uses AmsiScanBuffer() underneath. This can be seen in WinDBG:

AmsiScanString()

And with a disassembler:

AmsiScanString()

So, if we can bypass the checks performed by AmsiScanBuffer(), we can also bypass AmsiScanString()!

Let’s get it done!

Here, we can see the disassembly graph of AmsiScanBuffer():

AmsiScanBuffer()

As you can see, it is not a complex function either.

At the end of the function, we can see this:

AmsiScanBuffer()

It seems that the actual anti-malware scanning is performed in the instructions that compose the big box on the left. Also, we notice that several JMP instructions land in mov eax 0x800700057 and then the function ends. The value 0x80070057 is a standardized error code from Microsoft, which is E_INVALIDARG. In this case, it’s used by AmsiScanBuffer() to return when the parameters passed by the caller code are not valid.

So, what would happen if we modify the AmsiScanBuffer() function in memory to bypass the anti-malware checking instructions altogether and force it always to return 0x80070057? Let’s check it!

Get started with Fluid Attacks' Red Teaming solution right now

First, let’s examine the instructions using WinDBG:

AmsiScanBuffer() disassembly

Here we can see the disassembled instructions of AmsiScanBuffer(). We can also see the byte-code corresponding to the mov eax,80070057h instruction: b857000780.

Using that information, we can modify the very beginning of AmsiScanBuffer() with the following instructions:

b857000780          mov eax,0x80070057
c3                  ret

That would move the E_INVALIDARG value (0x80070057) to EAX, making it the return value of AmsiScanBuffer(), and then the function ends with a RET. As can be seen above, the bytes b857000780 and c3 are the byte-codes of those instructions.

We can do the memory patching using WinDBG. The steps are the following:

  • Attach the current PowerShell session to WinDBG.

  • Break the execution.

  • Try to load a common flagged module (e.g., PowerView) to see AMSI in action.

  • Check the current instructions of the beginning of AmsiScanBuffer(). This can be accomplished with u amsi!AmsiScanBuffer inside WinDBG.

  • As we are in a little-endian architecture (x86_64), we need to reverse the byte-code of the mov eax,0x80070057 | ret instructions: c380070057b8.

  • Modify the start of amsi!AmsiScanBuffer with those bytes. This can be done using eq amsi!AmsiScanBuffer c380070057b8.

  • Resume the execution.

  • Load again PowerView.

  • Enjoy an AMSI-free PowerShell session!

Let’s check the bypass in action:

AMSI Bypass

However, returning 80070057 is not the only way to bypass AmsiScanBuffer(). In fact, we can make it return 0, using something like sub eax,eax | ret, and the bypass will be successful as well.

Let’s see:

AMSI Bypass v2

Success! Now we can use PowerView, Invoke-Mimikatz or any other Red Team tool!

AMSI Bypass

Conclusion

Memory patching is a nice trick to use to modify the behavior of running applications. Keep in mind that this technique is not persistent. The modification of AmsiScanBuffer() is performed on the memory of the PowerView process and the original amsi.dll is never touched on disk.

Table of contents

Share

Subscribe to our blog

Sign up for Fluid Attacks' weekly newsletter.

Recommended blog posts

You might be interested in the following related posts.

Photo by CardMapr on Unsplash

Users put their trust in you; they must be protected

Photo by Robs on Unsplash

Consequential data breaches in the financial sector

Photo by Claudio Schwarz on Unsplash

Is your financial service as secure as you think?

Photo by Brian Kelly on Unsplash

We need you, but we can't give you any money

Photo by Sean Pollock on Unsplash

Data breaches that left their mark on time

Photo by Roy Muz on Unsplash

Lessons learned from black swans

Photo by Valery Fedotov on Unsplash

A digital infrastructure issue that many still ignore

Start your 21-day free trial

Discover the benefits of our Continuous Hacking solution, which hundreds of organizations are already enjoying.

Start your 21-day free trial
Fluid Logo Footer

Hacking software for over 20 years

Fluid Attacks tests applications and other systems, covering all software development stages. Our team assists clients in quickly identifying and managing vulnerabilities to reduce the risk of incidents and deploy secure technology.

Copyright © 0 Fluid Attacks. We hack your software. All rights reserved.