SecurityXploded.com  
  
DLL Injection and Hooking | www.SecurityXploded.com
 
 
DLL Injection and Hooking
Author: Amit Malik 
 
 
 
See Also
 
 
 
Contents
 
 
Introduction

In this article we will learn about DLL Injection and then using it to perform Inline Hooking in remote process with practical step by step illustrations.

This is the part of our free "Reverse Engineering & Malware Analysis Course".

You can visit our training page here and all the presentations of previous sessions here

 
 

In windows each process has its own virtual address space in which it can load and unload any DLL at any time. But that loading and unloading of DLL is initiated by the process itself. Sometimes we may want to load a DLL into a process without the process knowledge.

There are many reasons (legitimate or otherwise) to do it. For example a malware author may want to hide the malicious activity by loading a DLL into a trusted process or may want to bypass security devices while on the other hand a person may want to extend the functionality of the original program. But for both the activities steps are same.

Here we will discuss on various way to Inject our code/DLL into remote process with practical examples. Then we will extend it to hook specific API function in the target process to perform our own tasks.

 
 
DLL Injection

If I am not mistaken then approximately 45-50% malwares these days use code injection to carry out the malicious activities. So it is very crucial to understand the concept of DLL injection for a malware analyst.


I will demonstrate the technique using assembly programming language. If your development environment is not ready then i would highly recommend reading my previous article on "Assembly programming basics – A beginner's guide" to get starting with assembly programming language.

There are couple of method by which we can inject DLL into a process. The latest versions of windows enforce session separation so some of the methods may not work on the latest version of windows like windows 7/8.

Couple of Dll Injection Methods:

  1. Window hooks (SetWindowsHookEX)
  2. CreateRemoteThread
  3. App_Init registry key
  4. ZwCreateThread or NtCreateThreadEx ? Global method (works well on all versions of windows)
  5. Via APC (Asynchronous procedure calls)
 

In this article I will use CreateRemoteThread [Reference 1] method because it is the simplest approach and explains the overall logic. CreateRemoteThread will not work from windows vista onwards due to Session Separation/Isolation [Reference 4]. In such case you can use similar but undocumented function, NtCreateThread [Reference 2]

In fact it is not the problem with the CreateRemoteThread, it is the CsrClientCallServer method from Ntdll that returns false. If we can patch CsrClientCallServer to return success then we can inject DLL into a process using CreateRemoteThread itself. You can read more about it here.

Here I will focus on CreateRemoteThread on windows XP.

 
 
DLL Injection using CreateRemoteThread
 
There are primarily two situations
  1. Inject DLL into a running process
  2. Create a process and Inject DLL into it.
 
#2 is more suitable for this article because in later section I will cover hooking as well. While #1 is just the part of #2.

Below is the line from MSDN about the CreateRemoteThread API.

Creates a thread that runs in the virtual address space of another process.
 

So it means CreateRemoteThread can create a thread into another process or we can say that it can execute a function into another process.

Let's look into its syntax.
      HANDLE WINAPI CreateRemoteThread(
  __in   HANDLE hProcess,                                               ?-------- 1
  __in   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in   SIZE_T dwStackSize,
  __in   LPTHREAD_START_ROUTINE lpStartAddress, ?---------2
  __in   LPVOID lpParameter,                                           ?---------3
  __in   DWORD dwCreationFlags,                                  ?---------4
  __out  LPDWORD lpThreadId                                       
); 
 
Mentioned parameters are critical for our task
  #1 – handle to the process in which the thread is to be created.
  #2 – A pointer to function or entry point of the thread that is going to be executed
  #3 – parameters to the function
  #4 – Creation state of the thread
 
We all know that kernerl32.dll export LoadLibrary API to load DLL at run time and also kernel32.dll is loaded by default into every process. So we can pass LoadLibrary address to #2 and parameter to LoadLibrary in #3. When we pass arguments in this order then CreateRemoteThread will execute LoadLibrary with its parameter in another process and hence loads the DLL into external process.

The only problem here is that parameter to LoadLibrary must be in target process. For example if we use LoadLibrary (#2) with "mydll.dll"(#3) as parameter to Loadlibrary then the name "mydll.dll" must be in our target process. 

Fortunately windows provide API to do that as well. We can write into any process using WriteProcessMemory and can allocate space into another process using VirtualAllocEx API. But Before that we need handle to our process, we can get that using OpenProcess or CreateProcess API.

So our order will be:

  1. Use OpenProcess or CreateProcess API to get the handle of our target process
  2. Use VirtualAllocEx to allocate space into our target process
  3. Use WriteProcessMemory to write our DLL name into our target process
  4. Use CreateRemoteThread to inject our DLL into our target process
 
Above steps are enough to inject our DLL into a process. Although to inject into a system process we first have to set se_debug privilege to our process (means the process that will inject DLL into another process) but for simplicity I am ignoring that part.

If you remember "two situations" from the beginning of this part then we need a bit of more work for #2 i.e Create a process and Inject DLL into it.

We first have to create a process and after that we will use above steps to inject our DLL into newly created process.

Let's look into CreateProcess syntax:

BOOL WINAPI CreateProcess(
  __in_opt     LPCTSTR lpApplicationName,
  __inout_opt  LPTSTR lpCommandLine,
  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in         BOOL bInheritHandles,
  __in         DWORD dwCreationFlags,               ?-------- 1
  __in_opt     LPVOID lpEnvironment,
  __in_opt     LPCTSTR lpCurrentDirectory,
  __in         LPSTARTUPINFO lpStartupInfo,
  __out        LPPROCESS_INFORMATION lpProcessInformation
);
      
 
Here dwCreationFlags is the important parameter.  If you look into its definition on MSDN then you will see that it is used to control the creation of a process. We can set it to "CREATE_SUSPENDED" to create a process into suspended mode.


With CREATE_SUSPENDED flag CreateProcess will create the process and stop the execution of the main thread at the entry point of the thread. To start the process we can use ResumeThread API.

So our steps will be
  1. Create Process in suspended state
  2. Inject DLL into the process using above steps
  3. Resume the process
 
Here is the complete program which mimics above steps
 
;Author: Amit Malik
;http://www.SecurityXploded.com
;No error checking

.386
.model flat, stdcall
option casemap:none

include windows.inc
include msvcrt.inc
include kernel32.inc

includelib kernel32.lib
includelib msvcrt.lib

.data
greet	db	"enter file name: ",0
sgreet	db	"%s",0
dreet	db	"enter DLL name: ",0
dgreet	db	"%s",0
apiname	db	"LoadLibraryA",0
dllname	db	"kernel32.dll",0

.data?
processinfo	 PROCESS_INFORMATION <>
startupinfo	STARTUPINFO <>
fname	db	20	dup(?)
dname	db	20	dup(?)
dllLen	dd	?
mAddr	dd	?
vpointer	dd	?
lpAddr	dd	?


.code
start:

invoke crt_printf,addr greet
invoke crt_scanf,addr sgreet,addr fname
invoke crt_printf,addr dreet
invoke crt_scanf,addr dgreet,addr dname
invoke LoadLibrary, addr dllname
ov mAddr,eax
invoke GetProcAddress,mAddr,addr apiname
mov lpAddr,eax

;create process in suspended state
invoke CreateProcess,addr fname,0,0,0,0,CREATE_SUSPENDED,0,0,addr startupinfo,addr processinfo
invoke crt_strlen,addr dname
mov dllLen,eax

; Allocate the space into the newly created process
invoke VirtualAllocEx,processinfo.hProcess,NULL,dllLen,MEM_COMMIT,PAGE_EXECUTE_READWRITE
mov vpointer,eax

; Write DLL name into the allocated space
invoke WriteProcessMemory,processinfo.hProcess,vpointer,addr dname,dllLen,NULL

; Execute the LoadLibrary function using CreateRemoteThread into the previously created process
invoke CreateRemoteThread,processinfo.hProcess,NULL,0,lpAddr,vpointer,0,NULL
invoke Sleep,1000d

; Finally resume the process main thread.
invoke ResumeThread,processinfo.hThread
xor eax,eax
invoke ExitProcess,eax

end start
      
 
Select console application in WinAsm and assemble the above code.  It should create a process and inject our DLL into it.

For eg: you can create calc.exe process and can inject urlmon.dll into it, by default calc.exe doesn't load urlmon.dll.
 
 
 
Hooking
 
Here is definition of Hooking from Wikipedia
 
In computer programming, the term hooking covers a range of techniques used to alter or augment the behaviour of an operating system, of applications, or of other software components by intercepting function calls or messages or events passed between software components. Code that handles such intercepted function calls, events or messages is called a "hook"
 
Hooking is the most powerful technique available in computer software. A person can do almost everything on a system by applying hooks on the right locations.

As stated in the definition that in hooking we intercept function calls or messages or events. Because it is taking the advantage of flow of execution so we can apply hooks on multiple locations from original file to system calls.

Primarily Hooks can be divided into two parts
  1. User mode hooks
    1. IAT (Import Address Table) Hooking
    2. Inline Hooking
    3. Call Patching in binary etc..
  2. Kernel Mode hooks
    1. IDT Hooking
    2. SSDT Hooking etc..
 
In this article I will discuss Inline hooking technique which is one of the more effective hooking techniques.

 
 
Inline Hooking
 
In Inline hooking we overwrite the first 5 byte of the function or API to redirect the flow of execution to our code. The 5 bytes can be JMP, PUSH RET or CALL instruction.

Visually it can be explained by the following figures
 

Screenshot 1: Normal Call (Without hooking)

 
 
Screenshot 2: Call after hooking
 
 
As you can see in the above picture that the MessageBox function starting bytes are overwritten by JMP to MyHandler function. In MyHandler function we do our stuff and then transfer the control back to original function i.e MessageBox.

Now let's create a DLL that will hook MessageBox API and display our custom message instead of the real message.


To make a DLL we need following things:

  1. MessageBoxA API address i.e pointer
  2. Our function or code address i.e pointer
 

We can get MessageBoxA Api address using GetProcAddress.

Here are the steps:

  1. Get MessageBoxA address
  2. Get custom code or function address
  3. Overwrite bytes at #1 with JMP to #2
  4. Modify the parameter of original call
  5. Transfer control back to #1
 
Here is the complete code deomonstrating Inline Hooking MessageBox function
 
;Author: Amit Malik
;http://www.SecurityXploded.com
;No error checking

.386
.model flat,stdcall
option casemap:none

include windows.inc
include kernel32.inc
include msvcrt.inc
include user32.inc


includelib kernel32.lib
includelib msvcrt.lib
includelib user32.lib


.data

tszMsg		db	"Hello from Hooking Function",0
userDll		db	"user32.dll",0
msgapi		db	"MessageBoxA",0


.data?
oByte1	dd	?
oByte2	dd	?
userAddr	dd	?
msgAddr	dd	?
nOldProt	dd	?

.code 
LibMain proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
 .if reason == DLL_PROCESS_ATTACH 
	invoke LoadLibrary,addr userDll
	mov userAddr,eax
    
	; Get MessageBoxA address from user32.dll
	invoke GetProcAddress,userAddr,addr msgapi
	mov msgAddr, eax
	
    ; Set permission to write at the MessageBoxA address
	invoke VirtualProtect,msgAddr,20d,PAGE_EXECUTE_READWRITE,OFFSET nOldProt
	
    ; Store first 8 byte from the MessageBoxA address
	mov eax,msgAddr
	mov ebx, dword ptr DS:[eax]
	mov oByte1,ebx
	mov ebx, dword ptr DS:[eax+4]
	mov oByte2,ebx

	patchlmessagebox:
		; Write JMP MyHandler (pointer) at MessageBoxA address
		mov byte ptr DS:[eax],0E9h
		; move MyHandler address into ecx
		mov ecx,MyHandler
		add eax,5
		sub ecx,eax
		sub eax,4
		mov dword ptr ds:[eax],ecx
		
    .elseif reason == DLL_PROCESS_DETACH 
    .elseif reason == DLL_THREAD_ATTACH
    .elseif reason == DLL_THREAD_DETACH
    .endif
    ret
LibMain endp


MyHandler proc
		pusha
		xor eax,eax
		mov eax,msgAddr
		
        ; change the lpText parameter to MessageBoxA with our text 
		mov dword ptr ss:[esp+028h],offset tszMsg
		
        ; Restore the bytes at MessageBoxA address
		mov ebx,oByte1
		mov dword ptr ds:[eax],ebx
		mov ebx,oByte2
		mov dword ptr ds:[eax+4],ebx
		
        ; Restore all registers
		popa
		
        ;jump to MessageBoxA address (Transfer control back to MessageBoxA)
		jmp msgAddr
MyHandler endp

end LibMain
  
      
 
Select standard DLL under "New Project" tab in WinAsm and paste the above code into the editor area and assemble it.

Now we have our DLL that will hook MessageBoxA and change the lpText parameter to our message.
We will inject this DLL into a "Hello world" program that I shown in my previous article "Assembly Programming – A beginner's guide"  with the help of our DLL inject program.

The output is shown in the below picture:

 
 
 
 
Conclusion
 

Both DLL injection and Hooking are powerful techniques and popularly used by malicious software as well as legitimate software from the years.

But as the saying goes if you have nuclear power then it is entirely depends on you whether you make a nuclear missile or use that power for solving problems.

 
 
 
References
  1. Three ways to inject code into another process
  2. Remote Thread Execution in System Process using NtCreateThreadEx for Vista & Windows7
  3. MSR Detour Project - Hook SDK
  4. Impact of Session 0 Isolation on Injection
 
 
See Also