2014-08-27 85 views
4

以下代碼將注入dll並將調用DllMain。我如何從DLL中調用特定的函數,而不僅僅是DllMain?如何在dll注入中調用特定函數?

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

回答

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不爲空,它創建在hProcess中的遠程線程(就像在您的代碼中那樣)在g_lpMyFunc指向的地址處調用函數。

還有一些對功能有一定的侷限性,雖然因爲CreateRemoteThread只有一個參數遠程功能(你可以通多,但它需要一個顯著更復雜的方法),如果你需要一個返回值,你會必須等待遠程線程完成執行並獲取其退出代碼,即DWORD

該方法擅長編寫Initialize/Uninitialize函數,而且它完全適用於託管的C++/CLI DLL。

當然,您可以使用任何其他跨進程數據存儲來保存函數指針。內存映射文件就是一個很好的例子。

5

當您注入的DLL的DllMain第一次運行時,請撥打CreateThread來創建一個可以執行任何您喜歡的新線程。請注意,您不能從文檔中所述的DllMain調用任意代碼。因此撥打CreateThread來自DllMain