API Function hooking - Easymode

Posts 1–4 of 4 · Page 1 of 1
API Function hooking - Easymode
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!
Or you use the Microsoft Detours Library It's simpler and better
Quote Originally Posted by CFHackerExtreme View Post
Or you use the Microsoft Detours Library It's simpler and better
Yeah, sure you can use MS Detours. I just thought I would show you how to do do what MS Detours does on your own. MS Detours replaces the first few bytes of the original function with a jmp, just like I do. If I would recommend a library for hooking, go with mhook. It's lightweight and both x86 and x64. And its open source!
great stufff
Posts 1–4 of 4 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us