让我们假设远程线程过程如下所示:DWORD __stdcall ThreadProc (void *pData) { ThreadData *p = (ThreadData*)pData; // Contains function references and strings p->MessageBoxW(NULL, p->Message, p->Title, MB_OK);}然后,一切正常,p->MessageBoxW(...)会按预期显示一个消息框。但是我不想为我在远程线程中使用的每个函数都调用GetProcAddress,所以我认为我可以在模块内创建函数导出(EXE文件创建远程线程),以便远程线程仅调用将我的EXE文件作为模块加载到目标进程的地址空间中,而LoadLibraryW获取导出的函数的地址以便对其进行调用。typedef void (__stdcall *_Test) ();extern "C" void __stdcall Test () { return;}DWORD __stdcall ThreadProc (void *pData) { ThreadData *p = (ThreadData*)pData; // Contains function references and strings HMODULE hLib = p->LoadLibraryW(p->LibPath); _Test pTest = (_Test)p->GetProcAddress(hLib, p->ProcName); pTest(); p->FreeLibrary(hLib); return NULL;}这仍然可以正常工作。但是,一旦我将导出的功能更改为extern "C" void __stdcall Test () { MessageBoxW(NULL, L"Message", L"Title", MB_OK); return;}目标进程突然崩溃。 GetProcAddress不能解析模块间参考吗?是否可以将我的模块加载到目标进程的地址空间中,以便可以在不将所有函数地址传递给导出函数的情况下对导出的函数进行编码?附加信息:对于复制代码的每个人,我必须禁用增量链接,以发行版形式进行构建,并添加模块定义文件,以确保将LoadLibrary导出为Test而不是Test。由于某些原因,仅在_Test@SoMeJuNk前面添加无效。模块定义文件如下所示EXPORTS Test@0__declspec(dllexport)结构看起来像这样typedef struct tagThreadData { typedef BOOL (__stdcall *_FreeLibrary) (HMODULE); typedef FARPROC (__stdcall *_GetProcAddress) (HMODULE, PSTR); typedef HMODULE (__stdcall *_LoadLibraryW) (LPWSTR); typedef DWORD (__stdcall *_MessageBoxW) (HWND, LPWSTR, LPWSTR, DWORD); _FreeLibrary FreeLibrary; _GetProcAddress GetProcAddress; _LoadLibraryW LoadLibraryW; _MessageBoxW MessageBoxW; WCHAR LibPath[100]; WCHAR Message[30]; CHAR ProcName[10]; WCHAR Title[30];} ThreadData, *PThreadData; (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 我想出了一个临时解决方案:将所有远程代码放入实际的DLL中。但是将代码放入DLL并不是我的目标,因此,如果有人提出了一个聪明的解决方案,其中EXE文件既是注入器又是注入的模块,我将把新答案标记为正确。即使有许多关于如何将实际的DLL注入另一个进程的地址空间的教程,我仍然给出我的解决方案。我只为UNICODE和64位编写了原始解决方案,但我尽力使它对ASCII和UNICODE以及32位和64位都适用。但是让我们开始吧...首先,对基本步骤进行说明至少具有以下访问权限,以获得目标进程的句柄PROCESS_CREATE_THREADPROCESS_QUERY_INFORMATIONPROCESS_VM_OPERATIONPROCESS_VM_WRITEPROCESS_VM_READ为远程线程过程分配内存,以及加载目标dll及其“入口点”所需的数据和函数指针(我不是指实际的入口点DllMain,而是旨在从远程线程内部调用的函数)PVOID pThread = VirtualAllocEx(hProc, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);将远程线程过程和重要数据复制到目标进程WriteProcessMemory(hProc, pThread, ThreadProc, ThreadProcLen, NULL);WriteProcessMemory(hProc, pParam, &data, sizeof(ThreadData), NULL);创建远程线程。该线程将目标dll加载到目标进程的地址空间中,并调用其“入口点”HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (PTHREAD_START_ROUTINE)pThread, pParam, NULL, NULL);可选:等待线程返回WaitForSingleObject(hThread, INFINITE);DWORD threadExitCode;GetExitCodeThread(hThread, &threadExitCode);关闭线程句柄,释放内存,关闭进程句柄CloseHandle(hThread);VirtualFreeEx(hProc, pThread, 4096, MEM_RELEASE);CloseHandle(hProc);这是我的ThreadProc和ThreadData结构。 ThreadProc是由CreateRemoteThread调用的远程线程过程,并且应LoadLibrary目标dll,因此它可以调用目标dll的“入口点”。 ThreadData结构包含LoadLibrary,GetProcAddress和FreeLibrary的地址,目标dll的路径TargetDll以及“入口点” DllEntry的名称。typedef struct { typedef BOOL (__stdcall *_FreeLibrary) (HMODULE); typedef FARPROC (__stdcall *_GetProcAddress) (HMODULE, LPCH); typedef HMODULE (__stdcall *_LoadLibrary) (LPTSTR); typedef void (__stdcall *_DllEntry) (); _LoadLibrary LoadLibrary; TCHAR TargetDll[MAX_PATH]; _GetProcAddress GetProcAddress; CHAR DllEntry[50]; // Some entrypoint designed to be // called from the remote thread _FreeLibrary FreeLibrary;} ThreadData, *PThreadData;// ThreadProcLen should be smaller than 3400, because ThreadData can// take up to 644 bytes unless you change the length of TargetDll or// DllEntry#define ThreadProcLen (ULONG_PTR)2048#define SPY_ERROR_OK (DWORD)0#define SPY_ERROR_LOAD_LIB (DWORD)1#define SPY_ERROR_GET_PROC (DWORD)2DWORD ThreadProc (PVOID pParam) { DWORD err = SPY_ERROR_OK; PThreadData p = (PThreadData)pParam; // Load dll to be injected HMODULE hLib = p->LoadLibrary(p->TargetDll); if (hLib == NULL) return SPY_ERROR_LOAD_LIB; // Obtain "entrypoint" of dll (not DllMain) ThreadData::_DllEntry pDllEntry = (ThreadData::_DllEntry)p->GetProcAddress(hLib, p->DllEntry); if (pDllEntry != NULL) // Call dll's "entrypoint" pDllEntry(); else err = SPY_ERROR_GET_PROC; // Free dll p->FreeLibrary(hLib); return err;}然后是将远程线程过程注入目标进程的地址空间的实际代码int main(int argc, char* argv[]) { // DWORD pid = atoi(argv[1]); // Open process HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProc != NULL) { // Allocate memory in the target process's address space PVOID pThread = VirtualAllocEx(hProc, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pThread != NULL) { PVOID pParam = (PVOID)((ULONG_PTR)pThread + ThreadProcLen); // Initialize data to be passed to the remote thread ThreadData data; HMODULE hLib = LoadLibrary(TEXT("KERNEL32.DLL")); data.LoadLibrary = (ThreadData::_LoadLibrary)GetProcAddress(hLib, "LoadLibrary"); data.GetProcAddress = (ThreadData::_GetProcAddress)GetProcAddress(hLib, "GetProcAddress"); data.FreeLibrary = (ThreadData::_FreeLibrary)GetProcAddress(hLib, "FreeLibrary"); FreeLibrary(hLib); _tcscpy_s(data.TargetDll, TEXT("...")); // Insert path of target dll strcpy_s(data.DllEntry, "NameOfTheDllEntry"); // Insert name of dll's "entrypoint" // Write procedure and data into the target process's address space WriteProcessMemory(hProc, pThread, ThreadProc, ThreadProcLen, NULL); WriteProcessMemory(hProc, pParam, &data, sizeof(ThreadData), NULL); // Create remote thread (ThreadProc) HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (PTHREAD_START_ROUTINE)pThread, pParam, NULL, NULL); if (hThread != NULL) { // Wait until remote thread has finished if (WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0) { DWORD threadExitCode; // Evaluate exit code if (GetExitCodeThread(hThread, &threadExitCode) != FALSE) { // Evaluate exit code } else { // The thread's exit code couldn't be obtained } } else { // Thread didn't finish for some unknown reason } // Close thread handle CloseHandle(hThread); } // Deallocate memory VirtualFreeEx(hProc, pThread, 4096, MEM_RELEASE); } else { // Couldn't allocate memory in the target process's address space } // Close process handle CloseHandle(hProc); } return 0;}当DllMain将目标dll加载到目标进程的地址空间中时,被注入的dll具有一个实际的入口点LoadLibrary,并且由远程线程过程(如果可以找到它)调用另一个“入口点” NameOfTheDllEntry。首先)// Module.def:// LIBRARY NameOfDllWithoutExtension// EXPORTS// NameOfTheDllEntry__declspec(dllexport) void __stdcall NameOfTheDllEntry () { // Because the library is actually loaded in the target process's address // space, there's no need for obtaining pointers to every function. // I didn't try libraries other than kernel32.dll and user32.dll, but they // should be working as well as long as the dll itself references them // Do stuff return;}BOOL APIENTRY DllMain (HMODULE hLib, DWORD reason, PVOID) { if (reason == DLL_PROCESS_ATTACH) DisableThreadLibraryCalls(hLib); // Optional return TRUE;} (adsbygoogle = window.adsbygoogle || []).push({}); 10-07 15:10