如何调用已被其他进程加载的DLL中的函数,求可行实现示例
方案1:使用CreateRemoteThread实现跨进程调用DLL导出函数
该方案前提:目标进程与调用程序架构一致(同为32位或64位)、目标进程已加载目标DLL、调用程序持有目标进程的足够操作权限
编译时需要链接psapi.lib库
#include <windows.h> #include <psapi.h> #include <iostream> int main() { // 替换为实际目标进程ID DWORD dwPid = 1234; // 替换为实际DLL文件名 const wchar_t* dllName = L"TestDll.dll"; // 1. 打开目标进程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); if (!hProcess) { std::cout << "打开进程失败,错误码:" << GetLastError() << std::endl; return 1; } // 2. 计算Test函数的内存偏移 HMODULE hLocalDll = LoadLibraryW(dllName); if (!hLocalDll) { std::cout << "本地加载DLL失败,错误码:" << GetLastError() << std::endl; CloseHandle(hProcess); return 1; } FARPROC pfnTestLocal = GetProcAddress(hLocalDll, "Test"); if (!pfnTestLocal) { std::cout << "获取Test函数地址失败,错误码:" << GetLastError() << std::endl; FreeLibrary(hLocalDll); CloseHandle(hProcess); return 1; } uintptr_t testOffset = (uintptr_t)pfnTestLocal - (uintptr_t)hLocalDll; FreeLibrary(hLocalDll); // 3. 枚举目标进程模块获取DLL基址 HMODULE hMods[1024]; DWORD cbNeeded; if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { WCHAR szModName[MAX_PATH]; if (GetModuleBaseNameW(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(WCHAR))) { if (_wcsicmp(szModName, dllName) == 0) { // 计算Test函数在目标进程的实际地址 uintptr_t pfnTestRemote = (uintptr_t)hMods[i] + testOffset; // 4. 创建远程线程执行Test函数 HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnTestRemote, NULL, 0, NULL); if (hRemoteThread) { WaitForSingleObject(hRemoteThread, INFINITE); CloseHandle(hRemoteThread); std::cout << "远程调用成功,可通过DebugView查看目标进程输出" << std::endl; } else { std::cout << "创建远程线程失败,错误码:" << GetLastError() << std::endl; } break; } } } } CloseHandle(hProcess); return 0; }
注意:该方案调用后Test函数返回的字符串指针属于目标进程地址空间,调用方无法直接读取,如需获取返回值需要额外做远程内存读取操作
方案2:使用命名管道实现IPC调用
该方案稳定性更高,不会触发安全软件误拦截,可直接获取返回值,也支持跨架构调用。需要将服务端逻辑集成到目标DLL中,随DLL加载启动。
服务端代码(集成到目标DLL)
// 管道服务线程函数 DWORD WINAPI PipeServerThread(LPVOID lpParam) { HANDLE hPipe = CreateNamedPipeW( L"\\\\.\\pipe\\TestDllPipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, 0, NULL ); if (hPipe == INVALID_HANDLE_VALUE) { return 1; } while (true) { // 等待客户端连接 if (ConnectNamedPipe(hPipe, NULL)) { WCHAR recvBuf[256]; DWORD dwRead; if (ReadFile(hPipe, recvBuf, sizeof(recvBuf), &dwRead, NULL)) { // 约定收到CallTest指令则执行Test函数 if (wcscmp(recvBuf, L"CallTest") == 0) { LPCWSTR result = Test(); DWORD dwWritten; WriteFile(hPipe, result, (wcslen(result) + 1) * sizeof(WCHAR), &dwWritten, NULL); } } DisconnectNamedPipe(hPipe); } } CloseHandle(hPipe); return 0; } // 修改DllMain的DLL_PROCESS_ATTACH分支,加载DLL时启动服务线程 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { OutputDebugStringW(L"Loading Library..."); switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: CreateThread(NULL, 0, PipeServerThread, NULL, 0, NULL); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
客户端代码(发起调用的程序)
#include <windows.h> #include <iostream> int main() { HANDLE hPipe = CreateFileW( L"\\\\.\\pipe\\TestDllPipe", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if (hPipe == INVALID_HANDLE_VALUE) { std::cout << "连接管道失败,错误码:" << GetLastError() << std::endl; return 1; } // 发送调用请求 const WCHAR* req = L"CallTest"; DWORD dwWritten; WriteFile(hPipe, req, (wcslen(req) + 1) * sizeof(WCHAR), &dwWritten, NULL); // 读取返回结果 WCHAR resp[256]; DWORD dwRead; ReadFile(hPipe, resp, sizeof(resp), &dwRead, NULL); std::wcout << L"调用Test返回结果:" << resp << std::endl; CloseHandle(hPipe); return 0; }
内容的提问来源于stack exchange,提问作者user16839617
相关产品推荐
相关产品推荐

