This blog has been written by our Senior Security Researcher, S. Nayani
Understanding how real attackers develop methods for bypassing security controls and reverse engineering them is always fascinating. It has always been my passion to explore the world of vulnerability research therefore, I started learning debuggers and how to debug applications. Furthermore, I was also looking at different methods to bypass AMSI. Even though there are several blogs and onliners to bypass AMSI, I still wanted to explore it myself and gladly was able to bypass it using WinDbg.
What is AMSI
Before diving into the bypass part, let’s first take a look at what AMSI is. Microsoft developed AMSI or AntiMalware Scan Interface to defend against Scripting languages such as PowerShell, VBScript, or JScript which are usually easy prey for hackers. These languages are integrated into the OS and have a lot of “legit” functions that could be used by hackers to perform illegitimate activities. AMSI is used by Antiviruses to detect malicious scripts being run on these scripting languages.
For more information refer to Microsoft documentation: https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal.
I’ll be bypassing AMSI in PowerShell using WinDbg and will be going over the basics of WinDbg, so basically, every time a PowerShell session is opened AMSI.dll is initialized with it.
First, we need to see what functions are there in AMSI.dll, there are a few methods that we can use to get the functions of DLL,
1. Using the dumpbin.exe
dumpbin /exports <dllname>
2. Using dependency walker:
3. Microsoft also has documentation of AMSI, they have also mentioned the functions:
After getting the functions of the dll, the thing we want to figure out is which functions are called when AMSI detects something malicious. For that we are going to use Frida:
Run Frida-trace to attach to a PowerShell session, you can get the process ID by running the Get-Process command.
Frida-trace.exe -p 4820 -i *Amsi* -x amsi.dll
-p: Process ID
-i: specify the function name or matching pattern
-x: Module or dll name
After attaching to the PowerShell session and hooking the functions, we enter a string in the session that is hooked:
Note: Amsi flags a simple string “amsiutils” as malicious.
Now check Frida-trace output:
As you may have noticed, 2 functions are called
AmsiOpen() and AmsiScanButter(). The next step would be to examine those functions through a debugger, let’s fire up WinDbg and attach it to our PowerShell session:
Let’s set a breakpoint to the AmsiScanBuffer functions:
You can set a breakpoint using the bp command:
After setting the breaking point, enter the (g) command to run the process normally and enter another string in the PowerShell session to trigger the breaking point, and enter the (u) command to unassemble the function.
When I was trying to bypass AMSI, I was exploring and trying to figure out the logic behind this function, I went through all the registers that it was using and in the above screenshot, there is a rdi register when I looked at its value it had ‘AMSI’ ASCII string in it.
That was a bit suspicious for me, so I modified that instruction and changed it to just return (c3 in hex):
You can edit the instruction by using the (a) command:
Let’s see if that worked, run the process normally using the (g) command, and let’s see if we bypassed AMSI:
And there you have it, it was flagging the ‘amsiutils’ string as malicious after our bypass it did not flag that, proving that we have indeed bypassed AMSI successfully.