进程间通信——DLL共享节

DLL共享节技术可以让使用同一个DLL的多个进程共享一块内存(共享节),下面我通过一个项目来演示使用方法。
首先准备一个受害者程序,我选用了xp的扫雷,您也可以用任意喜欢的程序。
进程间通信——DLL共享节
文章图片

然后,编写DLL,DLL中需要设置共享节,然后在本项目中,DLL被注入到扫雷进程,然后循环打印共享节中的数据,这个数据可以被控制程序修改。
下面是DLL代码,g_buffer就是共享节的数据。

// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "framework.h"#pragma data_seg("Shared") char g_buffer[0x1000] = {0}; #pragma data_seg() #pragma comment(linker,"/section:Shared,rws")extern "C"__declspec(dllexport) void SetData(char *buf, DWORD dwDataLen) { ZeroMemory(g_buffer, 0x1000); memcpy(g_buffer, buf, dwDataLen); }extern "C"__declspec(dllexport) void GetData(char *buf) { memcpy(buf, g_buffer, 0x1000); }BOOL APIENTRY DllMain( HMODULE hModule, DWORDul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { // 区分是目标进程(游戏)还是控制进程(WG) // 如果是扫雷进程(winmine.exe)则开始接收数据 char szModule[MAX_PATH] = { 0 }; GetModuleFileNameA(NULL, szModule, MAX_PATH); if (strstr(szModule, "winmine") != NULL) { MessageBoxA(NULL, "扫雷程序注入DLL成功", "", MB_OK); while (1) { if (strcmp(g_buffer, "quit") == 0) break; // 控制程序给的退出信号 MessageBoxA(NULL, g_buffer, szModule, MB_OK); } } break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }

然后是控制端代码,就是不停的修改共享节的数据而已。。
#define _CRT_SECURE_NO_WARNINGS #include #include BOOL InjectDLL(); BOOL EnableDebugPrivilege(); int main() { if (FALSE == InjectDLL()) { printf("注入DLL失败\n"); return -1; } else { printf("注入DLL成功\n"); } HMODULE hModule = LoadLibraryA("DLLShareSection-DLL.dll"); if (hModule == NULL) { printf("获取DLL句柄失败\n"); return -1; } typedef void (*PFNSETDATA)(char *, DWORD); typedef void (*PFNGETDATA)(char *); PFNSETDATA pFnSetData = https://www.it610.com/article/(PFNSETDATA)GetProcAddress(hModule,"SetData"); PFNGETDATA pFnGetData = https://www.it610.com/article/(PFNGETDATA)GetProcAddress(hModule,"GetData"); char szBuffer[0x1000]; while (1) { printf("输入要发送的数据: "); ZeroMemory(szBuffer, 0x1000); scanf("%s", szBuffer); pFnSetData(szBuffer, strlen(szBuffer)); //pFnGetData(szBuffer); //printf("修改数据成功,当前数据: %s\n", szBuffer); if (strcmp(szBuffer, "quit") == 0) break; } return 0; }// 远程线程注入 BOOL InjectDLL() { // 提权(win10) EnableDebugPrivilege(); // 根据窗口名获取进程句柄 HWND hWnd = FindWindowA(NULL, "扫雷"); if (hWnd == NULL) { printf("获取窗口句柄失败\n"); return FALSE; } DWORD dwPid = -1; GetWindowThreadProcessId(hWnd, &dwPid); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); if (hProcess == INVALID_HANDLE_VALUE) { printf("打开进程失败\n"); return FALSE; } // 在要注入的进程中申请一块内存,作为LoadLibrary的参数 char szDllName[MAX_PATH] = "DLLShareSection-DLL.dll"; LPVOID pAddress = VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); WriteProcessMemory(hProcess, pAddress, szDllName, strlen(szDllName), NULL); // 创建远程线程,线程入口设置为LoadLibrary,这样就可以自动加载dll HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, pAddress, 0, NULL); //VirtualFreeEx(hProcess, pAddress, 0, MEM_RELEASE); CloseHandle(hProcess); return TRUE; }// 提权函数:提升为DEBUG权限 BOOL EnableDebugPrivilege() { HANDLE hToken; BOOL fOk = FALSE; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); fOk = (GetLastError() == ERROR_SUCCESS); CloseHandle(hToken); } return fOk; }

运行结果 注意要把扫雷,控制端程序和DLL放在相同目录下运行
进程间通信——DLL共享节
文章图片

先启动扫雷,在启动控制程序。
进程间通信——DLL共享节
文章图片

在控制台输入数据,修改共享节的缓冲区内容,对话框打印的内容就会变。
【进程间通信——DLL共享节】进程间通信——DLL共享节
文章图片

    推荐阅读