How to Hook Windows Functions in C/C++

How can I hook Windows functions in C/C++?

Take a look at Detours, it's perfect for this sort of stuff.


For system-wide hooking, read this article from MSDN.


First, create a DLL which handles hooking the functions. This example below hooks the socket send and receive functions.

#include <windows.h>
#include <detours.h>

#pragma comment( lib, "Ws2_32.lib" )
#pragma comment( lib, "detours.lib" )
#pragma comment( lib, "detoured.lib" )

int ( WINAPI *Real_Send )( SOCKET s, const char *buf, int len, int flags ) = send;
int ( WINAPI *Real_Recv )( SOCKET s, char *buf, int len, int flags ) = recv;
int WINAPI Mine_Send( SOCKET s, const char* buf, int len, int flags );
int WINAPI Mine_Recv( SOCKET s, char *buf, int len, int flags );

int WINAPI Mine_Send( SOCKET s, const char *buf, int len, int flags ) {
// .. do stuff ..

return Real_Send( s, buf, len, flags );
}

int WINAPI Mine_Recv( SOCKET s, char *buf, int len, int flags ) {
// .. do stuff ..

return Real_Recv( s, buf, len, flags );
}

BOOL WINAPI DllMain( HINSTANCE, DWORD dwReason, LPVOID ) {
switch ( dwReason ) {
case DLL_PROCESS_ATTACH:
DetourTransactionBegin();
DetourUpdateThread( GetCurrentThread() );
DetourAttach( &(PVOID &)Real_Send, Mine_Send );
DetourAttach( &(PVOID &)Real_Recv, Mine_Recv );
DetourTransactionCommit();
break;

case DLL_PROCESS_DETACH:
DetourTransactionBegin();
DetourUpdateThread( GetCurrentThread() );
DetourDetach( &(PVOID &)Real_Send, Mine_Send );
DetourDetach( &(PVOID &)Real_Recv, Mine_Recv );
DetourTransactionCommit();
break;
}

return TRUE;
}

Then, create a program to inject the DLL into the target application.

#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv() {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;

OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );

LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid );

tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL );

CloseHandle( hToken );
}

int main( int, char *[] ) {
PROCESSENTRY32 entry;
entry.dwSize = sizeof( PROCESSENTRY32 );

HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );

if ( Process32First( snapshot, &entry ) == TRUE ) {
while ( Process32Next( snapshot, &entry ) == TRUE ) {
if ( stricmp( entry.szExeFile, "target.exe" ) == 0 ) {
EnableDebugPriv();

char dirPath[MAX_PATH];
char fullPath[MAX_PATH];

GetCurrentDirectory( MAX_PATH, dirPath );

sprintf_s( fullPath, MAX_PATH, "%s\\DllToInject.dll", dirPath );

HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, entry.th32ProcessID );
LPVOID libAddr = (LPVOID)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "LoadLibraryA" );
LPVOID llParam = (LPVOID)VirtualAllocEx( hProcess, NULL, strlen( fullPath ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );

WriteProcessMemory( hProcess, llParam, fullPath, strlen( fullPath ), NULL );
CreateRemoteThread( hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)libAddr, llParam, NULL, NULL );
CloseHandle( hProcess );
}
}
}

CloseHandle( snapshot );

return 0;
}

This should be more than enough to get you started!

Win32, How can i hook functions in compiled programs with C++?

First, you will want to inject a dll in the target process. To do so, you can use this code:

Injector.h

#ifndef INJECTOR_H_INCLUDED
#define INJECTOR_H_INCLUDED

#include <Windows.h>
#include <string>

class Injector
{
public:
/**
* Loads a DLL into the remote process
* @Return true on sucess, false on failure
*/
bool InjectDll(DWORD processId, std::string dllPath);
private:
};

#endif // INJECTOR_H_INCLUDED

Injector.cpp

#include "Injector.h"

bool Injector::InjectDll(DWORD processId, std::string dllPath)
{
HANDLE hThread, hProcess;
void* pLibRemote = 0; // the address (in the remote process) where szLibPath will be copied to;

HMODULE hKernel32 = GetModuleHandle("Kernel32");
HINSTANCE hInst = GetModuleHandle(NULL);

char DllFullPathName[_MAX_PATH];
GetFullPathName(dllPath.c_str(), _MAX_PATH, DllFullPathName, NULL);

// Get process handle
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);

// copy file path in szLibPath
char szLibPath[_MAX_PATH];
strcpy_s(szLibPath, DllFullPathName);

// 1. Allocate memory in the remote process for szLibPath
pLibRemote = VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );

if (pLibRemote == NULL)
{
// probably because you don't have administrator's right
return false;
}

// 2. Write szLibPath to the allocated memory
WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath, sizeof(szLibPath), NULL);

// 3. Force remote process to load dll
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) GetProcAddress(hKernel32,"LoadLibraryA"), pLibRemote, 0, NULL);

if (hThread == NULL)
{
return false;
}

return true;
}

main.cpp

#include "Injector.h"
int main()
{
Injector injector;
DWORD processId = 1653; // change the process id here.

if (injector.InjectDll(processId, "injected.dll"))
{
printf("Good job, you injected the dll\n");
}
else
{
printf("Something wrong happened\n");
}

while (true);
}

Then you have to make your dll. This is where it gets a little more complicated. First some includes:

injected.dll

#include <Windows.h>
#include <stdio.h>

Then we need to make a function that will detour the right location:

void DetourAddress(void* funcPtr, void* hook, BYTE* mem)
{
BYTE cmd[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jump place holder
void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(NULL)); // base + relative address

// make memory readable/writable
DWORD dwProtect;
VirtualProtect(RVAaddr, 5, PAGE_EXECUTE_READWRITE, &dwProtect);

// read memory
ReadProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL);

// write jmp in cmd
DWORD offset = ((DWORD)hook - (DWORD)RVAaddr - 5); // (dest address) - (source address) - (jmp size)
memcpy(&cmd[1], &offset, 4); // write address into jmp
WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, cmd, 5, 0); // write jmp

// write mem
VirtualProtect(mem, 13, PAGE_EXECUTE_READWRITE, &dwProtect);

void* returnAdress = (void*)((DWORD)RVAaddr + 5);
memcpy(&mem[8], &returnAdress, 4); // write return address into mem

// reprotect
VirtualProtect(RVAaddr, 5, dwProtect, NULL);
}

If you need to remove your dll at some point, you will need to restore the code:

void PatchAddress(void* funcPtr, BYTE* mem)
{
void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(NULL)); // base + relative address

// make memory readable/writable
DWORD dwProtect;
VirtualProtect(funcPtr, 5, PAGE_EXECUTE_READWRITE, &dwProtect);

WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL); // write jmp

VirtualProtect(RVAaddr, 5, dwProtect, NULL);
}

Next, we need to make a function out of the detoured bytes in order for the program to execute them, so that it isn't affected by our detour. Add this in global space:

// memory (0x5E = pop esi, 0x68 = push DWORD, 0xC3 = RETN)
BYTE detourMem[13] = { 0x5E, 0x5E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x00, 0x00, 0x00, 0x00, 0xC3 };

// Convert bytes array to function
typedef void ( * pFunc)();
pFunc funcMem = (pFunc) &detourMem;

// I also added a variable as an example of what you can do with it.
DWORD var = 0;

After that, you need your detouring function:

_declspec(naked) void DetourFunction()
{
// we need to push all flag and registers on the stack so we don't modify them by accident
__asm
{
PUSHFD
PUSHAD

// You can do "whatever" you want here in assembly code
// ex, put eax value into var:
mov var, eax
}

printf("this code is executed everytime the detoured function is called\n");
// Do whatever you want in c++ here
if (var < 7)
{
// eax was smaller than 7
}

// We pop every flags and registers we first pushed so that the program continue as it was supposed to
__asm
{
// we set everything back to normal
POPAD
POPFD
push esi

// we call our funcMem
mov edx, funcMem;
call edx
}
}

Finaly, here is how your DLLMain would look like:

BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved  )
{
DWORD detouredAddress = 0x689B; // add the RELATIVE ADDRESS of the location you want to detour
FILE *stream;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// Only add this if you want a console to appears when you inject your dll (don't forget FreeConsole when you remove the dll)
AllocConsole();
freopen_s(&stream, "CONOUT$", "w", stdout);

// If you need to know the base address of the process your injected:
printf("base address: 0x%X\n", (DWORD)GetModuleHandle(NULL));

// Our detour function
DetourAddress((void*)detouredAddress, (void*)&DetourFunction, detourMem);
break;
case DLL_PROCESS_DETACH:
// We restore the process to have what it was before it was injected
PatchAddress((void*)detouredAddress, detourMem);

FreeConsole();
break;
}

return true;
}

I understand this is a lot all at once, so if you have any questions don't hesitate!

When a Windows Hook is Called, Which Code is Run?

The SetWindowsHookEx doesn’t take just a function pointer: it takes a function pointer together with a handle of the DLL the function is defined in. Given that, the kernel can calculate function address relative to DLL base address. Then it (in some cases at least) injects the DLL in other processes on the system, recalculates address (if necessary; DLL base address is usually fixed so the code doesn’t need to be position-independent. Relocation is still possible, though) and setups the hook in the target process. (According to Hans Passant’s comment, that only happens for some hooks, while others run in the source process).

That means that you can pass address of any function existing in a DLL; it doesn’t need to be exported AFAIK (that seems to be the reason not to use names instead) but it needs to exist in its on-disk image.

Hooking windows API functions to intercept dll loading (Windows only)

First, what are you doing that requires a global hook?

If you want to be notified that a DLL has loaded in any process, you can look into PsSetImageLoadNotifyRoutine, which is a kernel-mode routine.
Despite it being kernel mode, it's not very hard to use and writing a basic driver is pretty fun.

Another way would be to force a load of your library in every process. There are a variety of methods, one of the more legit ones would be Windows Message hooks.

How does function hooking actually work? WinAPI, C++

BOOL HookFunction(LPCWSTR moduleName, LPCSTR funcName, LPVOID funcProxy, 
unsigned char* lpBackup)
{
BYTE jmp[6] =
{
0xe9,0x00,0x00,0x00,0x00, /*JMP and 4 bytes of offset*/
0xc3 /*RET*/
};

/*
JMP (e9) is relative, its 32-bit signed immediate operand encodes the
number of bytes to jump forward relative to the NEXT instruction.
*/

/* Get the target address of the function to hook */
DWORD funcAddr = (DWORD)GetProcAddress(GetModuleHandle(moduleName), funcName);

/* Code is not necessarily mapped as writable, we remap it */
DWORD prev;
VirtualProtect((LPVOID)funcAddr, 6, PAGE_EXECUTE_READWRITE, &prev);

/* Read the original 6 bytes we are going to overwrite */
ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcAddr, lpBackup, 6, NULL);

/*
Compute the offset: target - source
target = funcProxy
source = funcAddr + 5 (length of JMP)

target - source = funcProxy - funcAddr - 5
*/
DWORD proxy = ((DWORD)funcProxy - funcAddr) - 5;

/*
Create the JMP instruction: set the offset
*/
memcpy(&jmp[1], &proxy, 4);

/* Overwrite the first 6 bytes of the target function */
memcpy((LPVOID)funcAddr, jmp, 6);

/* Reset the memory protection to its original value*/
VirtualProtect((LPVOID)funcAddr, 6, prev, &prev);

/* Since we write to a code section with DS, flush the L1 I cache */
FlushInstructionCache(GetCurrentProcess(), NULL, NULL);

return funcAddr;
}

The HookFunction create a little piece of x86 code in memory (a trampoline) of the form

jmp <0>     ;e9 00 00 00 00
ret ;c3

where <0> is successively overwritten with the encoded target (see comments in the code) of the jump - the hook function.

The trampoline, once crafted, becomes

jmp funcProxy     ;e9 .. .. .. ..
ret ;c3

This code is then written directly at the beginning of the hooked function, thereby overwriting its original code.

The code is polyglot - it works both for x86 and x86-64.


The original code of the hooked function is copied into lpBackup.

This is necessary to call the original function again, the hook function cannot call it without first restoring it.

Since this is expensive and not re-entrant, a cleaner approach is to modify the Import Address Table - the effectiveness of this solution depends on your requirements however.

How to Hook Mouse Event in C++ Builder Application using Windows Mouse Hook API Function?

MouseInputHook() should be a global function, or a static class method. So, add the static keyword to the declaration of MouseInputHook() in your class header file.

The error message means: a _closure function doesn't match the required callback function prototype. _closure means "a pointer to a non-static class method" in the C++Builder compiler. A non-static class method has a hidden this parameter, which makes it incompatible with the function prototype that SetWindowsHookExW() requires.



Related Topics



Leave a reply



Submit