Dans cet article je présenterai mon tour d’horizon sur l’API Hooking.

L’API hooking consiste a détourner l’appelle d’une fonction vers une autre fonction cette autre fonction est bien évidemment une fonction définie par l’utilisateur pour exécuter son propre code.

Pour effectuer un hook api nos auront besoin de :

  • L’adresse de la fonction a détourner
  • L’adresse de notre fonction

On commence donc par récupérer les adresses des fonctions, pour l’exemple on prendra l’api MessageBox qui est défini dans la DLL user32.dll, dont le chargement au préalable de celle-ci est indispensable.

void InstallApiHook()
{
    hUser32 = LoadLibrary("user32.dll");

    pSysApiAddr = (DWORD)GetProcAddress(hUser32,"MessageBoxA");
    pMyApiAddr = (DWORD)MyMessageBoxA;

    SetHook();
}

hUser32 est une variable globale de type HINSTANCE défini dans le fichier pour stocker la handle de la DLL.

pSysApiAddr de type DWORD contiens l’adresse mémoire de l’API MessageBox retourner grâce a la fonction GetProcAddress.

pMyApiAddr aussi de type DWORD contiens l’adresse mémoire de note fonction a exécuté.

Maintenant nous devons réaliser le saut vers notre fonction qui se nommera MyMessageBoxA  depuis la fonction MessageBox de l’API Windows.

Pour ce si nous utiliserons la fonction WriteProcessMemory qui va réécrire la première instruction de la fonction MessageBox de l’API Windows en saut vers notre fonction.

Cependant avant l’écriture de l’instruction nous devons sauvegarder l’instruction qui se trouvait la avant, pour pouvoir réutiliser la fonction MessageBox de l’API Windows normalement, la sauvegarder se fera en copiant avant l’écriture, les 6 premiers octets pressent vers un buffer bRecover.

void SetHook()
{
    // On copie les 6 premier byte
    ReadProcessMemory(GetCurrentProcess(), (LPVOID)pSysApiAddr, bRecover, 6, 0);

    // On perepare le saut
    BYTE jmp[6] = {0xe9, 0, 0, 0, 0, 0xc3};

    DWORD jmpLength = (DWORD)pMyApiAddr - pSysApiAddr - 5;

    memcpy((void*)&jmp[1],(void*)&jmpLength,4);

    // On écrit le saut
    WriteProcessMemory(GetCurrentProcess(), (LPVOID)pSysApiAddr, jmp, 6, 0);

    cout << "SetHook Success" << endl;
}

Maintenant voici l’implementation de notre propre fonction MessageBox

int MyMessageBoxA(HWND hWnd, LPSTR lpText, LPSTR lpCaption, UINT uType)
{
    RemoveHook();

    MessageBoxA(hWnd, "MessageBox Api Hooked", "Hook state", uType);

    int res = MessageBoxA(hWnd, lpText, lpCaption, uType);

    HINSTANCE hUser32 = LoadLibrary("user32.dll");
    DWORD dAddrProc = (DWORD)GetProcAddress(hUser32,"MessageBoxA");

    SetHook();

    return res;
}

Notre fonction va se contenter de remplacer le texte écrit, par « MessageBox Api Hooked ».

La fonction RemoveHook va restaurer les 6 premiers octets de la fonction MessageBox de l’API Windows.

void RemoveHook()
{
    // On remet les 6 premiers bytes
    WriteProcessMemory(GetCurrentProcess(), (LPVOID)pSysApiAddr, bRecover, 6, 0);

    cout << "RemoveHook Success" << endl;
}

Enfin la fonction main (ou WinMain) qui va dans l’ordre, appliquer le hook, lancer la fonction MessageBox pour tester et ensuite restaurer la fonction.

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    InstallApiHook();

    MessageBox(0, "MessageBox Api Call", "App state", 0);

    UnInstallApiHook();

    getch();

    return 0;
}

Il faut savoir que ce hook d’api ne marchera que sur le processus courant, si un autre programme appelle la fonction MessageBox celle-ci s’affichera normalement.

Pour effectuer un hook sur tous les processus ou sur un autre processus ciblé, nous devrons utiliser l’injection DLL ou de Code pour arriver a faire exécuter note hook a un autre processus, car les fonctions contenu dans les DLL sont mappées pour chaque processus.

Télécharger l’archive : sources, makefile et l’exécutable