【问题标题】:How to inject a DLL into a Delphi program如何将DLL注入Delphi程序
【发布时间】:2012-09-15 12:26:07
【问题描述】:

我有一个旧应用程序,其中包含一个网格,其中包含我需要提取的数据。

我没有该应用程序的代码,并且无法通过正常方式从中获取数据(例如以编程方式选择所有单元格并将它们复制到剪贴板)。

所以我决定使用“II. CreateRemoteThread & LoadLibrary 技术”一节中所述的 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;
}

一些cmets:

  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是一样的,所以我可以排除这个潜在的bug。


使用调试器我发现执行在注释 (1) 行停止:

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

为了将示例 DLL 注入标题为“FORMSSSSS”的应用程序的地址空间,我需要进行哪些更改?

更新,16.09.2012:

我替换了所有出现的

sizeof(szLibPath)

按路径长度,其中

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的日志输出。

更新,16.09.2012 (2):

当我

a) 在示例 DLL 的 DllMain 中添加对 AllocConsole() 的调用, b) 重建它并 c) 执行注入程序,

然后会出现一个控制台窗口,其图标与 Delphi 应用程序相同。

当我从 DllMain 函数中删除 AllocConsole 并执行注入应用程序时,控制台窗口不会出现。

所以注入可能真的有效。

【问题讨论】:

  • 您确定要“自己动手”,而不仅仅是购买 MadCodeHook。它可以为您节省大量精力。

标签: c++ windows delphi winapi delphi-2009


【解决方案1】:

我能看到的最大问题是sizeof(szLibPath) 的计算结果是指针的大小。请改用strlen(szLibPath)+1

这肯定意味着您的注入将失败,因为LoadLibraryA 接收到的路径将被截断。可能还有其他问题,但这是开始的地方。

【讨论】:

  • 或替换为 const char szLibPath[] 来解决,顺便说一句。
  • @Craig 是的,那也可以。
  • 谢谢。我已经这样做了(请参阅“更新 16.09.2012”),但仍然出现问题,因为我在注入应用程序的输出中没有看到示例 DLL 生成的日志消息。
  • 使用 MessageBox 进行诊断。我希望这会产生结果。
  • 从您的更新看来,我已经回答了您的问题。
猜你喜欢
  • 2014-06-01
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 2012-09-22
  • 1970-01-01
  • 2011-01-27
相关资源
最近更新 更多