Introduction
If Windows is made to protect against API hooking, Trojan horses would not have effected our systems. I believe it is a loop hole from Microsoft. But from a programmer's point of view, it is a kernel level approach to PE (Portableexecutable) signature modification. API Hooking is one of the most crooked methods to get all the information of anexecutable without modifying its code. Firstly I will remind you about one thing, never ever use any content of my article for wrong purposes.
Before going to API hooking, you need to know about DLL Injection, which is a primary step for API hooking. In normal conditions, you cannot create a pointer that is referenced to another process. To achieve this, we need to inject our code into another process.
Let us familiarize ourselves with DLL Injection. DLL injection is a technique by which you can inject your own DLL into a third party executable without modifying the third party executable’s code. DLL Injection can be achieved in a number of methods, they are:
- Injecting a DLL using registry
- Injecting a DLL using Windows hook
- Injecting a DLL using remote thread
- Injecting a DLL with Trojan DLL
- Injecting a DLL as a debugger
Well for this article, we are just dealing with method 3, i.e., injecting a DLL using remote thread.
Background
In this technique, we have to load our DLL into a third party process with the help of LoadLibrary
API ofKernel32.dll.
The main difficulty in loading a DLL into another process is that, you cannot control the third party process’s thread. It is necessary for us to create our own thread in that process, for this Windows itself provides theWINAPI
CreateRemoteThread
, where we can specify the destination process handle as a parameter. I will give you a detailed explanation about the APIs and their use in the code section.
To explain API hooking technique, I am introducing 3 components in the sample attached with this article that will explain how to hook an API. Here I am hooking the API LoadLibrary
(LoadLibraryA
).
Three components that are attached with this article are:
- APIHandler.exe: This EXE will inject DLL into some other application with the help of DLLCheck.dll.
- DLLCheck.dll: DLL to be injected into third party application.
- SampleUsingLoadLibrary.exe: Third party application, actually this application is hooked.
APIHandler.exe has the DLL path (give the path of DLL to be injected) and Injected EXE is the EXE to which our DLL is to be injected. Once our DLL is injected, it will work such that, it the part of SampleUsingLoadLibrary.exe.
The method is a little twisted, once DLLCheck.dll is injected into the EXE,
the next job for the DLLCheck.DLL is to find the address of the function name (LoadLibrary
)
to be hooked. It can be achieved by parsing the PE file (ourexecutable SampleUsingLoadLibrary.exe)
and finding IMAGE_IMPORT_DESCRIPTOR
(this data structure holds the import table information of the PE file) of Kernel32.dll inside
the executable, which holds the address of LoadLibrary
in
our case.
Once we get the address of LoadLibrary
API of the kernel32 loaded in the EXE,
the next step is to find the address (using GetCurrentFunctAddr
of DLLCheck.dll,
refer to the code section) of our native API (MyFunction
) and replace the load address using VirtualProtect
WinAPI,
which makes the function address changing possible inside a remote thread without the protection fault error.
Once the above mentioned steps are done, our function will have the loaded address of LoadLibrary
API inside the third
party EXE, so whenever a call to LoadLibrary
function
of Kernel32.dll is invoked inside that third party EXE,
under the hood, our function will be invoked, i.e. our MyFunction
API, since address is changed in PE. These are based
on modifying the PE(Portable Executable) signature of EXE.
We modified the IMPORT
table of Kernel32.dll loaded inside
our executable. Very simple and effective method. To understand more, let us go
in detail with the code.
Using the Code
This code explains the stages of the API redirection:
// To Inject a DLL, we need three steps in APIHandler side.
// Allocate memory in the remote process for our library
// with write permission using the below mentioned WINAPI.
HANDLE hProc;
pLibRemote = ::VirtualAllocEx( hProcess,
NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );
// This API writes the library path name to third party process.
::WriteProcessMemory( hProcess, pLibRemote, (void*)szLibPath,
sizeof( szLibPath ), NULL );
// Load the DLL to third party process by creating a thread in that
// process, using the below mentioned WIN API, this API enable
hThread = ::CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)::GetProcAddress( hKernel32,"LoadLibraryA" ),
pLibRemote,0,NULL );
// The below mentioned code is from Injected DLL part, i.e. DLLCheck.DLL
// To redirect LoadLibrary API with our MyFunction we have do certain steps
// We have parse the PE file of third party EXE and find the import table and find
// the address of the Loadlibrary API in reference to the executable base address.
// This function gets the address of the import descriptor table.
IMAGE_IMPORT_DESCRIPTOR* GetImportDescriptor(HMODULE hMod, char* pszDllName )
{
// Get the DOS Header from which we can get the optional header.
IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)hMod;
IMAGE_OPTIONAL_HEADER* pOptionHeader = (IMAGE_OPTIONAL_HEADER*)((BYTE*)hMod +
pDOSHeader->e_lfanew + 24);
// To get the IMport descriptor datastructure.
IMAGE_IMPORT_DESCRIPTOR* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hMod +
OptionHeader->DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
char* pszImpAddr = 0;
// Iterate through the IMPORT DESCRIPTOR till we find the address of
// Kernel32.dll in our case, since LoadLibrary is from Kernel32.dll
while( pImportDesc->FirstThunk)
{
// Get the load address of the DLL.
pszImpAddr = (char*)(( BYTE* )hMod+ pImportDesc->Name );
if( stricmp( pszDllName, pszImpAddr ))
{
pImportDesc++;
continue;
}
else
{
return pImportDesc;
}
}
return NULL;
}
// This function gets the address of the LoadLibraryA function.
DWORD* GetCurrentFunctAddr( HMODULE hMod,
IMAGE_THUNK_DATA* pOriginalFirstThunk,
IMAGE_THUNK_DATA* pFirstThunk,
char* pszFunctionName )
{
// From the IMAGE thunk datastructure we
// get the address of the imported function.
char* szTest;
while(pOriginalFirstThunk->u1.Function)
{
// Get the import load address of the function,
// in our case LoadLibraryA.
szTest = (char*)((BYTE*)hMod +
(DWORD)pOriginalFirstThunk->u1.AddressOfData+2);
if(stricmp(pszFunctionName,szTest)==0)
{
return &pFirstThunk->u1.Function;
}
pOriginalFirstThunk++;
pFirstThunk++;
}
return NULL;
}
// Once address is found, we have to redirect using the VirtualProtect WinAPI
// that enables write permission to third party EXE.
bool ChangeAddress(DWORD* dwOldAddress,DWORD dwNewAddress)
{
// Change the old address of the function with the new address.
// Firstly this address is changed.
DWORD dwOld;
if (!(VirtualProtect(dwOldAddress,4,PAGE_READWRITE,&dwOld)))
{
return false;
}
*dwOldAddress = dwNewAddress;
// Once changed it updated in the executable.
if (!(VirtualProtect(dwOldAddress,4,PAGE_EXECUTE,&dwOld)))
{
return false;
}
else
{
OutputDebugString( "Change Address Final.." );
return true;
}
}
Points of Interest
API hooking is one of the most widely used techniques by hackers for creating Trojan, which will help them keep track of the system information, and anti virus companies around the globe use the low level API hooking to make antispyware. My intention with this
article is just to make you familiar with API hooking and the vulnerabilities that are in your system without your prior knowledge. My article explained a useful API hooking, which will help you to keep track of the libraries that are loaded using LoadLibrary
API
in a particular EXE, which is never possible with a dependency walker. This is
an ASCII version that will hook only LoadLibraryA
. If you want to hook Unicode DLLs, then hook LoadlbraryW
.
If you have any doubts, please feel free to ask me, if my Allah gives me the opportunity, I will write more articles of your interest.
History
- Version 1.0