Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call specific function in dll injection?

Following code will inject dll and DllMain will be called. How I call specific function from DLL, not just DllMain?

    DWORD pid;
    HANDLE hd;
    LPVOID gp, rs, proc;

    gp = (LPVOID)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryA");
    pid = 6096;

    hd = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);    


    rs = (LPVOID)VirtualAllocEx(hd, 0, sizeof(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

    if (!WriteProcessMemory(hd, (LPVOID)rs, DLL_NAME, strlen(DLL_NAME), 0))
    {
        printf("WriteProcessMemory %d", GetLastError());
    }

    if (!CreateRemoteThread(hd, 0, 0, (LPTHREAD_START_ROUTINE)gp, rs, 0, 0))
    {
        printf("CreateRemoteThread %d", GetLastError());
    }
like image 996
Pranit Kothari Avatar asked Feb 13 '23 04:02

Pranit Kothari


2 Answers

When your injected DLL's DllMain runs for the first time, call CreateThread to create a new thread that can do whatever you like. Note that you cannot call arbitrary code from DllMain as described in the documentation. Hence the call to CreateThread from DllMain.

like image 69
David Heffernan Avatar answered Feb 14 '23 18:02

David Heffernan


Well, I'm using the following approach.

In the DLL that is being injected, I create a shared section, like this:

#pragma data_seg(".MyShared")

LPTHREAD_START_ROUTINE g_lpMyFunc = NULL;

#pragma data_seg()
#pragma section(".MyShared", read, write, shared)

The shared section variable g_lpMyFunc is then initialized inside DllMain like this:

BOOL APIENTRY DllMain(HMODULE, DWORD dwReasonForCall, LPVOID)
{
    if (NULL != GetModuleHandle(_T("MyApp.exe")))
    {
        if (DLL_PROCESS_ATTACH == dwReasonForCall)
        {
            g_lpMyFunc = (LPTHREAD_START_ROUTINE)&MyFunc;
        }
        else if (DLL_PROCESS_DETACH == dwReasonForCall)
        {
            g_lpMyFunc = NULL;
        }
    }
    return TRUE;
}

This code does the following. The function call GetModuleHandle tries to get MyApp's executable module handle. If it succeeds, it return non-NULL value and that means that the injected DLL's DllMain is called from the remote process. If it's the case, the address of MyFunc is saved to g_lpMyFunc shared variable. And if the DLL is detached from the process (when it exits, for example), I set g_lpMyFunc to NULL in order to not be able to call a function by remote address that is not there.

I then create an external function MyFuncExtern that calls MyFunc in the remote process like this:

extern "C" __declspec(dllexport) bool __cdecl MyFuncExtern(HANDLE hProcess)
{
    if (NULL == g_lpMyFunc)
    {
        return false;
    }

    return NULL != CreateRemoteThread(hProcess, NULL, 0, g_lpMyFunc, NULL, 0, NULL);
}

It is a very simplified version, but it shows the main concept: if g_lpMyFunc is not NULL, it creates a remote thread in hProcess (just like in your code) that calls a function at the address pointed to by g_lpMyFunc.

There are some limitations on that function though since CreateRemoteThread takes only one argument for the remote function (you can pass more, however it will need a significantly more complicated approach), and if you need a return value you will have to wait for remote thread to complete execution and get its exit code, that is a DWORD.

This approach is good at writing Initialize / Uninitialize functions and, moreover, it perfectly works for managed C++/CLI DLLs.

And of course you can use any other cross-process data storage to save the function pointer(s). Memory mapped files are one good example.

like image 35
Alovchin Avatar answered Feb 14 '23 16:02

Alovchin