As a result of my foray into static malware analysis, I decided I needed a better understanding of DLL injection. DLL injection allows us to run code in another process. This is useful because it allows us to hide malicious processes in other, benign processes. It also means not having to save anything to the disk, making detection and forensics that much more difficult. This technique is used in a variety of vectors from malware to Metasploit, so understanding the concept will help us better grasp the inner workings of both. In this new series, we will walk through the different ways that we can inject DLLs as well as examine the entire process from a malware-analysis point of view. All of the code that follows can be found on my github page.
Understanding DLL Usage
A static library will be included at compile time. This means that the code is copied over into the new executable during compilation and used there. Dynamic Link Libraries (DLL) on the other hand, are loaded at run or load time using dynamic linking. This has several advantages over hardcoding them into the program:
- Lower memory usage because multiple programs can use one DLL as opposed to loading the functions into their memory space
- Save disk space
- Saves on compile time by having to compile less at one time
- Easier support, versioning, and updating
Here is a simple C program to import and run a method in a DLL.
And two simple dlls: Test.c
Now we are going to compile each of these. Here are the steps that I used to make it a bit easier:
- First, we create the executable from Dllhandler.c by using the mingw cross-compiler, which is similar to normal compilation using gcc.
- Then we compile and assemble the two DLL files using “-c” but we do not link them. Then we finally compile the “.o” files using the “-shared” option to create a DLL instead of an executable.
Rename the test1.dll to test.dll and then all that is left is to run our new executable.
The first dll looks good; how about the second? The dlltest file is expecting the DLL to be named “test.dll”. So move the “test.dll” and rename “test2.dll”
Running the test executable a second time now gives us results based on the second DLL payload.
A Touch of Forensics
This post began as a result of the malware analysis, so let’s take a brief look at that side of things. If we were reverse engineering malware, how do we know when a DLL is loaded? How does it use the DLL? Here is what the first part of the executable looks like when it is loaded into IDA.
We can see that it loads test.dll using LoadLibraryA. Then it checks to see if our library is null. If not, it gets the address for the test method, checks if it is null! There is a lot that can go into static analysis that we will leave out of this post, but now we at least have an idea about how it works.
The last tool for today is ListDlls, part of the Systinternals suite. It’s a simple tool that prints out all of the DLLs used by every process running.
There is our test.dll! We can see that it was run from the command line and its size. Next time we will load that DLL in another process. Stay tuned!