A High Level Overview
DLL injection is a technique that can be used by legitimate software to add functionality, aid with debugging, or reverse engineer software running on a Windows PC. It is also often used by malware to subvert applications running on target systems, so from a security point of view, it’s useful to know how DLL injection works.
This blog post will attempt to explain code injection with a very simple, high level overview. I am not planning on delving into the technical details here, which will follow in a subsequent post.
Why place our code into another process?
Virus checkers and personal security products largely use these techniques to place their own software routines into all processes running on the system. This allows them to monitor each process while it’s running and install hooks into critical functions. For example, you may want to monitor calls to the “CreateProcess” function in your web browser. A call to this function could be an indicator that the browser has been compromised, as you don’t generally expect the browser to be running additional processes.
Another legitimate reason would be for reverse engineering purposes. We may have a malware executable that we want to monitor the behaviour of, and loading our code into the malware would enable us to monitor this.
There are also nefarious reasons. From a penetration testing point of view, we may want to retrieve private information from the memory of an application, for example, password hashes from the lsass process.
Malware will also use injection techniques to place shell-code, executable or DLL code into the memory of another process in order to hide itself.
How is injection achieved?
Broadly speaking, user mode processes running on Windows are ‘compartmentalised’ ,in that they have their own memory space and cannot usually read or write the memory of other running processes. Furthermore, the basic unit of execution in Windows is called a Thread, and each process must have at least one Thread in order to be “running”. In other words,all code execution happens in Threads.
So, in order to “inject” our code and get it to run inside another process, we are going to need to be able to write our code from our injector application into the target process memory and then create a Thread of execution in the target process which will then execute the memory we have injected.
Luckily for us, Microsoft provides some functionality that allows us to do this.
There are several different methods we can use to get our code to run; the simplest is a combination of the functions “OpenProcess”, “VirtualAllocEx” ,“WriteProcessMemory”, “ReadProcessMemory” and “CreateRemoteThread”.
I will cover the technical details of how these, and other techniques are used in a follow-up post.
Do we always need to inject our code?
To load our own code into a process, we don’t always need to use injection. Another simpler method is available for legitimate purposes.
Microsoft provides some registry keys:
HKLMSoftwareMicrosoftWindows NTCurrentVersionWindowsAppInit_DLLs
HKLMSoftwareMicrosoftWindows NTCurrentVersionWindowsLoadAppInit_DLLs
On a 64 bit machine the following keys are also provided for 32bit executables:
HKLMSoftwareWow6432NodeMicrosoftWindows NTCurrentVersionWindowsAppInit_DLLs
HKLMSoftwareWow6432NodeMicrosoftWindows NTCurrentVersionWindowsLoadAppInit_DLLs
Placing a DLL filename into the AppInit_DLLs key will cause the DLL to be loaded when any application on the system loads User32.dll (which is broadly speaking, all applications on the system). This works provided that the LoadAppInit_DLLs key is set to 0x00000001.
We would then need to create our own thread as the DLL loads from the “DllMain” entry point being careful not to attempt any thread synchronisation.
Conclusion
Using AppInit_DLLs registry key has a downside, which is that it will load our DLL into every application on the system. If we want a more targeted approach, then we need to use an injection method to target a single application.