游戏注入教程(一)--远程线程注入

时间:2022-08-31 20:31:37

一、我们新建一个win32的dll,用来注入到游戏进程当中,注入成功的时候,会提示“注入成功”,而且提示注入到哪个窗口。

代码如下:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

// 枚举窗口进程ID是否为主进程
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) {
DWORD dwCurrentProcessId = *((DWORD*)lParam);
DWORD dwProcessId = 0;
GetWindowThreadProcessId(hWnd, &dwProcessId);
if (dwProcessId == dwCurrentProcessId && GetParent(hWnd) == NULL) {
*((HWND*)lParam) = hWnd;
return FALSE;
}
return TRUE;
}
// 获取主窗口的句柄
HWND GetMainHwnd()
{
DWORD dwCurrentProcessId = GetCurrentProcessId();
if (!EnumWindows(EnumWindowsProc, (LPARAM)&dwCurrentProcessId))
{
return (HWND)dwCurrentProcessId;
}
return NULL;
}

BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBox(GetMainHwnd(), TEXT("注入成功"), TEXT("目标程序"), MB_OK);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
MessageBox(GetMainHwnd(), TEXT("卸载注入"), TEXT("目标程序"), MB_OK);
break;
}
return TRUE;
}



二、如果要将上面的win32的dll注入到游戏进程当中,需要下面3个函数

ChangePrivilege函数的目的是为了让当前exe注入工具可以进行debug调试,此函数非必须

InjectLib,需要一个目标游戏进程ID,以及上面待注入的dll的绝对路径,路径是unicode字符串。

EjectLib,用来卸载已经注入的dll。

// 修改当前进程权限为DEBUG
BOOL ChangePrivilege() {
BOOL bOk = FALSE;
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tp;
LUID luid;
__try {
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) __leave;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) __leave;
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) __leave;
bOk = TRUE;
}
__finally {
if (hToken != NULL)
CloseHandle(hToken);
}
return bOk;
}

// 注入DLL函数
BOOL InjectLib(DWORD dwProcessId,PCWSTR pszLibFile) {
BOOL bOk = FALSE;
HANDLE hProcess = NULL, hThread = NULL;
PWSTR pszLibFileRemote = NULL;
__try {
// 获取目标进程的句柄
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | // Required by Alpha
PROCESS_CREATE_THREAD | // For CreateRemoteThread
PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx
PROCESS_VM_WRITE, // For WriteProcessMemory
FALSE,dwProcessId);
if (hProcess == NULL) __leave;
// 计算dll文件路径注入到目标处,需要多少字节的内存
int cb = (lstrlenW(pszLibFile) + 1) * sizeof(wchar_t);
// 在目标进程中申请一块内存
pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess,NULL,cb,MEM_COMMIT,PAGE_READWRITE);
if (pszLibFileRemote == NULL) __leave;
// 将文件路劲拷贝到刚申请的内存中
if (!WriteProcessMemory(hProcess, pszLibFileRemote, (LPVOID)pszLibFile, cb, NULL)) __leave;
// 获取LoadLibraryW在Kernel32中的真实地址
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
if (pfnThreadRtn == NULL) __leave;
// 创建一个远线程,并调用LoadLibraryW
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
if (hThread == NULL) __leave;
// 等待远线程的结束
WaitForSingleObject(hThread, INFINITE);
bOk = TRUE;
}
__finally {
if (pszLibFileRemote != NULL)
VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
if (hThread != NULL)
CloseHandle(hThread);
if (hProcess != NULL)
CloseHandle(hProcess);
}
return bOk;
}
// 卸载注入函数
BOOL EjectLib(DWORD dwProcessId, PCWSTR pszLibFile) {
BOOL bOk = FALSE;
HANDLE hProcess = NULL, hThread = NULL;
HANDLE hthSnapshot = NULL;
__try {
// 获取一个进程快照
hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if (hthSnapshot == INVALID_HANDLE_VALUE) __leave;
// 获取模块的结构信息
MODULEENTRY32W me = {sizeof(me)};
BOOL bFound = FALSE;
BOOL bMoreMods = Module32FirstW(hthSnapshot, &me);
for (; bMoreMods;bMoreMods = Module32NextW(hthSnapshot,&me))
{
bFound = (_wcsicmp(me.szModule, pszLibFile) == 0) || (_wcsicmp(me.szExePath, pszLibFile) == 0);
if (bFound) break;
}
if (!bFound) __leave;

// 获取目标进程的句柄
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | // Required by Alpha
PROCESS_CREATE_THREAD | // For CreateRemoteThread
PROCESS_VM_OPERATION, // For VirtualAllocEx/VirtualFreeEx
FALSE, dwProcessId);
if (hProcess == NULL) __leave;

// 获取FreeLibrary在Kernel32中的真实地址
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
if (pfnThreadRtn == NULL) __leave;
// 创建一个远线程,并调用FreeLibrary
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, me.modBaseAddr, 0, NULL);
if (hThread == NULL) __leave;
// 等待远线程的结束
WaitForSingleObject(hThread, INFINITE);
bOk = TRUE;
}
__finally {
if (hthSnapshot != NULL)
CloseHandle(hthSnapshot);
if (hThread != NULL)
CloseHandle(hThread);
if (hProcess != NULL)
CloseHandle(hProcess);
}
return bOk;
}

三、使用方法。

创建一个exe程序,onclick事件中如下调用:

void CInjectToolDlg::OnBnClickedInject()
{
BOOL bOk = FALSE;
DWORD dwProcessId = 0,dwThreadId = 0;
HWND hWnd = ::FindWindow(NULL, _T("demo1"));
if (hWnd == NULL) {
AfxMessageBox(_T("demo1 Window not found.")); return;
}
dwThreadId = ::GetWindowThreadProcessId(hWnd, &dwProcessId);
if (dwThreadId == NULL) {
AfxMessageBox(_T("demo1 thread id not fetch.")); return;
}
if (!InjectLib(dwProcessId, L"F:\\CPP\\pro\\inject\\Release\\inject.dll")) {
AfxMessageBox(_T("InjectLib Error."));
}
}

void CInjectToolDlg::OnBnClickedEject()
{
BOOL bOk = FALSE;
DWORD dwProcessId = 0, dwThreadId = 0;
HWND hWnd = ::FindWindow(NULL, _T("demo1"));
if (hWnd == NULL) {
AfxMessageBox(_T("demo1 Window not found.")); return;
}
dwThreadId = ::GetWindowThreadProcessId(hWnd, &dwProcessId);
if (dwThreadId == NULL) {
AfxMessageBox(_T("demo1 thread id not fetch.")); return;
}
if (!EjectLib(dwProcessId, L"F:\\CPP\\pro\\inject\\Release\\inject.dll")) {
AfxMessageBox(_T("EjectLib Error."));
}
}