3

抽出する必要があるデータを含むグリッドを含むレガシー アプリケーションがあります。

そのアプリケーションのコードがなく、通常の方法 (プログラムですべてのセルを選択してクリップボードにコピーするなど) でデータを取得することは不可能です。

そこで、セクション「II. The CreateRemoteThread & LoadLibrary Technique」で説明されているように、DLL インジェクションを使用することにしました。

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 インジェクションが成功したことを意味します)。

しかし、それは起こりません。


考えられる原因の 1 つは、レガシー アプリケーションの 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)

pathLength による、ここで

const int pathLength = 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):

私が

a) サンプル DLL の DllMain に AllocConsole() への呼び出しを追加し、b) 再構築し、c) 注入プログラムを実行します。

Delphi アプリケーションと同じアイコンのコンソール ウィンドウが表示されます。

DllMain 関数から AllocConsole を削除し、注入アプリケーションを実行すると、コンソール ウィンドウが表示されません。

したがって、注射は実際に機能する可能性があります。

4

1 に答える 1

1

私が見ることができる最大の問題sizeof(szLibPath)は、ポインターのサイズに評価されることです。strlen(szLibPath)+1代わりに使用してください。

LoadLibraryA確かに、これは、受信するパスが切り捨てられるため、インジェクションが失敗することを意味します。他の問題があるかもしれませんが、それが出発点です。

于 2012-09-15T12:51:59.850 に答える