Read string out of a process memory - c++

const char* GetName()
{
std::string s = *(std::string*)(this + 0x28);
return s.c_str();
}
Update:
struct Entity
{
static Entity* GetCurrentPlayer()
{
return (Entity*)(*(DWORD*)((DWORD)GetModuleHandleA("League of Legends.exe") + (DWORD)ADR_LocalPlayer));
}
}
Update2:
Actually, all i need to do is the same like Cheat Engine does: Read the string located at some pointer (this) + Offset 0x28 returned as const char* as i need this datatype right after.
I also tried directly accessing the address with const char*, this gave me cryptic symbols. Example at the top is crashing the game.
I guess i either need another datatype or another way to access the data?!
Note: This is an injected DLL and i'm accessing the data via an address

I think this is what you need, set the target address to Read, Write and Execute (if you even want to change code).
VirtualProtect((LPVOID)targetaddress,5,PAGE_EXECUTE_READWRITE,&oldp);
This is a full scenario:
Write a DLL with a shared memory section. The DLL should be linked to your main application to enable receiving notifications or data (the string), and to enable sending commands from your main app if you need to control the remote process.
Your main application should create the remote thread, the code in that thread would be to Load the DLL into the remote process, and then the DLL should take over from there.
Using the inter-process communication mechanism of your choice, start sending/receiving data between the remote process and your main application.
Here's a DLL injection function (in your main app) to inject your DLL into the remote process:
int Inject(char *fname,char *dllname,int NewProcess,DWORD PID) // 1=new process, 2= PID, 3=current process
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
BOOL rv;
void *pr;
HANDLE hh;
SIZE_T bwrit;
DWORD par,tid;HANDLE th;
FARPROC LoadLibProc = GetProcAddress(GetModuleHandleA("KERNEL32.dll"), "LoadLibraryA");
FARPROC ExitThreadProc = GetProcAddress(GetModuleHandleA("KERNEL32.dll"), "ExitThread");
char InjectedCode[500] =
{// 0xcc,
0x60, // pushad
0xB8, 00, 00, 00, 00, // mov EAX, 0h | Pointer to LoadLibraryA() (DWORD)
0xBB, 00, 00, 00, 00, // mov EBX, 0h | DLLName to inject (DWORD)
0x53, // push EBX
0xFF, 0xD0, // call EAX
0x5b, // pop EBX
0xB8, 00, 00, 00, 00, // EAX 2 mov EAX, 0h | Pointer to ExitThreadProc() (DWORD)
0x6a,00, // Push 00
0xFF, 0xD0, // call EAX
//0xcc // INT 3h
0x61, // popad
//0xcc
// 0xc3 // ret
};
int nob=30;
char *DLLName;
DWORD *EAX, *EBX, *EAX2;
DLLName = (char*)((DWORD)InjectedCode + nob);
strcpy( DLLName, dllname );
EAX = (DWORD*)( InjectedCode + 2);
EBX = (DWORD*) ( InjectedCode + 7);
EAX2 = (DWORD*)( InjectedCode + 16);
*EAX=(DWORD)LoadLibProc;
*EAX2=(DWORD)ExitThreadProc;
*EBX=nob;
ZeroMemory((VOID*)&si, sizeof(si));
si.dwFlags=STARTF_USESHOWWINDOW;//1
si.wShowWindow=SW_HIDE;//0
if (NewProcess==1) {
rv=CreateProcessA(fname,0,0,0,FALSE,CREATE_SUSPENDED,0,0,&si,&pi);
if (rv==FALSE) {return -1;}
hh=pi.hProcess;
}
TCHAR bb[200];
if (NewProcess==2) {////PROCESS_ALL_ACCESS
hh=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION ,0,PID);
if (hh==NULL) return -6;
}
if (NewProcess==3) {
hh=GetCurrentProcess();
}
//if (hh==INVALID_HANDLE_VALUE) {printf("\nError Opening Process...");return;}
pr=VirtualAllocEx(hh,0,500,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (pr==NULL) return -7;
Sleep(100);
//printf("\nAddress Allocated=%x",pr);
*EBX+=(DWORD)pr;
rv=WriteProcessMemory(hh,pr,InjectedCode,500,&bwrit);
if (rv==0) return -8;
th=CreateRemoteThread(hh,NULL,0,(LPTHREAD_START_ROUTINE)pr,&par,0,&tid);
if (th==NULL) return -9;
return 0;
}
Now for the DLL, in your DLL CPP, add the shared memory section to hold data for inter-process communication:
#pragma data_seg("shared")
char whateverdatatoshare[16384]={0};
// you can also define events or variables to use to signal the remote process or the main app of any incoming data
#pragma data_seg()
#pragma comment(linker, "/section:shared,rws") // This instructs the linker to make this section readable,writable and shared
In your APIENTRY dllmain function, create a thread to do whatever you want, like reading your string or data every second to send it back to the main app.
BOOL APIENTRY DllMain1( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
DWORD par,tid;
HANDLE thandle;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
thandle= CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&MsgThread,&par,0,&tid);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
The your thread code should do the actual work of sniffing the string you want.
Very Important: To make sure you can read/write in memory, use this:
First set the page to PAGE_EXECUTE_READWRITE
**VirtualProtect((LPVOID)targetaddress,5,PAGE_EXECUTE_READWRITE,&oldp);**
Second: IsBadWritePtr or IsBadReadPtr, to make sure you can write or read.

As Steve already mentioned you won't be able to access an other application's memory since it is protected by the OS. You can check that by running two little programs, the first creates a variable, stores its pointer in a file and keeps running after that (by waiting for user input or whatever). The second program reads the pointer from the file and then tries to use its content. Won't work.
Furthermore check out the documentation for GetModuleHandleA: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683199%28v=vs.85%29.aspx
It says:
"Retrieves a module handle for the specified module. The module must have been loaded by the calling process."
And:
"The name is compared (case independently) to the names of modules currently mapped into the address space of the calling process."
As you want to get a module which was loaded by another process this won't work either.

Related

Accessing Memory in DLL Injection results in Memory Access Violation

I recently started trying to get into game hacking to develop my reverse engineering skills. I am running Windows 10. For now, I am trying to write a basic DLL Injection program that will let me read certain bytes from the game and print them out. Unfortunately, when I inject my DLL the game immediately crashes with the following log recovered from Windows Event Viewer:
Faulting application name: game_to_hack.exe, version: 2019.4.19.23316, time stamp: 0x6007d1a6
Faulting module name: IL2CppDLL.dll, version: 0.0.0.0, time stamp: 0x618dc9c6
Exception code: 0xc0000005
Fault offset: 0x0000000000248f48
Faulting process id: 0x8ca8
which seems to indicate a memory access violation on the given address.
The code for my DLL is relatively simple. There is a class which is supposed to scan the game for a certain pattern of bytes:
class SigScan
{
public:
// For getting information about the executing module
MODULEINFO GetModuleInfo(char *szModule)
{
MODULEINFO modinfo = { 0 };
HMODULE hModule = GetModuleHandle(szModule);
if (hModule == 0)
return modinfo;
GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(MODULEINFO));
return modinfo;
}
// for finding a signature/pattern in memory of another process
DWORD FindPattern(char *module, char *pattern, char *mask)
{
MODULEINFO mInfo = GetModuleInfo(module);
DWORD base = (DWORD)mInfo.lpBaseOfDll;
DWORD size = (DWORD)mInfo.SizeOfImage;
DWORD patternLength = (DWORD)strlen(mask);
char test = *(char*)base; // <- This is the memory access that causes the crash.
// TODO: Actually scan for the pattern
};
My dllmain.cpp then uses the above class to try and find the pattern:
void Run()
{
SigScan Scanner;
// It's a Unity game.
char proc_name[] = "gameassembly.dll";
char byte_sequence[] = "\x48\x8b\xc4\x48\x89\x58\x08\x48\x89\x70\x18";
char pattern[] = "xxxxxxxxxxx";
Scanner.FindPattern(proc_name, byte_sequence, pattern);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
init_il2cpp();
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Run, NULL, 0, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
My question is why does the crash happen and how can I fix it? I have confirmed that the MODULEINFO struct returned from the GetModuleInfo function is initialized to a non-null value, and the base address that I read from it seems legitimate. From reading other posts I understand that Windows will throw a memory access violation if you try to read another process's memory, but since my code is running in a DLL Injection my understand is that it should be able to read the memory without issue, since it is within the same process.
Any help is greatly appreciated! Thanks for your time.
I am a fool.
This line is the cause of all my issues:
DWORD base = (DWORD)mInfo.lpBaseOfDll;
This code is running on a 64-bit OS, whereas a DWORD is only 4 bytes, so it is presumably just taking the lower 4 bytes of the base pointer and using that, which results in invalid memory accesses as I am essentially looking at random addresses. Using a DWORD_PTR instead (8 bytes on a 64-bit OS) has solved all my issues.

What is the lowest level WinSock API available in the user mode? (For API injection trampoline.)

My goal is to intercept outbound TCP packets from a custom-built application that I do not have source code to. I need to adjust several parameters in the outbound data. It is an older application that the original company no longer sells and the developer is no longer available.
So I was planning to install an API injection trampoline into the send() type raw WinSock API from my DLL that I can inject into the target process. But before writing such DLL, I decided to test this concept in my local process. So I did the following:
#ifdef _M_X64
//Simple code to install "API injection trampoline"
//Compiled as 64-bit process
static int WINAPI TestJump1(SOCKET s, const char *buf, int len, int flags);
{
//This part is just for debugging to make sure that my trampoline method is called
//The actual "working" trampoline will involve additional steps to insure that the original method is also called
::MessageBox(NULL, L"Injected method called!", L"Debugger Message", MB_OK);
return SOCKET_ERROR;
}
HMODULE hModWS2 = ::LoadLibrary(L"Ws2_32.dll");
if(hModWS2)
{
int (WINAPI *pfn_send)(SOCKET s, const char *buf, int len, int flags);
int (WINAPI *pfn_sendto)(SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen);
if(pfn_send &&
pfn_sendto)
{
//Long absolute JMP
//48 b8 xx xx xx xx xx xx xx xx mov rax, 0xxxx
//ff e0 jmp rax
BYTE subst[] = {
0x48, 0xb8,
0, 0, 0, 0,
0, 0, 0, 0,
0xff, 0xe0
};
HANDLE hProc = ::GetCurrentProcess();
VOID* pPtrAPI = pfn_send;
//Also tried with
//VOID* pPtrAPI = pfn_sendto;
//Make this address writable
DWORD dwOldProtect = 0;
if(::VirtualProtectEx(hProc, pPtrAPI, sizeof(subst), PAGE_EXECUTE_READWRITE, &dwOldProtect))
{
//Install JMP opcodes
VOID* pJumpPtr = TestJump1;
*(VOID**)(subst + 2) = pJumpPtr;
memcpy(pPtrAPI, subst, sizeof(subst));
//Reset it back
DWORD dwDummy;
if(::VirtualProtectEx(hProc, pPtrAPI, sizeof(subst), dwOldProtect, &dwDummy))
{
if(::FlushInstructionCache(hProc, pPtrAPI, sizeof(subst)))
{
//Try to call our method
//int rz = pfn_send(NULL, "", 0, 0); //This works!
//Try real test with the higher level API
//Download a web page into a file:
//This API must be calling raw sockets at some point internally...
//but my TestJump1() is never called from here...
HRESULT hr = URLDownloadToFile(NULL,
L"http://microsoft.com/",
L"C:\\Users\\User\\Desktop\\file.txt", 0, NULL);
}
}
}
}
}
#endif
So the code works fine, the JMP trampoline is installed and called alright if I call send method explicitly (as shown above) but my further assumption that a higher level API (i.e. URLDownloadToFile) would call it as well does not seem to hold true. My trampoline method is never called from it.
So what am I missing here? Is there an even lower WinSock API?
send() is not the only function available for sending TCP data using Winsock in user code. There is also:
WSASend()
WSASendDisconnect()
WSASendMsg()
TransmitFile()
TransmitPackets()
RIOSend/Ex()
At the very least, apps that don't use send() will usually use WSASend() instead, for use with Overlapped I/O or I/O Completion Ports. That is usually good enough for most situations. The other functions are not used very often, but may be used in certain situations where higher performance is really needed.
the lowest level winsock api is implemented by Winsock Service Provider Interface. during interface initialization the WSPStartup function is called from interface provider (this api must be exported by name from provider dll). for MSAFD Tcpip [TCP/IP] "{E70F1AA0-AB8B-11CF-8CA3-00805F48A192}" it implemented in mswsock.dll by default - look more here (strictly said used dll registered in HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries[64] but by default, this is mswsock.dll )
WSPStartup return to ws2_32 WSPPROC_TABLE - here the lowest user mode api which called. say for sendto - this is lpWSPSendTo function. so for hook all sendto you need replace lpWSPSendTo pointer in WSPPROC_TABLE to own. some api pointers returned via WSPIoctl. so you must replace lpWSPIoctl member in table to own and replace in result returned by original WSPIoctl to own api. example for RIO extension:
#include <ws2spi.h>
#include <mswsock.h>
LPWSPIOCTL g_lpWSPIoctl;
LPWSPSENDTO g_lpWSPSendTo;
LPFN_RIOSENDEX g_RIOSendEx;
int WSPAPI WSPIoctl(
__in SOCKET s,
__in DWORD dwIoControlCode,
__in LPVOID lpvInBuffer,
__in DWORD cbInBuffer,
__out LPVOID lpvOutBuffer,
__in DWORD cbOutBuffer,
__out LPDWORD lpcbBytesReturned,
__in LPWSAOVERLAPPED lpOverlapped,
__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
__in LPWSATHREADID lpThreadId,
__out LPINT lpErrno
)
{
int r = g_lpWSPIoctl(s, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
static GUID functionTableId = WSAID_MULTIPLE_RIO;
if (
!r
&&
dwIoControlCode == SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER &&
cbInBuffer == sizeof(GUID) &&
cbOutBuffer >= sizeof(RIO_EXTENSION_FUNCTION_TABLE) &&
!memcmp(lpvInBuffer, &functionTableId, sizeof(GUID))
)
{
PRIO_EXTENSION_FUNCTION_TABLE priot = (PRIO_EXTENSION_FUNCTION_TABLE)lpvOutBuffer;
if (priot->cbSize >= FIELD_OFFSET(RIO_EXTENSION_FUNCTION_TABLE, RIOSendEx))
{
g_RIOSendEx = priot->RIOSendEx;// save original pointer to use
priot->RIOSendEx = RIOSendEx;// this is your hook function
}
}
return r;
}
so we need hook WSPStartup function before it will be called first time by ws2_32.dll

Call function from thread created via CreateRemoteThread

I'm studying dll injection and so far I managed to inject a dll in a process causing the message box to show up.
The part I didn't quite understand, even after tons of readings and research, is how I pass a parameter to the dll, or call a specific function within it.
The dll:
extern "C" __declspec(dllexport) bool WINAPI
DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
MessageBoxA(NULL, "Hello World!", "Dll says:", MB_OK);
break;
}
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return true;
}
The injection:
char dllPath[] = "sampleDll.dll";
// For dll path injection.
int memAmountToAllocate = strlen(dllPath);
LPVOID dllPathAddress = VirtualAllocEx(procHandle, 0, memAmountToAllocated, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
FARPROC loadLibraryAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
WriteProcessMemory(procHandle, dllPathAddress, dllPath, memAmountToAllocated, 0);
// creating a thread that will call LoadLibraryA with allocMemAddress as argument
CreateRemoteThread(procHandle, 0, 0, loadLibraryAddr, dllPathAddress, 0, 0);
As I said, the injection works fine, i.e. the message box appears.
But say I have a method in the dll foo(LPVOID ptrToData). How can I call the foo function?
I have the address of the function I want to execute on the target process, it is an adding function, so I need to pass x and y.
I can call the function like this
_asm
{
push 0;
push 0x7;
mov ecx, esi;
mov eax, 0x41367C;
call eax;
}
however the values for push must come from the injecting process.
How can I do that?
The solution to my problem was to use an IPC mechanism to allow my main application and dll to communicate.
I used a named pipe.
I created the pipe in C# and then when I inject the dll I connect to the pipe.

Execute BYTE array in detoured function

I know it's a long post but it's mostly code and pictures, it's a quick read! First of all, here is what I'm trying to do:
I'm trying to execute a BYTE array in a detoured function in order to go back to the original code as if I didn't detour anyhting Here is my code:
DllMain (DetourAddress is all that matter):
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
DetourAddress((void*)HookAddress, (void*)&DetourFunc);
case DLL_PROCESS_DETACH:
FreeConsole();
break;
}
return TRUE;
}
DetourAddress (code is self-explanatory, I think):
void DetourAddress(void* funcPtr, void* hook)
{
// write jmp
BYTE cmd[5] =
{
0xE9, //jmp
0x00, 0x00, 0x00, 0x00 //address
};
// make memory readable/writable
DWORD dwProtect;
VirtualProtect(funcPtr, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
// read bytes about to be replaced
ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, mem, 5, NULL);
// write jmp in cmd
DWORD offset = ((DWORD)hook - (DWORD)funcPtr - 5); // (dest address) - (source address) - (jmp size)
memcpy(&cmd[1], &offset, 4); // write address into jmp
WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, cmd, 5, 0); // write jmp
// reprotect
VirtualProtect(funcPtr, 5, dwProtect, NULL);
}
DetourFunc:
_declspec(naked) void DetourFunc()
{
__asm
{
PUSHFD
PUSHAD
}
printf("function detoured\n");
__asm
{
POPAD
POPFD
}
// make memory readable/writable
DWORD dwProtect;
VirtualProtect(mem, 6, PAGE_EXECUTE_READWRITE, &dwProtect);
pByteExe();
// reprotect
VirtualProtect(mem, 6, dwProtect, NULL);
__asm
{
jmp HookReturnAddress
}
}
And finaly the global variables, typedef for pByteExe() and includes:
#include <Windows.h>
#include <cstdio>
DWORD HookAddress = 0x08B1418,
HookReturnAddress = HookAddress+5;
typedef void ( * pFunc)();
BYTE mem[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0xC3 };
pFunc pByteExe = (pFunc) &mem
As you can see in DetourFunc, I'm trying to execute my byte array (mem) directly. Using OllyDbg, this gets me there:
Which is exactly the bytes I'm trying to execute. Only problem is that it gives me an Access violation error when executing... Any idea why? I would have thought "VirtualProtect(mem, 5, PAGE_EXECUTE_READWRITE, &dwProtect);" would have made it safe to access... Thanks for your help!
EDIT: I just realized something wierd was happening... when I "Step into" with ollydbg, the mem instructions are correct, but as soon as I scroll a little, they change back to this:
Any idea why?
You've forgot the module offset...
DWORD module = (DWORD)GetModuleHandle(NULL);
DWORD real_address = module + (DWORD)ADDRESS;
ADDRESS have to of course relative to your module. (The module offset isn't allways the same)
And btw. why you take WriteProcessMemory, when you inject your DLL? A simple memcpy is enought...

How to create a trampoline function for hook

I'm interested in hooking and I decided to see if I could hook some functions. I wasn't interested in using a library like detours because I want to have the experience of doing it on my own. With some sources I found on the internet, I was able to create the code below. It's basic, but it works alright. However when hooking functions that are called by multiple threads it proves to be extremely unstable. If two calls are made at nearly the same time, it'll crash. After some research I think I need to create a trampoline function. After looking for hours all I was not able to find anything other that a general description on what a trampoline was. I could not find anything specifically about writing a trampoline function, or how they really worked. If any one could help me write one, post some sources, or at least point me in the right direction by recommending some articles, sites, books, etc. I would greatly appreciate it.
Below is the code I've written. It's really basic but I hope others might learn from it.
test.cpp
#include "stdafx.h"
Hook hook;
typedef int (WINAPI *tMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
DWORD hMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
hook.removeHook();
tMessageBox oMessageBox = (tMessageBox)hook.funcPtr;
int ret =oMessageBox(hWnd, lpText, "Hooked!", uType);
hook.applyHook(&hMessageBox);
return ret;
}
void hookMessageBox()
{
printf("Hooking MessageBox...\n");
if(hook.findFunc("User32.dll", "MessageBoxA"))
{
if(hook.applyHook(&hMessageBox))
{
printf("hook applied! \n\n");
} else printf("hook could not be applied\n");
}
}
hook.cpp
#include "stdafx.h"
bool Hook::findFunc(char* libName, char* funcName)
{
Hook::funcPtr = (void*)GetProcAddress(GetModuleHandleA(libName), funcName);
return (Hook::funcPtr != NULL);
}
bool Hook::removeHook()
{
DWORD dwProtect;
if(VirtualProtect(Hook::funcPtr, 6, PAGE_EXECUTE_READWRITE, &dwProtect))
{
WriteProcessMemory(GetCurrentProcess(), (LPVOID)Hook::funcPtr, Hook::origData, 6, 0);
VirtualProtect(Hook::funcPtr, 6, dwProtect, NULL);
return true;
} else return false;
}
bool Hook::reapplyHook()
{
DWORD dwProtect;
if(VirtualProtect(funcPtr, 6, PAGE_EXECUTE_READWRITE, &dwProtect))
{
WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, Hook::hookData, 6, 0);
VirtualProtect(funcPtr, 6, dwProtect, NULL);
return true;
} else return false;
}
bool Hook::applyHook(void* hook)
{
return setHookAtAddress(Hook::funcPtr, hook);
}
bool Hook::setHookAtAddress(void* funcPtr, void* hook)
{
Hook::funcPtr = funcPtr;
BYTE jmp[6] = { 0xE9, //jmp
0x00, 0x00, 0x00, 0x00, //address
0xC3 //retn
};
DWORD dwProtect;
if(VirtualProtect(funcPtr, 6, PAGE_EXECUTE_READWRITE, &dwProtect)) // make memory writable
{
ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, Hook::origData, 6, 0); // save old data
DWORD offset = ((DWORD)hook - (DWORD)funcPtr - 5); //((to)-(from)-5)
memcpy(&jmp[1], &offset, 4); // write address into jmp
memcpy(Hook::hookData, jmp, 6); // save hook data
WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, jmp, 6, 0); // write jmp
VirtualProtect(funcPtr, 6, dwProtect, NULL); // reprotect
return true;
} else return false;
}
If you want your hook to be safe when called by multiple threads, you don't want to be constantly unhooking and rehooking the original API.
A trampoline is simply a bit of code you generate that replicates the functionality of the first few bytes of the original API (which you overwrote with your jump), then jumps into the API after the bytes you overwrote.
Rather than unhooking the API, calling it and rehooking it you simply call the trampoline.
This is moderately complicated to do on x86 because you need (a fairly minimal) disassembler to find the instruction boundaries. You also need to check that the code you copy into your trampoline doesn't do anything relative to the instruction pointer (like a jmp, branch or call).
This is sufficient to make calls to the hook thread-safe, but you can't create the hook if multiple threads are using the API. For this, you need to hook the function with a two-byte near jump (which can be written atomically). Windows APIs are frequently preceded by a few NOPs (which can be overwritten with a far jump) to provide a target for this near jump.
Doing this on x64 is much more complicated. You can't simply patch the function with a 64-bit far jump (because there isn't one, and instructions to simulate it are often too long). And, depending on what your trampoline does, you may need to add it to the OS's stack unwind information.
I hope this isn't too general.
The defacto standard hooking tutorial is from jbremer and available here
Here is a simple x86 detour and trampoline hook based on this tutorial using Direct3D's EndScene() function as a example:
bool Detour32(char* src, char* dst, const intptr_t len)
{
if (len < 5) return false;
DWORD curProtection;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);
intptr_t relativeAddress = (intptr_t)(dst - (intptr_t)src) - 5;
*src = (char)'\xE9';
*(intptr_t*)((intptr_t)src + 1) = relativeAddress;
VirtualProtect(src, len, curProtection, &curProtection);
return true;
}
char* TrampHook32(char* src, char* dst, const intptr_t len)
{
// Make sure the length is greater than 5
if (len < 5) return 0;
// Create the gateway (len + 5 for the overwritten bytes + the jmp)
void* gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
//Write the stolen bytes into the gateway
memcpy(gateway, src, len);
// Get the gateway to destination addy
intptr_t gatewayRelativeAddr = ((intptr_t)src - (intptr_t)gateway) - 5;
// Add the jmp opcode to the end of the gateway
*(char*)((intptr_t)gateway + len) = 0xE9;
// Add the address to the jmp
*(intptr_t*)((intptr_t)gateway + len + 1) = gatewayRelativeAddr;
// Perform the detour
Detour32(src, dst, len);
return (char*)gateway;
}
typedef HRESULT(APIENTRY* tEndScene)(LPDIRECT3DDEVICE9 pDevice);
tEndScene oEndScene = nullptr;
HRESULT APIENTRY hkEndScene(LPDIRECT3DDEVICE9 pDevice)
{
//do stuff in here
return oEndScene(pDevice);
}
//just an example
int main()
{
oEndScene = (tEndScene)TrampHook32((char*)d3d9Device[42], (char*)hkEndScene, 7);
}