Hello!
Today I will show you how to hook windows API functions the easy way. I made a class to make the process easier and faster. I've succesfully hooked ws2 send and recv functions, loadlibrary in kernel32 and messagebox in user32. As far as I know, you can pretty much hook any API function with the provided code.
Here is the class for hooking (hkClass.h):
Code:
#include <cstdlib>
#include <cstring>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
class ApiCave
{
public:
void GenerateBytes();
void RestoreBytes();
void PlaceJump();
void GetOriginalFuncAddress(char * moduleName, char * functionName);
ApiCave(LPVOID DetourFunction, int iSize);
~ApiCave();
private:
int iInstructionSize;
BYTE *originalBytes, *hookBytes, *tempBytes;
DWORD OriginalFunctionAddress, DetourFunctionAddress, oldprotect;
DWORD myprotect;
};
void ApiCave::GenerateBytes()
{
tempBytes[0] = 0xE9;
tempBytes[5] = 0xC3; // 0xE9 = JMP 0x90 = NOP oxC3 = RET
memcpy(hookBytes, tempBytes, iInstructionSize); // store jmp instruction to JMP
DWORD JMPSize = ((DWORD)DetourFunctionAddress - (DWORD)OriginalFunctionAddress - 5); // calculate jump distance
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, // assign read write protection
myprotect, &oldprotect);
memcpy((LPVOID)originalBytes, (LPVOID)OriginalFunctionAddress, iInstructionSize); // make backup
memcpy(&hookBytes[1], &JMPSize, 4); // fill the nop's with the jump distance (JMP,distance(4bytes),RET)
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, oldprotect, NULL);
}
void ApiCave::RestoreBytes()
{
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, myprotect, &oldprotect);
memcpy((LPVOID)OriginalFunctionAddress, originalBytes, iInstructionSize);
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, oldprotect, NULL);
}
void ApiCave::PlaceJump()
{
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, myprotect, &oldprotect);
memcpy((LPVOID)OriginalFunctionAddress, hookBytes, iInstructionSize);
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, oldprotect, NULL);
}
void ApiCave::GetOriginalFuncAddress(char * moduleName, char * functionName)
{
OriginalFunctionAddress = (DWORD)GetProcAddress(GetModuleHandle(moduleName), functionName);
}
ApiCave::ApiCave(LPVOID DetourFunction, int iSize)
{
iInstructionSize = iSize;
myprotect = PAGE_EXECUTE_READWRITE;
DetourFunctionAddress = (DWORD)DetourFunction;
tempBytes = new BYTE[iSize];
originalBytes = new BYTE[iSize];
hookBytes = new BYTE[iSize];
}
ApiCave::~ApiCave()
{
delete[] tempBytes;
delete[] originalBytes;
delete[] hookBytes;
}
As you can see, the class must be initialized with the address to your detour function and how many bytes will be swapped on each detour. (Generally you only need to swap 6 bytes) After you have initialized a class object, you must GetOriginalFunctionAddress(Modulename, FunctionName);. After you have aquired the address of the function to hook, you can GenerateBytes();. And finally, to enable the hook you PlaceJump(); so that the original instructions at the beginning of the function get overwritten with a JMP instruction to your detour function. Instead of a E9 JMP instruction it is possible to do other kind of jumps too:
Code:
void ApiCave::GenerateBytes()
{
tempBytes[0] = 0x68; // 68 PUSH
tempBytes[5] = 0xC3; // C3 RETN
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, // assign read write protection
myprotect, &oldprotect);
memcpy((LPVOID)originalBytes, (LPVOID)OriginalFunctionAddress, iInstructionSize); // make backup
memcpy(&hookBytes[1], (DWORD)DetourFunctionAddress, 4); // store the address into tempbytes
VirtualProtect((LPVOID)OriginalFunctionAddress, iInstructionSize, oldprotect, NULL);
}
The code above achieves the same as the E9 JMP, but using a PUSH addr and RETN instead. Note that the E9 jump can be expressed in 5 bytes, but the PUSH RETN takes up 6. A call statement would work too, though you have to pop the retn address from the stack in your function. Play around with these, having a debugger like ollydbg is very useful so you can actually look at the code.
Lets get started by creating the main.cpp:
Code:
#include "hook.h"
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DoTheHook();
break;
}
return TRUE;
}
Now the interesting stuff (hook.h) I will hook the send function in winsock2 and MessageBoxA as a demonstration. Because we are hooking winsock send, you need to include the WS2_32 lib.
Code:
#include "hkClass.h"
int WINAPI MySend(SOCKET, const char *, int, int);
int WINAPI MyMessageBoxA(HWND, LPCTSTR, LPCTSTR, UINT);
ApiCave sendCave((LPVOID)MySend, 6);
ApiCave mbCave((LPVOID)MyMessageBoxA, 6);
int WINAPI MySend (SOCKET s, const char * buf, int len, int flags)
{
sendCave.RestoreBytes();
int retVal = send(s, buf, len, flags);
sendCave.PlaceJump();
return retVal;
}
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR text, LPCTSTR title, UINT type)
{
mbCave.RestoreBytes();
int retVal = MessageBoxA(hWnd, text, title, type);
mbCave.PlaceJump();
return retVal;
}
void DoTheHook()
{
sendCave.GetOriginalFuncAddress("ws2_32.dll", "send");
mbCave.GetOriginalFuncAddress("user32.dll", "MessageBoxA");
sendCave.GenerateBytes();
mbCave.GenerateBytes();
sendCave.PlaceJump();
mbCave.PlaceJump();
}
We create ApiCave objects for both our detours and initialize them with the addresses of our detour functions. The actual detour functions first restore the original bytes to the API function, then get the return value and finally place the jmp instruction back.
The stuff that is done in DoTheHook() should be pretty much self explanatory.
And that is it, the functions will now get hooked as soon as the dll is injected into a process. Credits go to wikipedia for an awesome snippet showing the logic behind this. If you have any questions or suggestions, please tell me. Happy coding!