How to call specific function in dll injection?

2019-04-10 00:15发布

问题:

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());
    }

回答1:

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.



回答2:

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.