Beruflich Dokumente
Kultur Dokumente
t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
jona.t4
To change code in another process we must load our own shared library in the address space of the other
process. On UNIX platforms (Linux/MAC-OSX) this can be achieved using the LD_PRELOAD
environment variable, which instructs the loader to load the specific shared libraries. Function and other
symbol definitions in the specified libraries will be used instead of the original ones.
However on Windows systems there is no such thing as LD_PRELOAD, to achieve the same result we must
use a little exploit called DLL Injection (On Windows shared libraries are .DLL's, on Linux .so's and on
MAC-OSX .dylib's). See Appendix A below for more information.
§2.1 UNIX/Linux
UNIX offers a simple way to override functions in a shared library with the LD_PRELOAD environment
variable. When you make a twin brother of a function that is defined in an existing shared library, put it in
your shared library, and you register your shared library name in DYLD_INSERT_LIBRARIES, your
function is used instead of the original one. It is exactly the same as MAC-OSX (see below) but use
LD_PRELOAD instead of DYLD_INSERT_LIBRARIES .
§2.2 MAC-OSX
Since MAC-OSX is also UNIX based it's almost exactly the same as in Linux, only they have renamed
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 1/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
LD_PRELOAD to DYLD_INSERT_LIBRARIES and .so to .dylib. In this example I've detoured fopen
from a test program. In 2003 Jonathan Rentzsch showed ways of detouring in MAC-OSX and released
mach_star, but this method is way easier.
#include <stdio.h>
#include <dlfcn.h>
FILE* fopen(const char *path, const char *mode)
{
printf("Detoured fopen\n");
FILE* (*real_fopen)(const char*, const char*) =
(FILE* (*)(const char*, const char*)) dlsym(RTLD_NEXT, "fopen");
return real_fopen (path, "r"); // note r instead of w, this will prevent the program from creating f
}
You also need to define DYLD_FORCE_FLAT_NAMESPACE (doesn't matter what value it has).You can
use the same technique to override a method in a class. Say there's a method named "libfff" in a class AAA.
class AAA
{
public:
int m;
AAA(){m = 1234;}
void libfff(int a);
};
To override it, you first need to know the mangled symbol name of the method.
Then what you need to define is _ZN3AAA3fffEi. Don't forget removing the first '_'. If you see multiple
symbols in the shared library and not sure which one to override, you can check it by de-mangling a symbol.
$ c++filt __ZN3AAA3fffEi
AAA::libfff(int)
This is the framework of a standard API hook. All of this resides in a DLL that will be injected into a
process. For this example, I chose to hook the MessageBoxW function. Once this DLL is injected, it will get
the address of the MessageBoXW function from user32.dll, and then the hooking begins. In the
BeginRedirect function, an unconditional relative jump (JMP) opcode (0xE9) instruction will contain the
distance to jump to. The source is fully commented.
#include <windows.h>
#define SIZE 6
typedef int (WINAPI *pMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT); // Messagebox protoype
int WINAPI MyMessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT); // Our detour
void BeginRedirect(LPVOID);
pMessageBoxW pOrigMBAddress = NULL; // address of original
BYTE oldBytes[SIZE] = {0}; // backup
BYTE JMP[SIZE] = {0}; // 6 byte JMP instruction
DWORD oldProtect, myProtect = PAGE_EXECUTE_READWRITE;
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH: // if attached
pOrigMBAddress = (pMessageBoxW)
GetProcAddress(GetModuleHandle("user32.dll"), // get address of original
"MessageBoxW");
if(pOrigMBAddress != NULL)
BeginRedirect(MyMessageBoxW); // start detouring
break;
case DLL_PROCESS_DETACH:
memcpy(pOrigMBAddress, oldBytes, SIZE); // restore backup
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
void BeginRedirect(LPVOID newFunction)
{
BYTE tempJMP[SIZE] = {0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3}; // 0xE9 = JMP 0x90 = NOP oxC3 =
memcpy(JMP, tempJMP, SIZE); // store jmp instruction to JMP
DWORD JMPSize = ((DWORD)newFunction - (DWORD)pOrigMBAddress - 5); // calculate jump distance
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, // assign read write protection
PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(oldBytes, pOrigMBAddress, SIZE); // make backup
memcpy(&JMP[1], &JMPSize, 4); // fill the nop's with the jump distanc
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 3/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
memcpy(pOrigMBAddress, JMP, SIZE); // set jump instruction at the
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, NULL); // reset protection
}
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType)
{
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, myProtect, NULL); // assign read write protection
memcpy(pOrigMBAddress, oldBytes, SIZE); // restore backup
int retValue = MessageBoxW(hWnd, lpText, lpCaption, uiType); // get return value of original
memcpy(pOrigMBAddress, JMP, SIZE); // set the jump instruction aga
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, NULL); // reset protection
return retValue; // return original return value
}
The reason why we restore the backup before getting the return value is because if we don't do it we will get
an infinite loop, we call a function that jumps to the function that calls the function again etc etc.. If you
change the parameters of the call to MessageBoxW inside MyMessageBoxW every messagebox that the
DLL is injected to will have those parameters. See appendix C for the MS-Detours method which is way
easier and recommended.
See the diagram:
// main()
void *dllString, *vfunc;
unsigned long ulproc_id, threadID, funcLen, oldIP, oldprot, loadLibAddy;
HANDLE hProcess, hThread;
CONTEXT ctx;
To continue we'll need a handle to a thread in the process, to achieve this one can use this function show in
block A-2.
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 4/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
unsigned long GetThreadFromProc(char *procName) { // block A-2
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE) {
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval) {
if(StrStrI(pe.szExeFile, procName) ) {
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
This is a prototype for the function we are going to allocate in the target process which will call loadlibrary,
the addresses are left blank because we patch them later on when we have the right values.
Now, we need to pause the thread in order to get it's "context". The context of a thread is the current state of
all of it's registers, as well as other peripheral information. However, we're mostly concerned with the EIP
register, which points to the next instruction to be executed. So, if we don't suspend the thread before
retrieving its context information, it'll continue executing and by the time we get the information, it'll be
invalid. Once we've paused the thread, we'll retrieve it's context information using the GetThreadContext()
function. We'll grab the value of the current next instruction to be executed, so that we know where our
function should return to. Then it's just a matter of patching up the function to have all of the proper
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 5/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 6/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
There is another way using the CreateRemoteThread call. It is extremely easy, and relatively efficient.
Before starting though, it is important to actually find the process to inject into. The Windows API provides
a great function for doing this – CreateToolhelp32Snapshot.
#undef UNICODE
#include <vector>
#include <string>
#include <windows.h>
#include <Tlhelp32.h>
using std::vector;
using std::string;
int main(void) {
vector<string>processNames;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
BOOL bProcess = Process32First(hTool32, &pe32);
if(bProcess == TRUE) {
while((Process32Next(hTool32, &pe32)) == TRUE)
processNames.push_back(pe32.szExeFile); // store every process name
}
CloseHandle(hTool32);
return 0;
}
I didn’t bother storing the value after I called Process32First because that will always be “[System Process]”,
so there’s really no need. Process32Next returns TRUE on success, so just simply putting it in a loop and
pushing the name of the process it received in a vector is what is needed. Once the loop is finished, every
single process should be stored in processNames. This is great and all, but where does the DLL injection
come in? Well, the PROCESSENTRY32 structure also has a member that holds the Process ID. Inside that
loop, while we’re pushing the process names in our vector, we’re also going to inject the DLL.
The code above is pretty straightforward, we first get the current directory and append our dll name to it so
we can later allocate it in the target process memory. Then we create a new thread which calls loadlibrary
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 7/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
One section of note is the import address table (IAT), which is used as a lookup table when the application is
calling a function in a different module. It can be in the form of both import by ordinal and import by name.
Because a compiled program cannot know the memory location of the libraries it depends upon, an indirect
jump is required whenever an API call is made. As the dynamic linker loads modules and joins them
together, it writes actual addresses into the IAT slots, so that they point to the memory locations of the
corresponding library functions. Though this adds an extra jump over the cost of an intra-module call
resulting in a performance penalty, it provides a key benefit: The number of memory pages that need to be
copy-on-write changed by the loader is minimized, saving memory and disk I/O time. If the compiler knows
ahead of time that a call will be inter-module (via a dllimport attribute) it can produce more optimized code
that simply results in an indirect call opcode.
int ip = 0;
if (module == 0)
module = GetModuleHandle(0);
then we retrieve the headers (warning:Whoever wrote the header file for the PE format is certainly a believer
in long, descriptive names, along with deeply nested structures and macros. When coding with WINNT.H,
it's not uncommon to have mind blowing expressions):
Now we basicly have enough information to start making the loops to the function pointer, note that every
DLL has its own IMAGE_IMPORT_DESCRIPTOR that's why we loop through all of them:
for (IMAGE_IMPORT_DESCRIPTOR* iid = pImgImportDesc; iid->Name != NULL; iid++){}
And inside this loop, we loop through the functions, if you add an int to the firsthunk you get to the next
thunk and so on.
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 8/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
Now if you look in the import_desciptor structure you can see the name is on firsthunk +2 so
when we have the name we can compare it with our target and patch the address.the function will look like
this:
First of all you need to make sure you have MS-Detours 1.5 downloaded and added the corresponding files
to your project. I am using version 1.5 because it's the simplest to use, and it does the job nicely.
There is one important function we are going to use, its called DetourFunction. First we are going to need a
typedef of the function we are going to hook (endscene in this case, since it gets called AFTER the drawing
so we can add code right before that).
Now to actually hook endscene we need to retrieve the address of the original function, this can be done in
two ways, the first way is to reverse a sample direct3d program to find the address of the endscene call and
add that to the module base of d3d9.dll. And the second way is to use the GetProcAddress function. The
problem with the first way is that it is platform dependent, the address is different on 64bit Windows from
the 32bit version.
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 9/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
HMODULE hd3d9 = GetModuleHandle("d3d9.dll");
// detourfunction from ms-detours, the first parameter is the original address and the second is our
oEndScene = (tEndScene)DetourFunction( (LPBYTE)GetProcAddress(hd3d9, "EndScene" ), (LPBYTE)&mEndSc
// where our detour function would look something like this
HRESULT WINAPI hkEndScene(LPDIRECT3DDEVICE9 pDevice){
// do evil
return oEndScene(pDevice);
}
What we did here is retrieve the address with GetProcAddress and pass it as the first parameter, the second
parameter is a pointer to our own detour function (hkEndScene). Now you can add drawing function to the
original program, benchmarking programs make good use of this.
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 10/12
3/31/2018 jona.t4: Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX
this call.
enum SYSTEM_INFORMATION_CLASS
{
SystemProcessInformation = 5
};
struct SYS_PROCESS_INFO
{
ULONG NextEntryOffset; // next entry
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName; // Process name
};
NTSTATUS (__stdcall *origNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
Now all is left is define our detour function and use mhook to hook it.
First i will show our detour function.
What we basically do here is create a loop that checks every process name, once we found our process name
we skip our process and return the original call (without our process). Now we hook it using mhook.
http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html 11/12