Cet article présente le principe de l’injection DLL avec la méthode SetWindowsHookEx.

L’injection DLL consiste à faire exécuter notre code qui sera contenu dans une DLL par un autre processus avec ses privilèges.

Par exemple dans la situation d’un par-feu qui bloquera surement les tentatives de connexion des processus non autoriser, une injection DLL permettra de se connecter avec les privilèges des processus autoriser.

Donc pour cela nous aurons besoin de compiler une DLL qui contiendra notre code à exécuter et un loader qui se chargera d’injecter notre DLL dans le processus cible.

Commencent par le loader qui est un programme simple, son code va dans l’ordre :

  1. Charger notre DLL avec la fonction LoadLibrary.
  2. Récupère la fonction d’initialisation.
  3. Exécuter la fonction d’initialisation.
HINSTANCE dll = LoadLibrary("injection.dll");

DLLPROC InitHook =  (DLLPROC)GetProcAddress(dll, "InitHook");

HHOOK hook = InitHook();

getch();

UnhookWindowsHookEx(hook);

Notre DLL va effectuer un api hooking des quelle sera attacher a notre processus cible

ici pour l’exemple ça sera notepad.exe que nous allons détourner sa fonction MessageBoxW a l’aide d’un hook api.

Le code de la DLL est similaire (voire identique) au code de l’API hooking, seules deux fonctions sont ajoutées, la fonction du point d’entrée de la DLL et la fonction d’initialisation

extern "C" int WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID Reserved)
{
    char buff[264];
    GetModuleFileName(0, buff, 264);

    switch(dwReason)
    {
    case DLL_PROCESS_ATTACH:
        cout << "DLL_PROCESS_ATTACH " << buff << endl;

        hThis = hDll;
        if(strstr(buff, "notepad.exe") != 0)
            InstallApiHook();
        break;

    case DLL_PROCESS_DETACH:
        cout << "DLL_PROCESS_DETACH " << buff << endl;

        if(strstr(buff, "notepad") != 0)
            UnInstallApiHook();
        break;
    }

    return 1;
}

Ce-si est la fonction d’entrer des DLL lorce que Windows charge en mémoire une DLL et que cette fonction est présent Windows l’exécute avec en paramètre :

le HANDLE du processus qui a chargé la DLL (HINSTANCE hDll)

la raison de l’appel de cette fonction (DWORD dwReason), car cette fonction est appel plusieurs fois par moment (lors de l’attachement, détachement…)

le dernier paramètre (LPVOID Reserved) est réservé donc ignoré dans le corps de la fonction

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    return CallNextHookEx(hook, nCode, wParam, lParam);
}

extern "C" HHOOK InitHook()
{
    cout << "InitHook" << endl;

    return SetWindowsHookEx(WH_CBT, HookProc, hThis, 0);
}

La fonction d’initialisation va effectuer un hook pour demande a Windows d’appeler notre fonction de hook (HookProc) contenue a l’intérieur de la DLL a chaque fois qu’un événement de type WH_CBT (Création de fenêtre, réduction, destruction…) aura lieu.

le préfixe (extern « C ») permiet d’éviter la décoration du nom de la fonction en C++ ce si est indispensable pour récupérer l’adresse de la fonction avec GetProcAddress.

Donc quand ce type d’événement aura lieu Windows va chercher notre fonction (HookProc) a l’intérieur de la DLL et comme une fonction d’entrer et présente dans la DLL celle-ci est exécuter par le processus cible, après notre fonction d’entrer va effectuer un API Hooking de la fonction MessageBoxW du processus cible.

Attention de bien mentionner MessageBoxW avec un W a la fin, ce si permet de différencier les fonctions UNICODE des fonctions ANSI dans l’API Windows, car notepad utilise l’API MessageBox au format UNICODE donc vous devez hooker l’API MessageBoxW pour que l’opération ait le résultat attendu.

Si vous essayer de débuter votre DLL avec la sortie standard (cout <<), rien ne s’affichera, car chaque processus a sa propre console, utiliser plutôt
un fichier comme sortie.

WINAPI doit être spécifié pour la fonction détourner (MyMessageBoxW) pour éviter un plantage lors du retour de valeur

Voila pour l’injection DLL cette méthode marche parfaitement, mais le code a exécuté doit être contenu dans DLL à part, une autre méthode consiste a injecter du code directement (ShellCode), celle-ci par contre est plus difficile a mettre en place et nécessite des connaissances en assembleur.

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