如何将DLL注入Delphi程序

时间:2012-09-15 12:26:08

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

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

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

所以我决定使用DLL注入,如“II.The CreateRemoteThread& LoadLibrary技术”一节所述

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

我的计划是

  1. 将DLL加载到旧版应用程序的地址空间中。
  2. 让DLL从网格中读取数据并将其写出来(例如通过命名管道)。

  3. 第一步是将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方法:
    3. -

      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)

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

      更新,16.09.2012(2):

      当我

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

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

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

      因此注射可能确实有效。

1 个答案:

答案 0 :(得分:1)

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

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