日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

游戏修改器制作教程七:注入DLL的各种姿势

發布時間:2023/12/31 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 游戏修改器制作教程七:注入DLL的各种姿势 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

教程面向有C\C++基礎的人,最好還要懂一些Windows編程知識
代碼一律用Visual Studio 2013編譯,如果你還在用VC6請趁早丟掉它...
寫這個教程只是為了讓玩家更好地體驗所愛的單機游戲,順便學到些逆向知識,我不會用網絡游戲做示范,請自重

往其他進程注入代碼大概分兩種,一種是像CE注入代碼那樣在目標進程申請內存,然后把機器碼寫進去,另一種是用高級語言寫一個DLL,然后注入目標進程(顯然是用高級語言實現更方便!)
注入的代碼就是目標進程的一部分了,可以直接用指針讀寫目標進程內存,還可以hook目標進程的函數

本章介紹幾種常用的注入DLL的方法

遠線程注入

遠線程注入的原理是在目標進程調用LoadLibrary載入我們的DLL

首先寫個DLL用來測試,實現禁止結束進程

// dllmain.cpp : 定義 DLL 應用程序的入口點。 #include "stdafx.h"// hook代碼略,參考上一章BYTE terminateProcessOldCode[sizeof(JmpCode)];BOOL WINAPI MyTerminateProcess(HANDLE hProcess, UINT uExitCode) {return FALSE; // 禁止結束進程 }// DLL被加載、卸載時調用 BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {TCHAR processPath[256];TCHAR msg[270];switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:GetModuleFileName(GetModuleHandle(NULL), processPath, sizeof(processPath) / sizeof(processPath[0]));_stprintf_s(msg, _T("注入了進程 %s"), processPath);MessageBox(NULL, msg, _T(""), MB_OK);hook(GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "TerminateProcess"), MyTerminateProcess, terminateProcessOldCode);break;case DLL_PROCESS_DETACH:MessageBox(NULL, _T("DLL卸載中"), _T(""), MB_OK);// 卸載時記得unhookunhook(GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "TerminateProcess"), terminateProcessOldCode);break;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:break;}return TRUE; }

然后寫個EXE用來注入DLL

主要用到的API:

// 載入DLL HMODULE WINAPI LoadLibrary(_In_ LPCTSTR lpFileName );// 在目標進程創建遠線程,相當于調用目標進程的函數 HANDLE WINAPI CreateRemoteThread(_In_ HANDLE hProcess,_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,_In_ SIZE_T dwStackSize,_In_ LPTHREAD_START_ROUTINE lpStartAddress,_In_ LPVOID lpParameter,_In_ DWORD dwCreationFlags,_Out_ LPDWORD lpThreadId );// 在目標進程申請內存 LPVOID WINAPI VirtualAllocEx(_In_ HANDLE hProcess,_In_opt_ LPVOID lpAddress,_In_ SIZE_T dwSize,_In_ DWORD flAllocationType,_In_ DWORD flProtect );

遠線程注入DLL的實現有兩個前提
1. kernel32比較特殊,這個模塊的基址在每個進程是一樣的(當然,32位和64位是不一樣的),所以本進程中的LoadLibrary地址可以用在其他進程(只要本進程和其他進程位數一樣)
2. LoadLibrary需要一個參數,而且CreateRemoteThread剛好能傳入一個參數

EXE代碼(建議下載GitHub上的整個項目看看):

// 注入DLL,返回模塊句柄(64位程序只能返回低32位) HMODULE InjectDll(HANDLE process, LPCTSTR dllPath) {DWORD dllPathSize = ((DWORD)_tcslen(dllPath) + 1) * sizeof(TCHAR);// 申請內存用來存放DLL路徑void* remoteMemory = VirtualAllocEx(process, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);if (remoteMemory == NULL){printf("申請內存失敗,錯誤代碼:%u\n", GetLastError());return 0;}// 寫入DLL路徑if (!WriteProcessMemory(process, remoteMemory, dllPath, dllPathSize, NULL)){printf("寫入內存失敗,錯誤代碼:%u\n", GetLastError());return 0;}// 創建遠線程調用LoadLibraryHANDLE remoteThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, remoteMemory, 0, NULL);if (remoteThread == NULL){printf("創建遠線程失敗,錯誤代碼:%u\n", GetLastError());return NULL;}// 等待遠線程結束WaitForSingleObject(remoteThread, INFINITE);// 取DLL在目標進程的句柄DWORD remoteModule;GetExitCodeThread(remoteThread, &remoteModule);// 釋放CloseHandle(remoteThread);VirtualFreeEx(process, remoteMemory, dllPathSize, MEM_DECOMMIT);return (HMODULE)remoteModule; }// 卸載DLL BOOL FreeRemoteDll(HANDLE process, HMODULE remoteModule) {// 創建遠線程調用FreeLibraryHANDLE remoteThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)remoteModule, 0, NULL);if (remoteThread == NULL){printf("創建遠線程失敗,錯誤代碼:%u\n", GetLastError());return FALSE;}// 等待遠線程結束WaitForSingleObject(remoteThread, INFINITE);// 取返回值DWORD result;GetExitCodeThread(remoteThread, &result);// 釋放CloseHandle(remoteThread);return result != 0; }#ifdef _WIN64 #include <tlhelp32.h> HMODULE GetRemoteModuleHandle(DWORD pid, LPCTSTR moduleName) {HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);MODULEENTRY32 moduleentry;moduleentry.dwSize = sizeof(moduleentry);BOOL hasNext = Module32First(snapshot, &moduleentry);HMODULE handle = NULL;do{if (_tcsicmp(moduleentry.szModule, moduleName) == 0){handle = moduleentry.hModule;break;}hasNext = Module32Next(snapshot, &moduleentry);} while (hasNext);CloseHandle(snapshot);return handle; } #endifint _tmain(int argc, _TCHAR* argv[]) {// 提升權限,不提升貌似也可以,以管理員身份運行就行EnablePrivilege(TRUE);// 打開進程HWND hwnd = FindWindow(NULL, _T("任務管理器"));DWORD pid;GetWindowThreadProcessId(hwnd, &pid);HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);if (process == NULL){printf("打開進程失敗,錯誤代碼:%u\n", GetLastError());return 1;}// 要將RemoteThreadDll.dll放在本程序當前目錄下TCHAR dllPath[MAX_PATH]; // 要用絕對路徑GetCurrentDirectory(_countof(dllPath), dllPath);_tcscat_s(dllPath, _T("\\RemoteThreadDll.dll"));// 注入DLLHMODULE remoteModule = InjectDll(process, dllPath);if (remoteModule == NULL){CloseHandle(process);return 2;} #ifdef _WIN64remoteModule = GetRemoteModuleHandle(pid, _T("RemoteThreadDll.dll"));printf("模塊句柄:0x%08X%08X\n", *((DWORD*)&remoteModule + 1), (DWORD)remoteModule); #elseprintf("模塊句柄:0x%08X\n", (DWORD)remoteModule); #endif// 暫停printf("按回車卸載DLL\n");getchar();// 卸載DLLif (!FreeRemoteDll(process, remoteModule)){CloseHandle(process);return 3;}// 關閉進程CloseHandle(process);return 0; }

結果

64位的win10:

然后任務管理器無法結束任務,按回車后

又可以結束任務了

32位的win7:

(同上)

在主線程運行前遠線程注入

這個跟上面差不多,只是在目標進程的主線程運行前就可以運行我們DLL的代碼,可以提前做些手腳

方法是用CreateProcess創建進程時指定CREATE_SUSPENDED標志,這樣主線程就被掛起了,然后用遠線程注入DLL,再恢復主線程

// 程序運行時注入DLL,返回模塊句柄(64位程序只能返回低32位) HMODULE InjectDll(LPTSTR commandLine, LPCTSTR dllPath, DWORD* pid, HANDLE* process) {TCHAR* commandLineCopy = new TCHAR[32768]; // CreateProcess可能修改這個_tcscpy_s(commandLineCopy, 32768, commandLine);int cdSize = _tcsrchr(commandLine, _T('\\')) - commandLine + 1;TCHAR* cd = new TCHAR[cdSize];_tcsnccpy_s(cd, cdSize, commandLine, cdSize - 1);// 創建進程并暫停STARTUPINFO startInfo = {};PROCESS_INFORMATION processInfo = {};if (!CreateProcess(NULL, commandLineCopy, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, cd, &startInfo, &processInfo)){delete commandLineCopy;delete cd;return 0;}delete commandLineCopy;delete cd;*pid = processInfo.dwProcessId;*process = processInfo.hProcess;DWORD dllPathSize = ((DWORD)_tcslen(dllPath) + 1) * sizeof(TCHAR);// 申請內存用來存放DLL路徑void* remoteMemory = VirtualAllocEx(processInfo.hProcess, NULL, dllPathSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);if (remoteMemory == NULL){printf("申請內存失敗,錯誤代碼:%u\n", GetLastError());return 0;}// 寫入DLL路徑if (!WriteProcessMemory(processInfo.hProcess, remoteMemory, dllPath, dllPathSize, NULL)){printf("寫入內存失敗,錯誤代碼:%u\n", GetLastError());return 0;}// 創建遠線程調用LoadLibraryHANDLE remoteThread = CreateRemoteThread(processInfo.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, remoteMemory, 0, NULL);if (remoteThread == NULL){printf("創建遠線程失敗,錯誤代碼:%u\n", GetLastError());return NULL;}// 等待遠線程結束WaitForSingleObject(remoteThread, INFINITE);// 取DLL在目標進程的句柄DWORD remoteModule;GetExitCodeThread(remoteThread, &remoteModule);// 恢復線程ResumeThread(processInfo.hThread);// 釋放CloseHandle(remoteThread);VirtualFreeEx(processInfo.hProcess, remoteMemory, dllPathSize, MEM_DECOMMIT);return (HMODULE)remoteModule; }

消息鉤子注入

還記得第二章的SetWindowsHookEx嗎,只要把dwThreadId設置為其他進程的線程ID或0就可以注入指定進程或所有進程了!(當然,32位DLL只能注入32位程序,64位DLL只能注入64位程序)

當鉤子過程被調用時,系統會檢測鉤子過程所在DLL是否已載入,如果沒有就會載入
所以用SetWindowsHookEx注入DLL的前提是鉤子過程會被調用(比如安裝了鍵盤鉤子,但是沒有在目標進程按一下鍵盤,DLL就不會被注入)
而且用這種方法DLL必須實現并導出鉤子過程(就算用不到)

測試用的DLL(dllmain.cpp不變,在另外一個文件導出鉤子過程):

// MsgHookDll.cpp : 定義 DLL 應用程序的導出函數。 //#include "stdafx.h"extern "C" __declspec(dllexport) // 導出這個函數 LRESULT CALLBACK CallWndProc(int code, WPARAM wParam, LPARAM lParam) {return CallNextHookEx(NULL, code, wParam, lParam); }

為了讓鉤子過程被調用我選擇了調用頻率最高的WH_GETMESSAGE鉤子(當然,沒有消息循環的進程還是注入不了)

EXE代碼(建議下載GitHub上的整個項目看看):

DWORD GetProcessThreadID(DWORD pid) {HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pid);THREADENTRY32 threadentry;threadentry.dwSize = sizeof(threadentry);BOOL hasNext = Thread32First(snapshot, &threadentry);DWORD threadID = 0;do{if (threadentry.th32OwnerProcessID == pid){threadID = threadentry.th32ThreadID;break;}hasNext = Thread32Next(snapshot, &threadentry);} while (hasNext);CloseHandle(snapshot);return threadID; }// 注入DLL,返回鉤子句柄,DLL必須導出CallWndProc鉤子過程,pid = 0則安裝全局鉤子 HHOOK InjectDll(DWORD pid, LPCTSTR dllPath) {// 載入DLLHMODULE module = LoadLibrary(dllPath);if (module == NULL){printf("載入DLL失敗,錯誤代碼:%u\n", GetLastError());return NULL;}// 取鉤子過程地址HOOKPROC proc = (HOOKPROC)GetProcAddress(module, "CallWndProc");if (proc == NULL){printf("取鉤子過程地址失敗,錯誤代碼:%u\n", GetLastError());return NULL;}// 取線程IDDWORD threadID = 0;if (pid != 0){threadID = GetProcessThreadID(pid);if (threadID == 0){printf("取線程ID失敗\n");return NULL;}}// 安裝鉤子HHOOK hook = SetWindowsHookEx(WH_GETMESSAGE, proc, module, threadID);// 釋放FreeLibrary(module);return hook; }int _tmain(int argc, _TCHAR* argv[]) {// 提升權限,不提升貌似也可以,以管理員身份運行就行EnablePrivilege(TRUE);// 取PID//DWORD pid = 0; // 全局鉤子,少玩全局鉤子不然會出問題...HWND hwnd = FindWindow(NULL, _T("任務管理器"));if (hwnd == NULL){printf("尋找窗口失敗,錯誤代碼:%u\n", GetLastError());return 1;}DWORD pid;GetWindowThreadProcessId(hwnd, &pid);// 注入DLL// 要將MsgHookDll.dll放在本程序當前目錄下HHOOK hook = InjectDll(pid, _T("MsgHookDll.dll"));if (hook == NULL)return 2;// 暫停printf("按回車卸載DLL\n");getchar();// 卸載DLLUnhookWindowsHookEx(hook);return 0; }

安裝全局鉤子的結果

DLL劫持

這個是我最喜歡的注入方式,因為只需要DLL,連EXE都不用了,而且隨著程序啟動就自動注入,有些游戲補丁就用這個實現的

原理是系統加載DLL時會優先搜索程序當前目錄下有沒有這個DLL,沒有就再去System32等目錄搜索(除非在注冊表的KnownDLLs里)
所以只要自己編個DLL,實現程序要用的函數(直接調用原DLL對應的函數就可以實現),再把它放到要注入的程序同目錄下,程序啟動時就會自動注入(當然,32位的程序會無視掉64位的DLL)


還是拿東方輝針城開刀,先看看它導入了什么函數

d3d9.dll只導入了一個函數,我們只用實現一個函數,就劫持它好了


DLL代碼(完整源碼):

// dllmain.cpp : 定義 DLL 應用程序的入口點。 #include "stdafx.h" #include "DllHijact.h"HMODULE g_d3d9Module = NULL;// DLL被加載、卸載時調用 BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {TCHAR processPath[MAX_PATH];TCHAR msg[MAX_PATH + 20];switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:GetModuleFileName(GetModuleHandle(NULL), processPath, MAX_PATH);_tcscpy_s(msg, _T("注入了進程 "));_tcscat_s(msg, processPath);MessageBox(NULL, msg, _T(""), MB_OK);// 加載原DLL,獲取真正的Direct3DCreate9地址g_d3d9Module = LoadLibrary(_T("C:\\Windows\\System32\\d3d9.dll"));RealDirect3DCreate9 = (Direct3DCreate9Type)GetProcAddress(g_d3d9Module, "Direct3DCreate9");if (RealDirect3DCreate9 == NULL){MessageBox(NULL, _T("獲取Direct3DCreate9地址失敗"), _T(""), MB_OK);return FALSE;}break;case DLL_PROCESS_DETACH:MessageBox(NULL, _T("DLL卸載中"), _T(""), MB_OK);// 手動卸載原DLLFreeLibrary(g_d3d9Module);break;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:break;}return TRUE; } // DllHijack.cpp : 定義 DLL 應用程序的導出函數。 //#include "stdafx.h" #include "DllHijact.h"Direct3DCreate9Type RealDirect3DCreate9 = NULL;// 把MyDirect3DCreate9導出為Direct3DCreate9,用__declspec(dllexport)的話實際上導出的是_MyDirect3DCreate9@4 #ifndef _WIN64 #pragma comment(linker, "/EXPORT:Direct3DCreate9=_MyDirect3DCreate9@4") #else #pragma comment(linker, "/EXPORT:Direct3DCreate9=MyDirect3DCreate9") #endif extern "C" void* WINAPI MyDirect3DCreate9(UINT SDKVersion) {MessageBox(NULL, _T("調用了Direct3DCreate9"), _T(""), MB_OK);return RealDirect3DCreate9(SDKVersion); }

編譯后把DLL命名為d3d9.dll,放到目標程序同目錄下,運行目標程序時就自動注入


這個也能用于其他用了D3D9的程序,比如東方神靈廟

總結

以上是生活随笔為你收集整理的游戏修改器制作教程七:注入DLL的各种姿势的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩黄色免费视频 | 日本午夜视频在线观看 | 99久久久国产精品无码免费 | 亚洲一区二区高清视频 | 青娱乐福利视频 | 一级bbbbbbbbb毛片 | 正在播放老肥熟妇露脸 | 久久久久国产精品一区二区 | 91av网址 | 91中文在线观看 | 动漫美女揉胸 | 级毛片内射视频 | 欧美高清hd19| 激情综合网五月天 | av电影免费在线播放 | 美女三级黄色片 | 中文字幕+乱码+中文乱码91 | 大尺度做爰啪啪床戏 | 日韩av在线免费播放 | 96人xxxxxxxxx69 | www操| 波多野结衣加勒比 | 1024手机在线看片 | 国产伦精品一区二区三区88av | 91日日夜夜 | 91在线网 | 亚洲色图 欧美 | 中文字幕日韩无 | 午夜偷拍福利 | 国产精品毛片一区二区在线看舒淇 | 人人干人人插 | 免费看污片的网站 | 亚洲色欲色欲www | 久久视频一区二区 | 国产精品无码内射 | 91国偷自产一区二区三区女王 | 露出调教羞耻91九色 | 日韩二区在线 | 日本一区二区免费看 | 国产污视频| 亚洲91网 | 中文字幕第十一页 | 亚洲欧美在线观看视频 | 色射色 | 亚洲欧美日韩国产一区 | 日本免费在线播放 | 欧美成人综合视频 | free性欧美69巨大 | 精品成人免费一区二区在线播放 | 男人天堂2019 | 美色视频 | 国产美女精品人人做人人爽 | 妇女一级片 | 国产欧美一区二区视频 | 在线成人av | 亚洲乱码电影 | 男人天堂手机在线 | 久久久久性色av无码一区二区 | 精品国产av一区二区三区 | 超碰超碰超碰超碰超碰 | 日本午夜一区二区 | 一本到视频 | 成人污网站 | 91在线视频免费看 | 亚洲欧美日韩视频一区 | 三级大片在线观看 | 欧美在线性爱视频 | 亚洲欧美综合一区 | 久久影院午夜 | 精品动漫一区 | 最近的中文字幕在线看视频 | 关之琳三级全黄做爰在线观看 | 免费高清欧美大片在线观看 | 色播99| 日本欧美国产一区二区三区 | 在线aa| 三年中文免费观看大全动漫 | 丰满熟女一区二区三区 | 日本成人福利视频 | 麻豆美女视频 | 在线免费看mv的网站入口 | 精品区一区二区 | 国产中文 | 成人午夜视频免费在线观看 | 一区二区视频网站 | 日韩大片免费观看 | 久久网一区 | 性欧美17一18内谢 | 吞精囗交69激情欧美 | 两性免费视频 | 欧美另类精品xxxx孕妇 | 午夜操操| 亚洲精品乱码久久久久久蜜桃麻豆 | 毛片a片免费看 | 免费手机av | 91草视频| 91免费网站在线观看 | 国内自拍第三页 | 91人妻一区二区三区 |