2012-09-15 27 views
3

我有一個遺留應用程序,其中包含一個需要提取數據的網格。如何將DLL注入到Delphi程序中

我沒有該應用程序的代碼,並且不可能通過常規方式(如以編程方式選擇所有單元格並將它們複製到剪貼板中)從其中獲取數據。

所以我決定用DLL注入作爲

節「二,遠程線程&調用LoadLibrary技術」描述

http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces

我的計劃是

  1. 到DLL加載到地址遺留應用程序的空間。
  2. 使DLL從網格讀取數據並將其寫出(例如通過命名管道)。

的第一步是將DLL注入到遺留應用的地址空間(步驟a)上文)。

我已經寫了下面的代碼爲:

int InjectDll   (HANDLE hProcess); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    printf("DllInjector\n"); 

    /** 
    * Find out PID of the legacy application (START) 
    */ 
    HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS"); 
    DWORD* processID = new DWORD; 
    GetWindowThreadProcessId(windowHandle, processID); 

    DWORD delphiAppProcessId = *processID; 
    /** 
    * Find out PID of the legacy application (END) 
    */ 

    printf("Process ID of legacy app: %lu\n", delphiAppProcessId); 

    // Now we need the handle of the legacy app 
    HANDLE hProcess = OpenProcess(
    PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, 
    FALSE, delphiAppProcessId); 

    if (hProcess != NULL) 
    { 
     printf("Found handle, ready for injection\n"); 
     int result = InjectDll(hProcess); 
     CloseHandle(hProcess); 
     printf("Injection complete, result=%d\n", result); 

    } 
    else 
    { 
     printf("Handle not found\n"); 
    } 

    system("pause"); 

    return 0; 
} 

int InjectDll(HANDLE hProcess) 
{ 
    HANDLE hThread; 
    const char* const szLibPath = "D:\\mycompany\\SampleDll\\Debug\\SampleDll.dll"; 
    void* pLibRemote = 0; // the address (in the remote process) where 
          // szLibPath will be copied to; 
    DWORD hLibModule = 0; // base adress of loaded module (==HMODULE); 

    HMODULE hKernel32 = ::GetModuleHandle(L"Kernel32"); 

    // 1. Allocate memory in the remote process for szLibPath 
    // 2. Write szLibPath to the allocated memory 
    pLibRemote = ::VirtualAllocEx(hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE); 
    if(pLibRemote == NULL) 
     return false; 
    ::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,sizeof(szLibPath),NULL); 

    // Load "LibSpy.dll" into the remote process 
    // (via CreateRemoteThread & LoadLibrary) 
    hThread = ::CreateRemoteThread(hProcess, NULL, 0, 
        (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryA"), 
        pLibRemote, 0, NULL); 
    if(hThread == NULL) 
     goto JUMP; 

    ::WaitForSingleObject(hThread, INFINITE); 

    // Get handle of loaded module 
    ::GetExitCodeThread(hThread, &hLibModule); 
    ::CloseHandle(hThread); 

JUMP: 
    ::VirtualFreeEx(hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE); 
    if(hLibModule == NULL) // (1) 
     return false; 


    // Unload "LibSpy.dll" from the remote process 
    // (via CreateRemoteThread & FreeLibrary) 
    hThread = ::CreateRemoteThread(hProcess, 
       NULL, 0, 
       (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"FreeLibrary"), 
       (void*)hLibModule, 
       0, NULL); 
    if(hThread == NULL) // failed to unload 
     return false; 

    ::WaitForSingleObject(hThread, INFINITE); 
    ::GetExitCodeThread(hThread, &hLibModule); 
    ::CloseHandle(hThread); 

    // return value of remote FreeLibrary (=nonzero on success) 
    return hLibModule; 
} 

一些評論:

  1. 遺留節目的標題爲 「FORMSSSSS」。
  2. 樣品DLL具有以下的DllMain方法:

-

BOOL APIENTRY DllMain(HMODULE hModule, 
DWORD ul_reason_for_call, 
LPVOID lpReserved 

{ 
    OutputDebugStringA("DllMain called: "); 
    switch (ul_reason_for_call) 
    { 
    case DLL_PROCESS_ATTACH: 
     OutputDebugStringA("DLL_PROCESS_ATTACH\n"); 
    case DLL_THREAD_ATTACH: 
     OutputDebugStringA("DLL_THREAD_ATTACH\n"); 
    case DLL_THREAD_DETACH: 
     OutputDebugStringA("DLL_THREAD_DETACH\n"); 
    case DLL_PROCESS_DETACH: 
     OutputDebugStringA("DLL_PROCESS_DETACH\n"); 
     break; 
    } 
    return TRUE; 
} 

當被調用時,文本被寫入到應用程序的標準輸出。


當運行上述程序(具有_tmain方法),我希望看到在控制檯輸出的文本

DllMain called: DLL_PROCESS_ATTACH 

(這意味着該DLL注射成功)。

但它沒有發生。


的一個潛在原因是遺留應用程序的PID被錯誤地確定:

HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS"); 
DWORD* processID = new DWORD; 
GetWindowThreadProcessId(windowHandle, processID); 

DWORD delphiAppProcessId = *processID; 

但價值delphiAppProcessId是一樣的PID顯示在任務管理器,這樣我就可以排除這種潛在的錯誤。


使用,我發現,在停止執行與註釋的行調試器(1):

JUMP: 
    ::VirtualFreeEx(hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE); 
    if(hLibModule == NULL) // (1) 
     return false; 

我需要什麼,以使樣本DLL改變被注入地址空間的標題爲「FORMSSSSS」的應用程序?

更新,2012年9月16日:

我取代

的sizeof(szLibPath)

由光程長度,所有出現的其中

const int的光程長度= strlen的(szLibPath)+ 1;

現在,在

::WaitForSingleObject(hThread, INFINITE); 
    ::GetExitCodeThread(hThread, &hLibModule); 
    ::CloseHandle(hThread); 

    // return value of remote FreeLibrary (=nonzero on success) 
    return hLibModule; 
} 

hLibModule爲非零值,這意味着該注射是成功的。

但我仍然無法在程序的輸出中看到示例DLL的日誌輸出。

更新,2012年9月16日(2):

當我

一個)DllMain中添加示例DLL, b)中重建,並 C的AllocConsole()的調用)執行注入程序

然後出現一個控制檯窗口,它具有與Delphi應用程序相同的圖標。

當我從DllMain函數中刪除AllocConsole並執行注入應用程序時,控制檯窗口不會出現。

所以注射可能實際上工作。

+0

您確定要「自己推出」,而不是隻購買MadCodeHook。它可以節省大量的工作。 –

回答

1

我能看到的最大的問題是sizeof(szLibPath)評估指針的大小。改爲使用strlen(szLibPath)+1

當然,這意味着您的注射將失敗,因爲LoadLibraryA收到的路徑將被截斷。可能還有其他問題,但這是開始的地方。

+0

或用const char szLibPath []代替以尋址,順便說一句。 – WhozCraig

+0

@克雷格是的,也會這樣做。 –

+0

謝謝。我已經這樣做了(請參閱「更新16.09.2012」),但仍然出現問題,因爲我沒有在注入應用程序的輸出中看到示例DLL生成的日誌消息。 –