5

我想在我制作的注入 DLL 的远程进程中调用一个函数。

我已成功注入我的 DLL:

CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA"), pLibRemote, 0, NULL);

DllMain 被执行并且 DLL 在待机模式下运行。我想做的是以某种方式调用远程加载的 DLL 来做一些工作。

我试过像这样导出函数:

extern "C" __declspec(dllexport) void MyFunc(void)

然后像这样执行函数:

CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("mydll"), "MyFunc"), NULL, 0, NULL);

但这会导致崩溃。

我该如何解决这个问题?

4

2 回答 2

13

按照您的方式调用GetModuleHandle将获得 DLL 的基础,因为它被映射到您的进程中(如果有的话)。所以你需要做的是首先确保在DLL中导出函数。您可以照常做或创建一个文件,如此.def所示。此后:

理论上

  1. 将 DLL 注入目标进程并获取加载它的基地址
  2. 将 DLL 注入当前进程。用于GetProcAddress查找导出的函数与 DLL 的基础之间的偏移量。
  3. 将此偏移量添加到从步骤 1.CreateRemoteThread在此位置获得的基地址。

在实践中

在进行 DLL 注入时,您可以获得将 DLL 加载到目标中的基础。

HMODULE hInjected;

hThread = CreateRemoteThread( hProcess, NULL, 0,
      (LPTHREAD_START_ROUTINE)( GetProcAddress( hMod,
      "LoadLibraryW" ) ), lpAddress, 0, NULL );

// Locate address our payload was loaded
if( hThread != 0 ) {
  WaitForSingleObject( hThread, INFINITE );
  GetExitCodeThread( hThread, ( LPDWORD )&hInjected );
  CloseHandle( hThread );
}

hInjected将是注入的 DLL 的基础。然后我有另一个功能:

void* GetPayloadExportAddr( LPCWSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName ) {
  // Load payload in our own virtual address space
  HMODULE hLoaded = LoadLibrary( lpPath );

  if( hLoaded == NULL ) {
    return NULL;
  } else {
    void* lpFunc   = GetProcAddress( hLoaded, lpFunctionName );
    DWORD dwOffset = (char*)lpFunc - (char*)hLoaded;

    FreeLibrary( hLoaded );
    return (DWORD)hPayloadBase + dwOffset;
  }
}

这样做是首先将有效负载加载到我们自己的虚拟地址空间中。之后,我们可以使用GetProcAddress来获取导出函数的地址。由此,我们可以得到函数相对于 DLL 基础的偏移量。将此偏移量添加到hInjected我们之前获得的值中将告诉我们CreateRemoteThread应该在哪里进行调用。所以你可以这样打电话:

BOOL InitPayload( HANDLE hProcess, LPCWSTR lpPath, HMODULE hPayloadBase, HWND hwndDlg ) {
  void* lpInit = GetPayloadExportAddr( lpPath, hPayloadBase, "Init" );
  if( lpInit == NULL ) {
    return FALSE;
  } else {
    HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
        lpInit, hwndDlg, 0, NULL );

    if( hThread == NULL ) {
      return FALSE;
    } else {
      CloseHandle( hThread );
    }
  }

  return TRUE;
}

这是从我拥有的旧项目中提取的所有代码。欢迎您使用代码并做任何您想做的事情,但我知道如果我现在要重写代码,我会做很多不同的事情。

于 2012-04-07T21:40:21.340 回答
3

如果您将 32 位 DLL 注入 32 位进程,则迈克的回答有效。

如果要将 64 位 DLL 注入 64 位进程,则无法从中获取 DLL 的基地址,GetExitCodeThread因为它只会为您提供 64 位地址的低 32 位。

在这种情况下,要获得正确的地址,您必须在调用的进程中写入一段代码LoadLibrary(将结果存储在进程内存中的特定位置),执行这段代码(使用CreateRemoteThread),然后从该位置使用ReadProcessMemory.

您可以在此处找到更多详细信息(包括 PowerShell 和 ASM 代码):http: //clymb3r.wordpress.com/2013/05/26/implementing-remote-loadlibrary-and-remote-getprocaddress-using-powershell-and -部件/

然后,您可以按照 Mike 描述的相同方式计算导出函数的偏移量,但请注意将差异存储在 64 位值中,而不是存储在 DWORD(即 32 位)中。

于 2013-07-14T06:27:24.800 回答