如何在dll注入中调用特定函数?

时间:2014-08-27 07:31:24

标签: windows winapi dll code-injection dll-injection

以下代码将注入dll并将调用DllMain。我如何从DLL调用特定函数,而不仅仅是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());
    }

2 个答案:

答案 0 :(得分:5)

当您注入的DLL DllMain第一次运行时,请调用CreateThread创建一个可以执行任何操作的新线程。请注意,您无法按照文档中的说明从DllMain调用任意代码。因此,从CreateThread拨打DllMain

答案 1 :(得分:3)

好吧,我正在使用以下方法。

在正在注入的DLL中,我创建了一个共享部分,如下所示:

#pragma data_seg(".MyShared")

LPTHREAD_START_ROUTINE g_lpMyFunc = NULL;

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

然后在g_lpMyFunc内部初始化共享部分变量DllMain,如下所示:

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

此代码执行以下操作。函数调用GetModuleHandle尝试获取MyApp的可执行模块句柄。如果成功,则返回非NULL值,这意味着从远程进程调用注入的DLL的DllMain。如果是这种情况,MyFunc的地址将保存到g_lpMyFunc共享变量。如果DLL与进程分离(例如,当它退出时),我将g_lpMyFunc设置为NULL,以便无法通过不存在的远程地址调用函数。

然后我创建一个外部函数MyFuncExtern,在远程进程中调用MyFunc,如下所示:

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

这是一个非常简化的版本,但它显示了主要概念:如果g_lpMyFunc不是NULL,它会在hProcess中创建一个远程线程(就像在你的代码中一样)调用一个函数g_lpMyFunc指向的地址。

虽然CreateRemoteThread只为远程函数提供了一个参数(可以传递更多,但是它需要一个更复杂的方法),因此该函数存在一些限制,并且如果需要返回值,则必须等待远程线程完成执行并获取其退出代码,即DWORD

这种方法擅长编写Initialize / Uninitialize函数,而且,它非常适用于托管C ++ / CLI DLL。

当然,您可以使用任何其他跨进程数据存储来保存函数指针。内存映射文件就是一个很好的例子。