Over the period of time , several code injection / DLL injection techniques have been developed and used by malware authors for covert launching of malicious code . Injecting DLL into other legitimate process is a very well known and well documented technique to hide the execution of malicoius code . Several such DLL injection techniques have already been known for years . For instance , DLL can be injected into another process using known process enumeration APIs and then opening the handle to the targetted process using OpenProcess ( ) , subsequently allocating the memory using VirtualAlloc ( ) , doing the WriteProcessMemory( ) , and finally creating the remote thread using CreateRemoteThread ( ) . Similar goal can be achieved by direct code injection and setting the thread context to the injected code using SetThreadContext ( ) and executing the injected code in the targetted process .
I recently came across the malware that used another flavour of DLL injection known as Asynchronous Procedure Calls ( APC ) injection . The precise idea behind this mechanism is : If you can figure out the thread in the remote process which is in the alertable state or which is likely to go into alertable state, you can queue custom code to that thread which will be executed before the thread resumes . Threads can go into alertable state by calling APIs like WaitForSingleObjectsEx ( ) . Fortunately , for malware authors , finding such a target thread is not a difficult job . There will be several threads already into that state .
Let's check how this goal is achieved in the recent malware that I analysed . I wont be digging into the full functionality of this malware but just the APC injection part . Initially , malware seems to have a corrupted import table so we'll have to allow it to construct it , until it is done with all the GetProcAddress( ) calls.
If we look at the API trace , we will see some of the functions being resolved during the initial execution of the malware as shown below .
After resolving all the function names , as you can see it drops the file linkinfo.dll into the windows directory. We will see along the way at later point of time , this DLL will be queued for loading in the remote process .
FYI : Linkinfo.dll is basically a legitimate component in Windows which tracks the volume information / removable media . It can intercept all the write calls to the disk and ensures that data gets written on the correct disk volume . More info about this here.
As expected , it follows the usual process and sequence of API calls to find the target process to inject into. Calls CreateToolhelp32Snapshot ( ) to get the snapshot of the all the running process , threads , modules used and then enumerates over the list to find the target process . Apparently it can be noticed , that it targets "explorer.exe" process .
Matching the explorer.exe , it allocates the virtual memory page into the process and then calls WriteProcessMemory ( ) to write the path to the "linkinfo.dll" into the allocated space.
Here is the memory map of the explorer.exe and we can notice the virtual memory being allocated and path to the DLL to be loaded written
Until this point , malware follows the usual DLL injection sequence , but difference at this point here is to find the target thread in the explorer.exe . It enumerates the running threads inside the explorer.exe and determines the thread to queue a call . Let's see how it does that . It calls the Thread32First ( ) and Thread32Next ( ) with the same process handle 5EC ( explorer.exe )
Enumerating all the threads , it finally ends up finding the thread identifier for the main thread of the explorer.exe process ( Ident : 5F0 ) :
and subsequently , opens the handle to the thread :
and then finally , calls QueueUserAPC ( ) to queue the call to the LoadLibraryA for the opened thread .
Details of the QueueUserAPC ( ) API is available on MSDN. And here we see . Linkinfo.dll being loaded into explorer.exe . Mission over..!!..
APC injection is one of the method of DLL injection into the remote process . This is usually done from the user space as demoed in this blog . This goal can also be achieved from the kernel space by calling corresponding kernel APIs.
Very Nice Blog and informative, well done keep rocking Chintan! :)
ReplyDelete