As a part of my work (read "fun") of maintaining this blog, I am constantly checking the statistic information on traffic sources and keywords (it's nice to know that people are getting here via Google) in order to see whether my readers are getting what they are looking for (personally, I see no reason in simply "streaming my consciousness to the masses" as this is not the point of this blog). Sometimes, it gives an idea of what is missing but still related to system and low level programming.
A couple of days ago, I saw that someone was looking for a way to load and use fake KERNEL32.dll and I realized that this information has not yet been covered here. There is no source code for this article as I am a bit short on time to write it, but I will do my best to provide as much information as possible so, those who would want to try it would have no problem doing that.
First notable thing about KERNEL32.dll is that it is always loaded, regardless of whether a running executable imports anything from it (this is briefly covered here). Same as NTDLL.dll (well, KERNEL32.dll imports from it). This library provides interfaces for interaction with deeper levels of "user land" part of the operating system for the running executable and some of other dynamic link libraries loaded into process' memory.
Knowing all that, the first thought may be: "how are we going to fake it if all the rest depends on it?". The solution is easier than one could think at first. However, we should keep in mind, that some programs may import from NTDLL.dll directly, bypassing the KERNEL32.dll (which used to happen quite often in the world of malware), meaning that once you faked KERNEL32.dll, you may have to fake NTDLL,as well.
We should start with writing a good old simple DLL/code injector. It is easier to dissect the victim process from inside. This is the simplest part and it is covered in this and this posts of this blog. Roughly saying, the injector should be able to create a victim process in suspended state by passing the CREATE_SUSPENDED process creation flag to CreateProcess API.
Writing the code or the DLL we are going to inject is a harder task as this code is intended to perform the tasks described below in order of execution.
Load Fake KERNEL32.dll
Let's assume, that we already have a ready to use fake KERNEL32.dll (we'll get back to creation of fake dll a bit later). This is quite simple - call LoadLibrary function from your code. One thing worth mentioning is that MSDN is not suggesting to use LoadLibrary in your DllMain function. Therefore, if you decide to use DLL Injection instead of code injection, then better use the approach described in "Advanced DLL Injection" article.
Fake KERNEL32.dll should simply import all API's from the original one. Don't be mistaken - import, not forward it's exports at least as long as we are talking about API functions, but you may safely forward exported objects and variables to the original one.
Resolve Victim's Imports
By the time we get our code/DLL running inside the suspended victim process, all of it's imports should already have been resolved. What we still have to do, is to replace all API addresses exported from the original KERNEL32.dll with corresponding addresses in our fake one.
Here is a link to Microsoft's specifications of MS PE and MS COFF file formats - would be useful digging through imports and export.
Hide the Original KERNEL32.dll
While performing the aforementioned actions may be enough in case of a regular application, we should take some precautions in case of malicious code. My suggestion is to hide the original KERNEL32.dll by replacing its entry in the list of LDR_MODULE structures in PEB with the one describing our fake KERNEL32.dll, just like we would hide an injected DLL in the "Hiding Injected DLL in Windows" article.
Creation of Fake KERNEL32.dll
This may sound scary, but there is no need to worry (at least not too much). All that we need in order to create one, is a C compiler (or whatever high level language you prefer) and any assembler (I use FASM as usual).
Dump KERNEL32.dll to ASM Source
No, of course we do not have to disassemble the whole DLL and dump it to a corresponding Assembly source. Instead, what we have to do, is write a small application in high level language (you may try to do it in Assembly if you want) that would parse the export table of the original KERNEL32.dll and create a set of Assembly source files: one for code, one for data (if needed), one for import and one for export sections.
Want it or not, but the application has to generate a bit of Assembly code for at least transferring the execution flow to an API function in the original KERNEL32.dll. For example, if we have no interest in, let's say, ExitProcess, then our fake ExitProcess should look similar to this:
; As we are not tracing/logging this function, we simply let the
; original ExitProcess shoot
jmp dword [real_ExitProcess]
However, the code would be different for APIs of interest. For example, the CreateFileA API would be implemented like this:
; We pass control to a fake CreateFileA, which is implemented in
; a separate DLL imported by our fake KERNEL32.dll
; Parameters are already on the stack, so we simply jump.
; Don't forget to declare the fake function as STDCALL
; (remember #define WINAPI __declspec(stdcall) ? )
jmp dword [our_CreateFileA]
The Assembly source file containing code for the import section would then contain the following:
section '.idata' import data readable writable
library original, 'kernel32.dll',\ ;Import original KERNEL32.dll
fake, 'our_dll_with_fake_api.dll' ;Import a DLL with fake APIs
our_CreateFileA, 'whatever you call it here'
Now, finally, we get to the export section's code:
section '.edata' export data readable
export 'KERNEL32.dll',\ ;FASM does not care about what you type here,
;so let's be fake to the end and pretend
;to be KERNEL32.dll
Finally the main source file, the one that would assemble all the rest together:
format PE DLL at 0x10000000
section '.reloc' fixups data discardable
compile it with FASM and you have your fake KERNEL32.dll.
Implementation of Fake API
As it has been mentioned above, there are some functions we would want to trace. Those should have some custom implementation, preferably in a separate DLL (which would be loaded by Windows loader at the time it resolves our fake KERNEL32.dll's dependencies). Below is a diagram of the interactions between all the modules:
|Interactions between modules involved in faking.|
And here is an example of such fake API:
HANDLE WINAPI fake_CreateFileA(
fprintf(log_file, "CreateFileA(list params here)\n", params);
Of course, you may implement addition mechanisms within this DLL, e.g. let it communicate with another application via sockets or pipes, but this is deserves a separate article.
My personal suggestion is to insert more code into each function inside the fake KERNEL32.dll so that it would look more realistic to the victim process (should it try to do anything with it).
Hope this article was useful.
See you at the next.