c++dlldllexport

C++ Injection dll export function


I am trying to inject a dll in a windows .exe process for example notepad.exe, the injection works fine but when the dll is already injected in the process and I try to call the exported function it tells me that there is no such function in the dll.

Inyector

#include <Windows.h>
#include <stdio.h>
#include <cassert>
#include <TlHelp32.h> // Para enumerar módulos en el proceso remoto

// Función para obtener el handle del módulo cargado remotamente
HMODULE GetRemoteModuleHandle(HANDLE hProcess, const wchar_t* moduleName) {
    HMODULE hModule = nullptr;
    MODULEENTRY32 me = { sizeof(me) };

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hProcess));
    if (hSnapshot == INVALID_HANDLE_VALUE)
        return nullptr;

    if (Module32First(hSnapshot, &me)) {
        do {
            if (_wcsicmp(me.szModule, moduleName) == 0) {
                hModule = me.hModule;
                break;
            }
        } while (Module32Next(hSnapshot, &me));
    }

    CloseHandle(hSnapshot);
    return hModule;
}

int main(int argc, const char* argv[]) {
    if (argc < 3) {
        printf("Usage: Inyector <pid> <dllPath>\n");
        return 0;
    }

    auto pid = atoi(argv[1]);

    // Abrir el proceso objetivo
    HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD, FALSE, pid);
    if (!hProcess) {
        printf("Error opening process (%u)\n", GetLastError());
        return 1;
    }

    // Reservar memoria en el proceso objetivo
    auto p = VirtualAllocEx(hProcess, nullptr, 1 << 12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    assert(p);

    // Escribir la ruta de la DLL en la memoria del proceso
    WriteProcessMemory(hProcess, p, argv[2], strlen(argv[2]) + 1, nullptr);

    // Crear un hilo remoto que cargue la DLL usando LoadLibraryA
    auto hThread = CreateRemoteThread(hProcess, nullptr, 0,
        (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA"), p, 0, nullptr);

    assert(hThread);
    WaitForSingleObject(hThread, INFINITE);

    // Obtener el handle del módulo cargado en el proceso remoto
    HMODULE remoteModule = GetRemoteModuleHandle(hProcess, L"mydll.dll");
    if (!remoteModule) {
        printf("Error: No se pudo encontrar el módulo remoto\n");
        return 1;
    }

    // Calcular la dirección de la función exportada en el proceso remoto
    auto funcAddr = (LPVOID)GetProcAddress(GetModuleHandle(L"mydll.dll"), "MyFunc");
    if (!funcAddr) {
        printf("Error: No se pudo encontrar la función 'MyFunc'\n");
        return 1;
    }

    // Ajustar la dirección de la función para el proceso remoto
    uintptr_t remoteFuncAddr = (uintptr_t)funcAddr - (uintptr_t)GetModuleHandle(L"mydll.dll") + (uintptr_t)remoteModule;

    // Crear un hilo remoto para llamar a MyFunc
    auto hFuncThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)remoteFuncAddr, nullptr, 0, nullptr);
    if (!hFuncThread) {
        printf("Error: No se pudo ejecutar la función remota (%u)\n", GetLastError());
    }
    else {
        printf("Función remota ejecutada con éxito.\n");
    }

    // Limpiar
    CloseHandle(hFuncThread);
    CloseHandle(hThread);
    CloseHandle(hProcess);

    return 0;
}

Dll

#include <windows.h>


// Exportar la función
extern "C" __declspec(dllexport) void MyFunc(long parm1) {

    for (int i = 1; i <= 10; i++) {
        // Mostrar un cuadro de mensaje en cada iteración
        MessageBox(
            NULL,                                // Ventana padre (NULL para ninguna)
            L"Este es un mensaje de prueba",     // Texto del mensaje
            L"Iteración del MessageBox",         // Título del cuadro de mensaje
            MB_OK | MB_ICONINFORMATION           // Botón OK con un ícono de información
        );
    }

}

// Función opcional para el punto de entrada de la DLL
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

Injection process and calling the exported dll fucnion

Checking the name of the exported dll function with Visual Studio's developer tool

What could be going on?


Solution

  • The problem is that you are not loading your DLL into your injector process, but your injector process is trying to access your DLL's exported function. GetModuleHandle() won't be able to find the DLL and will return NULL, thus GetProcAddress() will also fail. But you are not doing any error checking on those calls, otherwise you would have seen this issue, eg:

    auto myDll = GetModuleHandle(L"mydll.dll");
    if (!myDLL) {
        // error handling...
    }
    
    auto funcAddr = GetProcAddress(myDLL, "MyFunc");
    if (!funcAddr) {
        // error handling...
    }
    ...
    

    GetModuleHandle() only looks at the calling process, not at the whole system (which is why you had to implement GetRemoteModuleHandle() in the first place). So, you need to change your injector to call LoadLibraryA() instead of GetModuleHandle(), eg:

    auto myDll = LoadLibraryA(argv[2]);
    if (!myDLL) {
        // error handling...
    }
    
    auto funcAddr = GetProcAddress(myDLL, "MyFunc");
    if (!funcAddr) {
        // error handling...
    }
    

    That being said, even if you could get this working, your exported DLL function doesn't conform to the signature that CreateRemoteThread() is expecting, so calling the DLL function in this manner will invoke undefined behavior in the target process.

    Change the signature of the DLL function to this instead:

    extern "C" __declspec(dllexport) DWORD WINAPI MyFunc(LPVOID parm1) {
        ...
        return 0;
    }
    

    And then use a .def file when compiling the DLL to ensure the function is exported as "MyFunc".


    On a side note: you are also leaking the memory that you allocate in the target process with VirtualAllocEx(). You need to free that memory with VirtualFreeEx() after the LoadLibraryA remote thread has ended.