DLL共享节技术可以让使用同一个DLL的多个进程共享一块内存(共享节),下面我通过一个项目来演示使用方法。
首先准备一个受害者程序,我选用了xp的扫雷,您也可以用任意喜欢的程序。
然后,编写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,
DWORD ul_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 <Windows.h>
#include <stdio.h>
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 = (PFNSETDATA)GetProcAddress(hModule, "SetData");
PFNGETDATA pFnGetData = (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放在相同目录下运行
先启动扫雷,在启动控制程序。
在控制台输入数据,修改共享节的缓冲区内容,对话框打印的内容就会变。
---------------------
作者:hambaga
来源:CSDN
原文:https://blog.csdn.net/Kwansy/article/details/108091081
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件