logo Homepage
+  NewbieContest
|-+  Divers» Cracking» Injection de DLL dans un process
Username:
Password:
Pages: [1]
  Imprimer  
Auteur Fil de discussion: Injection de DLL dans un process  (Lu 5979 fois)
Pech
Profil challenge

Classement : 34/54279

Membre Junior
**
Hors ligne Hors ligne
Messages: 83


Voir le profil
« le: 08 Août 2016 à 16:36:43 »

Salut,

J'essaye de coder un "injecteur" de DLL et je me trouve confronté à un problème : ça ne marche que dans un cas.
Mes connaissances en Windows étant quelque peu limitées, à l'aide ! ^^

J'ai trois fichiers :
- test.exe : le binaire dans lequel je veux faire l'injection (en l'occurrence il affiche une fenêtre vide même si ça n'a aucune importance)
- test.dll : la DLL que je veux injecter (elle affiche une MessageBox dans DllMain juste pour que je vois facilement que l'injection est OK)
- inject.exe (cf. plus bas pour le code) : le binaire qui fait l'injection
A l'origine, chacun de ces fichiers était dans un sous-dossier (i.e. un dossier pour chaque code, logique).

Mon inject.exe prend deux arguments : le binaire de test et la DLL.
Pour tester, je lance à la main "test.exe" puis j'exécute en console le inject.exe.

Ma première tentative a été : inject\inject.exe bin_test\test.exe dll_test\test.dll
=> il ne trouve pas le PID de test.exe (normal, il cherche "bin_test\test.exe"...)

Du coup, seconde tentative plus logique : inject\inject.exe test.exe dll_test\test.dll
=> il trouve le PID de test.exe, mais pas de MessageBox

Après pas mal de n'importe quoi j'en suis arrivé à constater que *il faut que test.exe soit dans le dossier courant*.
Autrement dit, il ne faut pas le path pour pouvoir récupérer le PID mais il faut le path pour que l'injection réussisse oO
Etant donné que le nom du fichier de test sert uniquement (ou pas du coup ?) à récupérer le PID, me voila perdu.

Si quelqu'un a une explication, je suis preneur !
Merci d'avance

----

Note : pour simplifier au maximum j'ai supprimé les tests sur l'input + sur les valeurs de retour (elles sont toutes testées et je n'ai aucune erreur btw).

Code:
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

static DWORD GetProcessPID(char * processName)
{
    /* take a snapshot of running processes */
    HANDLE hProcessesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);

    /* get the first running process */
    Process32First(hProcessesSnapshot, &pe32);

    /* loop on the running processes: if we find the target then get its PID */
    DWORD targetPID = 0;
    do
    {
        if(strcmp(pe32.szExeFile, processName) == 0)
        {
            targetPID = pe32.th32ProcessID;
            break;
        }
    }
    while(Process32Next(hProcessesSnapshot, &pe32));

    CloseHandle(hProcessesSnapshot);
    return targetPID;
}

int main(int argc, char * argv[])
{
    char * target = argv[1];
    char * dllPath = argv[2];

    /* get a handle on the target process */
    DWORD dwTargetPID = GetProcessPID(target);
    HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTargetPID);

    /* allocate memory for the injection */
    void * pReservedSpace = VirtualAllocEx(hTargetProcess, NULL, strlen(dllPath), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(hTargetProcess, pReservedSpace, dllPath, strlen(dllPath), NULL);

    /* get the address of 'LoadLibraryA' function from kernel32.dll */
    HMODULE hModuleKernel32 = GetModuleHandle("kernel32");
    LPTHREAD_START_ROUTINE pLoadLibrary = (LPTHREAD_START_ROUTINE) GetProcAddress(hModuleKernel32, "LoadLibraryA");

    /* create a remote thread which executes the DllMain function of the injected DLL */
    HANDLE hThread = CreateRemoteThread(hTargetProcess, NULL, 0, pLoadLibrary, pReservedSpace, 0, NULL);

    /* wait until the thread returns*/
    WaitForSingleObject(hThread,INFINITE);

    /* clean and exit */
    VirtualFreeEx(hTargetProcess, pReservedSpace, strlen(dllPath), MEM_COMMIT);
    CloseHandle(hTargetProcess);
    exit(EXIT_SUCCESS);
}
Journalisée
Ge0

Profil challenge

Classement : 16/54279

Membre Senior
****
Hors ligne Hors ligne
Messages: 377


Voir le profil WWW
« #1 le: 08 Août 2016 à 19:30:46 »

Salut.

Citation
=> il trouve le PID de test.exe, mais pas de MessageBox

MessageBox censée s'afficher une fois l'injection achevée, j'imagine ?


Attache test.exe à un débogueur et énumère la liste des DLLs chargées dans le contexte de ton processus pour vérifier que l'injection a correctement abouti.

Tu peux aussi vérifier le nombre de threads dans test.exe puisque tu crées un thread sur le processus cible.

Enfin, peut-on avoir le code de ta DLL ?

---

Autrement je n'ai absolument rien compris ton problème.

Edit : c'est hors sujet, mais :

Code:
static DWORD GetProcessPID(char * processName)

N'oublie pas le const, puisque les données pointées par processName ne sont pas supposées être modifiées par ta fonction GetProcessPID.
« Dernière édition: 08 Août 2016 à 19:34:53 par Ge0 » Journalisée
Pech
Profil challenge

Classement : 34/54279

Membre Junior
**
Hors ligne Hors ligne
Messages: 83


Voir le profil
« #2 le: 08 Août 2016 à 21:01:50 »

Autrement je n'ai absolument rien compris ton problème.

Ca, c'est fait

Attache test.exe à un débogueur et énumère la liste des DLLs chargées dans le contexte de ton processus pour vérifier que l'injection a correctement abouti.
Tu peux aussi vérifier le nombre de threads dans test.exe puisque tu crées un thread sur le processus cible.

La liste des DLLs (les "executable modules" de Ollydbg) me confirme que ça ne marche pas.
Par contre, si je met mon test.exe dans le "working directory" -si le terme existe sous Windows- de la console, j'ai bien la MessageBox qui pop et ma DLL s'ajoute à la liste.

J'avais pas pensé à regarder les threads et, effectivement, il y a peut-être quelque chose à en tirer : à l'injection il crée un thread qui s'arrête immédiatement.
A voir de plus près.

----

Enfin, peut-on avoir le code de ta DLL ?

FYI, les codes de test.exe et test.dll c'est les templates de CodeBlocks (excepté, donc, l'appel à MessageBoxA que j'ai ajouté).

La DLL - main.cpp :
Code:
#include "main.h"

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if(fdwReason == DLL_PROCESS_ATTACH)
    {
        MessageBoxA(NULL, "Fake DLL loaded!", "test.dll", 0);
    }

    return TRUE;
}

La DLL - main.h :
Code:
#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>

/*  To use this exported function of dll, include this header
 *  in your project.
 */

#ifdef BUILD_DLL
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif


#ifdef __cplusplus
extern "C"
{
#endif

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

Le binaire de test :
Code:
#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#include <tchar.h>
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           _T("Code::Blocks Template Windows App"),       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Journalisée
Pech
Profil challenge

Classement : 34/54279

Membre Junior
**
Hors ligne Hors ligne
Messages: 83


Voir le profil
« #3 le: 09 Août 2016 à 18:14:13 »

Trouvé \o/

Avec Ollydbg j'ai breaké sur LoadLibraryA et constaté au fin fond de cette chose (aucune idée de comment ça marche) qu'il appelle une fonction nommée "LdrLoadDll".
Or elle renvoyait une erreur (c0000135, ce qui signifie qu'il ne trouve pas la DLL).
Forcément, s'il la trouve pas il y a peu de chance qu'il la charge...

Pour régler le problème, plusieurs choix :
* spécifier dans la commande le path absolu vers la DLL
* spécifier dans la commande le path relatif *au test.exe* vers la DLL
* mettre la DLL dans un dossier du PATH (et alors pas besoin de spécifier le path dans la commande)
Journalisée
Pages: [1]
  Imprimer  
 
Aller à: