In my previous diary[1], I explained why Python became popular for attackers. One of the given reason was that, from Python scripts, it’s possible to call any Windows API and, therefore, perform low-level activities on the system. In another script, besides a classic code injection in a remote process, I found an implementation of another goold old technique: live patching of a DLL.
A typical usage of live patching is the implementation of a hook on an API. They are many ways to hook an API but a common one is called inline API hooking or « trampoline » (because we « jump » from the original function to a malicious one). In a few words, how to implement this: You modify the beginning of a function in memory so that when the function is called, it first jumps to your malicious code. After your code runs, it can pass control back to the original function, so the program behaves as if the function was called normally, but with your modifications applied. A good example of API hooking is to perform data exfiltration. Imagine that you hook the API WriteFile(), before writing the buffer to the file, the malicious function can search for sensitive data.
Another scenario where live patching is useful: to bypass certain security controls implemented by the API. That’s what the discovered Python script will implement. I found that it will patch two interesting API calls:
To help you to better understand and "see" how it works, I wrote a quick Python script with the same behaviour. Let's run it inside a debugger and inspect the memory.
Run the script:
C:\Users\REM\Desktop>python patch-demo.py Attach a debugger to this process and press ENTER when ready
Now, launch your favourite debugger (I'm using x64dbg) and attach to the running python.exe process. Don't define any breakpoint, just allow the debugger to run the code. Go back to the command line and press enter.
AmsiScanBuffer() found at this address: 0x7ffbe9a523e0 In the debugger, jump to this address and check the code Press ENTER to continue
The Python script found the API call that we will patch. In the debugger, jump to the discovered address (0x7ffbe9a523e0 in this case). You can see that we are at the very beginning of the AmsiScanBuffer() API call:
Go back to the command line and press enter again. Now the Python script will patch!
AmsiScanBuffer() successfully patched Go back to the previous addresses in the debugger and check the patched code! Waiting to quit
In the debugger, jump again to the same address (0x7ffbe9a523e0) and you can see that the code changed!
What happened? Microsoft API calls use EAX to store their return value. In this case the patch performs the following instructions:
Note that the patch has overwritten 6 bytes (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00) and made the code after the RET non-functional!
Practically, when AmsiScanBuffer() will be called, it will immediately return an error and never scan the passed buffer for malicious code!
This technique is, by default, not malicious. All API calls are supported by Microsoft. There is not "hacking" techniques. Because DDL’s are loaded in the process environment, the process has access to the memory.
Of course, DLL’s can prevent this technique using different methods:
The code[2] is in Python but you could use any language that can use Windows API calls.
[1] https://isc.sans.edu/diary/Why+Is+Python+so+Popular+to+Infect+Windows+Hosts/31208
[2] https://pastebin.com/a8aAz9B6
Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key