Detecting Process Injection using Microsoft Detour Hooks
This blog post discusses using Microsoft Detours to add hooks for common APIs in an attempt to detect and prevent process injection.
Last updated
This blog post discusses using Microsoft Detours to add hooks for common APIs in an attempt to detect and prevent process injection.
Last updated
Microsoft Detours "is a software package for monitoring and instrumenting API calls on Windows". The package provides a generic and safe way to implement hooks for x86 and x64 Windows APIs, allowing for monitoring, tampering, or anything else that you'd want to do with an API hook.
This blog post will cover how to get started with detours, with the objective of being able to detect and prevent a typical example of process injection used by common attack frameworks. We'll build a DLL that when loaded into a process will hook the relevant API calls, and then kill the host process if the sequence of API calls indicates that process injection is about to occur.
To put it another way, we will try and create the most basic, simplistic, and probably incorrect example of a "Next-Generation Anti-Virus" (NGAV). Suffice to say the content of this blog should not be taken with any seriousness in terms of detecting real threats; it does not factor in performance, stability, false positives, or any of the other factors that enterprise security products have to address.
Getting started with Detours is very simple, we can use NuGet to install the package and the we just need to include the library at the start of our project file:
After we've added the library to our project we can hook our first function. For this initial proof of concept we will build a DLL that when injected into a process will hook the MessageBoxA function:
Implementing our first function hook is trivial as we can see from the code snippet above. The majority of the code is just boiler plate DLL code, but lines 5 - 13 are what we really care about. On line 5 we define a new function to map to the original MessageBoxA function, this allows us to call the original function after our hook has run. Note that it has the same return code and parameters as the real MessageBoxA function:
Lines 7 - 13 are where we define our "hook" code. We copy the return code and parameters of the real MessageBoxA function, do our "evil" (in this case changing the text displayed in the text box to 'Hooked!') and then return execution back to the original MessageBoxA function.
Finally, to implement the actual hook we call DetourTransactionBegin()
, DetourUpdateThread()
, DetourAttach()
and DetourTransactionCommit()
on lines 26 - 30. That's all that's needed to set up our hook, considerably easier that doing it all manually eh?
Now that we have a DLL that we can inject into a process to initiate our hook, let's test it out to make sure it works. In the screenshot below I created a simple program that will call MessageBoxA and display the text "Hi". It will then wait for user input and then display the message box again. In the break while it's waiting for user input, we can inject our DLL using Process Hacker, and if our hook works then the second call to MessageBoxA should have its text change to "Hooked!".
Now that we know how to hook APIs using Detours we can try something a little more interesting than just hooking MessageBoxA
. Instead, let's create a DLL that - when injected into a process - will hook the common API calls used for process injection, and then kill the host process if process injection is about to occur.
Discussing process injection (and the different variations) in detail is outside of the scope of this blog post in an attempt to keep the length of this post reasonable. In a nutshell typical process injection utilises the following API calls:
OpenProcess
- Used to get a handle to the target process of the process injection.
VirtualAllocEx
- Used to allocation memory in the target process to hold the payload.
WriteProcessMemory
- Used to write the payload to the memory region in the target process.
CreateRemoteThreadEx
- Used o create a thread in the target process to execute the payload memory region.
The code above is by no means safe to use in any meaningful way. It is simply an example of how hooking could be used to detect/prevent process injection. False positives and performance issues have not even slightly been considered.
The code above is a fairly straight forward extension to the MessageBoxA
example that we built previously, except instead of just hooking the MessageBoxA
function we are hooking the API calls that take place in the lead up to process injection.
For the most part the majority of our API hooks just toggle a boolean which allows us to track which APIs have been called. Then in line 41 - in the hook for the CreateRemoteThreadEx API - we have some simple logic that checks whether all of the other APIs have been called. If they have, then we get a handle to the current process and kill it. All going well, when we inject this DLL into a process, if that process attempts to perform process injection we should be able to catch the behaviour and kill the host process before the injection occurs.
To test whether our DLL will work correctly we need a simple way to perform process injection. Fortunately we can stand on the shoulders of other people's research and use the Invoke-ReflectivePEInjection
Powershell script from PowerSploit:
Before we use the process injection script we need to load our DLL into the Powershell process memory space. To simplify this process and to emulate a poor man's NGAV, I built a simple "supervisor" program that will inject our DLL into any powershell processes that are created.
As you can see from the GIF above, our supervisor service injected our DLL into the powershell process that was created. When we then tried to use the Invoke-ReflectivePEInjection
script to inject into another process, our hooks detected the lead up to the process injection and then ultimately killed the process!