├── lib ├── GameData.lib ├── MFC_DLL.dll ├── MFC_DLL.exp └── MFC_DLL.lib ├── MFC_DLL ├── MFC_DLL.rc ├── res │ └── MFC_DLL.rc2 ├── MFC_DLL.def ├── pch.cpp ├── targetver.h ├── pch.h ├── MFC_DLL.h ├── CMainDialogWnd.h ├── resource.h ├── framework.h ├── MFC_DLL.cpp ├── MFC_DLL.vcxproj.filters ├── CMainDialogWnd.cpp └── MFC_DLL.vcxproj ├── GameData ├── StructGame.h ├── gloab_var.h ├── StructGame.cpp ├── HookGameMainThread.cpp ├── HookGameMainThread.h ├── BaseGame.h ├── GameData.vcxproj.filters └── GameData.vcxproj ├── InjectDLL ├── MFC_DLL.dll ├── InjectDLL.vcxproj.filters ├── InjectDLL.cpp └── InjectDLL.vcxproj ├── .gitattributes ├── MFC_DLL.sln ├── .gitignore └── README.md /lib/GameData.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/lib/GameData.lib -------------------------------------------------------------------------------- /lib/MFC_DLL.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/lib/MFC_DLL.dll -------------------------------------------------------------------------------- /lib/MFC_DLL.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/lib/MFC_DLL.exp -------------------------------------------------------------------------------- /lib/MFC_DLL.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/lib/MFC_DLL.lib -------------------------------------------------------------------------------- /MFC_DLL/MFC_DLL.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/MFC_DLL/MFC_DLL.rc -------------------------------------------------------------------------------- /GameData/StructGame.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/GameData/StructGame.h -------------------------------------------------------------------------------- /GameData/gloab_var.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/GameData/gloab_var.h -------------------------------------------------------------------------------- /InjectDLL/MFC_DLL.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/InjectDLL/MFC_DLL.dll -------------------------------------------------------------------------------- /GameData/StructGame.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/GameData/StructGame.cpp -------------------------------------------------------------------------------- /MFC_DLL/res/MFC_DLL.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/MFC_DLL/res/MFC_DLL.rc2 -------------------------------------------------------------------------------- /MFC_DLL/MFC_DLL.def: -------------------------------------------------------------------------------- 1 | ; MFC_DLL.def: 声明 DLL 的模块参数。 2 | 3 | LIBRARY 4 | 5 | EXPORTS 6 | ; 此处可以是显式导出 7 | -------------------------------------------------------------------------------- /MFC_DLL/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: 与预编译标头对应的源文件 2 | 3 | #include "pch.h" 4 | 5 | // 当使用预编译的头时,需要使用此源文件,编译才能成功。 6 | -------------------------------------------------------------------------------- /GameData/HookGameMainThread.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/GameData/HookGameMainThread.cpp -------------------------------------------------------------------------------- /GameData/HookGameMainThread.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaJinRong12138/rxjh/HEAD/GameData/HookGameMainThread.h -------------------------------------------------------------------------------- /MFC_DLL/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 4 | 5 | // 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 6 | // 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /MFC_DLL/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: 这是预编译标头文件。 2 | // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 3 | // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 4 | // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 5 | // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // 添加要在此处预编译的标头 11 | #include "framework.h" 12 | #include 13 | 14 | #endif //PCH_H 15 | -------------------------------------------------------------------------------- /MFC_DLL/MFC_DLL.h: -------------------------------------------------------------------------------- 1 | // MFC_DLL.h: MFC_DLL DLL 的主标头文件 2 | // 3 | 4 | #pragma once 5 | 6 | #ifndef __AFXWIN_H__ 7 | #error "在包含此文件之前包含 'pch.h' 以生成 PCH" 8 | #endif 9 | 10 | #include "resource.h" // 主符号 11 | 12 | 13 | // CMFCDLLApp 14 | // 有关此类实现的信息,请参阅 MFC_DLL.cpp 15 | // 16 | 17 | class CMFCDLLApp : public CWinApp 18 | { 19 | public: 20 | CMFCDLLApp(); 21 | 22 | // 重写 23 | public: 24 | virtual BOOL InitInstance(); 25 | 26 | DECLARE_MESSAGE_MAP() 27 | }; 28 | -------------------------------------------------------------------------------- /GameData/BaseGame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 游戏人物的基址 4 | #define BaseRole 0x02C176D8 5 | 6 | // 游戏背包的基址存放地址 7 | #define BaseBackpack 0x02E3C3E4 8 | 9 | // 添加背包物品使用CALL 的地址 ===> 通过背包物品下标进行物品的使用 10 | #define BaseCall_UseGoodsForIndex 0x008384F0 11 | 12 | // 游戏主窗口基址 13 | #define BaseGameWndHandle 0x01195F88 14 | 15 | // 怪物列表基址 16 | #define BaseMonseterList 0x427FBA0 17 | 18 | // 人物动作基址 19 | #define BaseActionList 0x02E3CD58 20 | 21 | // 人物动作使用的CALL 的基址 22 | #define BaseActionCall 0x007139E0 23 | 24 | // 角色对象的基址 25 | #define BaseRoleObj 0x427FBA0 26 | 27 | // 所有对象的数组 [0*4+2E63A28] 28 | #define BaseAllObjList 0x2E64A28 29 | -------------------------------------------------------------------------------- /MFC_DLL/CMainDialogWnd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | // CMainDialogWnd 对话框 5 | 6 | class CMainDialogWnd : public CDialogEx 7 | { 8 | DECLARE_DYNAMIC(CMainDialogWnd) 9 | 10 | public: 11 | CMainDialogWnd(CWnd* pParent = nullptr); // 标准构造函数 12 | virtual ~CMainDialogWnd(); 13 | 14 | // 对话框数据 15 | #ifdef AFX_DESIGN_TIME 16 | enum { IDD = IDD_DIALOG1 }; 17 | #endif 18 | 19 | protected: 20 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 21 | 22 | DECLARE_MESSAGE_MAP() 23 | public: 24 | afx_msg void OnBnClickedButton1(); 25 | afx_msg void OnBnClickedButton2(); 26 | afx_msg void OnBnClickedButton3(); 27 | afx_msg void OnBnClickedButton4(); 28 | afx_msg void OnBnClickedButton5(); 29 | afx_msg void OnBnClickedButton6(); 30 | // 自动打怪的条件 31 | BOOL m_autoKillMon; 32 | afx_msg void OnBnClickedCheck1(); 33 | }; 34 | -------------------------------------------------------------------------------- /MFC_DLL/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ 生成的包含文件。 3 | // 供 MFC_DLL.rc 使用 4 | // 5 | #define IDD_DIALOG1 1000 6 | #define IDC_BUTTON1 1002 7 | #define IDC_BUTTON2 1003 8 | #define IDC_BUTTON3 1004 9 | #define IDC_BUTTON4 1005 10 | #define IDC_BUTTON5 1006 11 | #define IDC_BUTTON6 1007 12 | #define IDC_CHECK1 1009 13 | 14 | // Next default values for new objects 15 | // 16 | #ifdef APSTUDIO_INVOKED 17 | #ifndef APSTUDIO_READONLY_SYMBOLS 18 | #define _APS_NEXT_RESOURCE_VALUE 1002 19 | #define _APS_NEXT_COMMAND_VALUE 32771 20 | #define _APS_NEXT_CONTROL_VALUE 1010 21 | #define _APS_NEXT_SYMED_VALUE 1000 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /InjectDLL/InjectDLL.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | -------------------------------------------------------------------------------- /MFC_DLL/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef VC_EXTRALEAN 4 | #define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 5 | #endif 6 | 7 | #include "targetver.h" 8 | 9 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 10 | 11 | #include // MFC 核心组件和标准组件 12 | #include // MFC 扩展 13 | 14 | #ifndef _AFX_NO_OLE_SUPPORT 15 | #include // MFC OLE 类 16 | #include // MFC OLE 对话框类 17 | #include // MFC 自动化类 18 | #endif // _AFX_NO_OLE_SUPPORT 19 | 20 | #ifndef _AFX_NO_DB_SUPPORT 21 | #include // MFC ODBC 数据库类 22 | #endif // _AFX_NO_DB_SUPPORT 23 | 24 | #ifndef _AFX_NO_DAO_SUPPORT 25 | #include // MFC DAO 数据库类 26 | #endif // _AFX_NO_DAO_SUPPORT 27 | 28 | #ifndef _AFX_NO_OLE_SUPPORT 29 | #include // MFC 对 Internet Explorer 4 公共控件的支持 30 | #endif 31 | #ifndef _AFX_NO_AFXCMN_SUPPORT 32 | #include // MFC 对 Windows 公共控件的支持 33 | #endif // _AFX_NO_AFXCMN_SUPPORT 34 | 35 | 36 | -------------------------------------------------------------------------------- /GameData/GameData.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {d78c02e7-109b-4708-a450-fafd6e8e5f41} 18 | 19 | 20 | 21 | 22 | 源文件 23 | 24 | 25 | 头文件\HookMainThread 26 | 27 | 28 | 29 | 30 | 头文件 31 | 32 | 33 | 头文件 34 | 35 | 36 | 头文件\HookMainThread 37 | 38 | 39 | 头文件 40 | 41 | 42 | -------------------------------------------------------------------------------- /MFC_DLL/MFC_DLL.cpp: -------------------------------------------------------------------------------- 1 | // MFC_DLL.cpp: 定义 DLL 的初始化例程。 2 | // 3 | 4 | #include "pch.h" 5 | #include "framework.h" 6 | #include "MFC_DLL.h" 7 | // 包含含有主窗口的class1的头文件 8 | #include "CMainDialogWnd.h" 9 | 10 | 11 | #ifdef _DEBUG 12 | #define new DEBUG_NEW 13 | #endif 14 | 15 | // 16 | //TODO: 如果此 DLL 相对于 MFC DLL 是动态链接的, 17 | // 则从此 DLL 导出的任何调入 18 | // MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到 19 | // 该函数的最前面。 20 | // 21 | // 例如: 22 | // 23 | // extern "C" BOOL PASCAL EXPORT ExportedFunction() 24 | // { 25 | // AFX_MANAGE_STATE(AfxGetStaticModuleState()); 26 | // // 此处为普通函数体 27 | // } 28 | // 29 | // 此宏先于任何 MFC 调用 30 | // 出现在每个函数中十分重要。 这意味着 31 | // 它必须作为以下项中的第一个语句: 32 | // 出现,甚至先于所有对象变量声明, 33 | // 这是因为它们的构造函数可能生成 MFC 34 | // DLL 调用。 35 | // 36 | // 有关其他详细信息, 37 | // 请参阅 MFC 技术说明 33 和 58。 38 | // 39 | 40 | // CMFCDLLApp 41 | 42 | BEGIN_MESSAGE_MAP(CMFCDLLApp, CWinApp) 43 | END_MESSAGE_MAP() 44 | 45 | 46 | // CMFCDLLApp 构造 47 | 48 | CMFCDLLApp::CMFCDLLApp() 49 | { 50 | // TODO: 在此处添加构造代码, 51 | // 将所有重要的初始化放置在 InitInstance 中 52 | } 53 | 54 | 55 | // 唯一的 CMFCDLLApp 对象 56 | 57 | CMFCDLLApp theApp; 58 | 59 | 60 | // CMFCDLLApp 初始化 61 | 62 | // 定义全局的窗口变量 63 | CMainDialogWnd* PMainDialog; 64 | 65 | DWORD WINAPI ShowDialog(LPARAM lpData) { 66 | // 添加显示窗口的代码 67 | // 创建对象,划分空间 68 | PMainDialog = new CMainDialogWnd; 69 | //DoModal 是以阻塞的方式来运行 70 | PMainDialog->DoModal(); 71 | // 释放空间 72 | delete PMainDialog; 73 | // 在执行完成后,释放掉动态链接库(传递dll 的句柄和执行代码) 74 | FreeLibraryAndExitThread(theApp.m_hInstance, 1); 75 | return TRUE; 76 | } 77 | 78 | 79 | BOOL CMFCDLLApp::InitInstance() 80 | { 81 | CWinApp::InitInstance(); 82 | 83 | // 创建线程函数 84 | ::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ShowDialog, NULL, NULL, NULL); 85 | return TRUE; 86 | } 87 | -------------------------------------------------------------------------------- /MFC_DLL/MFC_DLL.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 源文件 26 | 27 | 28 | 29 | 30 | 源文件 31 | 32 | 33 | 资源文件 34 | 35 | 36 | 37 | 38 | 头文件 39 | 40 | 41 | 头文件 42 | 43 | 44 | 头文件 45 | 46 | 47 | 头文件 48 | 49 | 50 | 头文件 51 | 52 | 53 | 头文件 54 | 55 | 56 | 57 | 58 | 资源文件 59 | 60 | 61 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /InjectDLL/InjectDLL.cpp: -------------------------------------------------------------------------------- 1 | // InjectDLL.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | 5 | #include 6 | #include 7 | #define GAME_WND_CLASS "D3D Window" 8 | #define DLL_NAME "MFC_DLL.dll" 9 | #define GAME_TITLE "YB_OnlineClient" 10 | 11 | using namespace std; 12 | 13 | 14 | BOOL InjectDll(const char* DllPath, HWND GameH) { 15 | 16 | DWORD pid = 0; 17 | HANDLE hProcess = NULL; 18 | LPDWORD lpAddr = NULL; // 获取远程分配成功的地址 19 | DWORD size = NULL; 20 | HANDLE threadHandle = NULL; 21 | 22 | cout << DllPath << endl; 23 | if (GameH != 0) { 24 | //句柄获取成功 25 | // 获取进程PID 26 | 27 | GetWindowThreadProcessId(GameH, &pid); 28 | if (pid != 0) { 29 | // PID 获取成功 30 | // 获取进程句柄 31 | // 开启所以权限打开进程 32 | 33 | hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE ,pid); 34 | if (hProcess != NULL) { 35 | // 打开进程成功 36 | // 分配内存空间,写入动态链接库的全路径名 37 | //D:\\c_work\\MFC_DLL\\Debug\\MFC_DLL.dll 38 | 39 | lpAddr = (LPDWORD)VirtualAllocEx(hProcess, NULL, 256, MEM_COMMIT, PAGE_READWRITE); 40 | if (lpAddr != NULL) { 41 | // 地址分配成功, 写入DLL 的全路径 42 | WriteProcessMemory(hProcess, lpAddr, DllPath, strlen(DllPath) + 1, &size); 43 | 44 | if (size >= strlen(DllPath)) { 45 | threadHandle = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, lpAddr, NULL, NULL); 46 | // 等待注入DLL 的线程执行完再执行下一步(等待的进程句柄, 等到多少毫秒) 47 | 48 | // 清除内存数据 49 | WaitForSingleObject(threadHandle, 0xFFFFFFFF); 50 | // 关闭线程 51 | CloseHandle(threadHandle); 52 | // 释放进程 53 | VirtualFreeEx(hProcess, lpAddr, 256, MEM_DECOMMIT); 54 | // 关闭句柄 55 | CloseHandle(hProcess); 56 | return TRUE; 57 | } 58 | else { 59 | cout << "写入DLL 失败" << endl; 60 | return FALSE; 61 | } 62 | } 63 | else { 64 | cout << "地址分配失败" << endl; 65 | return FALSE; 66 | } 67 | 68 | } 69 | else { 70 | cout << "打开进程失败" << endl; 71 | return FALSE; 72 | } 73 | } 74 | else { 75 | cout << "获取PID 失败" << endl; 76 | return FALSE; 77 | } 78 | 79 | 80 | } 81 | else { 82 | cout << "获取窗口句柄失败" << endl; 83 | return FALSE; 84 | } 85 | 86 | 87 | 88 | } 89 | 90 | int main() 91 | { 92 | 93 | 94 | 95 | // 注入DLL 96 | // 打开游戏进程的句柄 97 | /* 98 | 1、 获取游戏进程的PID 99 | 2、 根据PID 获取进程 100 | 3、 在目标进程分配内存空间,方便写入DLL 全路径 101 | 4、 将DLL 全路径写入到目标进程 102 | 5、 远程注入DLL 103 | 6、 等待目标进程执行完成 104 | 7、 释放进程空间 105 | 8、 关闭线程句柄 106 | */ 107 | 108 | 109 | cout << "开始注入DLL" << endl; 110 | 111 | DWORD dwPID; 112 | // 获取游戏窗口句柄 113 | HWND GameH = FindWindow((LPCTSTR)GAME_WND_CLASS, GAME_TITLE); 114 | 115 | char path[256] = "D:\\c_work\\MFC_DLL\\lib"; 116 | 117 | // 拼接字符串(添加要查找的DLL 文件) 118 | strcat_s(path, "\\"); 119 | strcat_s(path, DLL_NAME); 120 | 121 | if (InjectDll(path, GameH)) { 122 | cout << "注入DLL 成功" << endl; 123 | } 124 | else { 125 | cout << "注入DLL 失败" << endl; 126 | } 127 | 128 | //system("pause"); 129 | 130 | } 131 | 132 | -------------------------------------------------------------------------------- /MFC_DLL.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28922.388 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MFC_DLL", "MFC_DLL\MFC_DLL.vcxproj", "{9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectDLL", "InjectDLL\InjectDLL.vcxproj", "{77A2B029-61A5-4FC5-97B5-55D3B58944B5}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameData", "GameData\GameData.vcxproj", "{8FD39511-E20D-429E-B6D3-DF7CBDEA519B}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Debug|x64.ActiveCfg = Debug|x64 21 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Debug|x64.Build.0 = Debug|x64 22 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Debug|x86.ActiveCfg = Debug|Win32 23 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Debug|x86.Build.0 = Debug|Win32 24 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Release|x64.ActiveCfg = Release|x64 25 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Release|x64.Build.0 = Release|x64 26 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Release|x86.ActiveCfg = Release|Win32 27 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA}.Release|x86.Build.0 = Release|Win32 28 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Debug|x64.ActiveCfg = Debug|x64 29 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Debug|x64.Build.0 = Debug|x64 30 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Debug|x86.ActiveCfg = Debug|Win32 31 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Debug|x86.Build.0 = Debug|Win32 32 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Release|x64.ActiveCfg = Release|x64 33 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Release|x64.Build.0 = Release|x64 34 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Release|x86.ActiveCfg = Release|Win32 35 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5}.Release|x86.Build.0 = Release|Win32 36 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Debug|x64.ActiveCfg = Debug|x64 37 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Debug|x64.Build.0 = Debug|x64 38 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Debug|x86.ActiveCfg = Debug|Win32 39 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Debug|x86.Build.0 = Debug|Win32 40 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Release|x64.ActiveCfg = Release|x64 41 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Release|x64.Build.0 = Release|x64 42 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Release|x86.ActiveCfg = Release|Win32 43 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B}.Release|x86.Build.0 = Release|Win32 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {B0626E3B-0ADF-4FAF-AC25-19427AF0771C} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /MFC_DLL/CMainDialogWnd.cpp: -------------------------------------------------------------------------------- 1 | // CMainDialogWnd.cpp: 实现文件 2 | // 3 | 4 | #include "pch.h" 5 | #include "MFC_DLL.h" 6 | #include "CMainDialogWnd.h" 7 | #include "afxdialogex.h" 8 | #include "BaseGame.h" 9 | #include "StructGame.h" 10 | #include "HookGameMainThread.h" 11 | 12 | 13 | // CMainDialogWnd 对话框 14 | 15 | IMPLEMENT_DYNAMIC(CMainDialogWnd, CDialogEx) 16 | 17 | CMainDialogWnd::CMainDialogWnd(CWnd* pParent /*=nullptr*/) 18 | : CDialogEx(IDD_DIALOG1, pParent) 19 | , m_autoKillMon(FALSE) 20 | { 21 | 22 | } 23 | 24 | CMainDialogWnd::~CMainDialogWnd() 25 | { 26 | } 27 | 28 | void CMainDialogWnd::DoDataExchange(CDataExchange* pDX) 29 | { 30 | CDialogEx::DoDataExchange(pDX); 31 | DDX_Check(pDX, IDC_CHECK1, m_autoKillMon); 32 | } 33 | 34 | 35 | BEGIN_MESSAGE_MAP(CMainDialogWnd, CDialogEx) 36 | ON_BN_CLICKED(IDC_BUTTON1, &CMainDialogWnd::OnBnClickedButton1) 37 | ON_BN_CLICKED(IDC_BUTTON2, &CMainDialogWnd::OnBnClickedButton2) 38 | ON_BN_CLICKED(IDC_BUTTON3, &CMainDialogWnd::OnBnClickedButton3) 39 | ON_BN_CLICKED(IDC_BUTTON4, &CMainDialogWnd::OnBnClickedButton4) 40 | ON_BN_CLICKED(IDC_BUTTON5, &CMainDialogWnd::OnBnClickedButton5) 41 | ON_BN_CLICKED(IDC_BUTTON6, &CMainDialogWnd::OnBnClickedButton6) 42 | ON_BN_CLICKED(IDC_CHECK1, &CMainDialogWnd::OnBnClickedCheck1) 43 | END_MESSAGE_MAP() 44 | 45 | 46 | // CMainDialogWnd 消息处理程序 47 | 48 | 49 | void CMainDialogWnd::OnBnClickedButton1() 50 | { 51 | TROLE_PROPERTY role; 52 | TROLE_PROPERTY* r = role.GetData(); 53 | TGOODSLIST_PROPERTY goods; 54 | 55 | TRACE("GameDebug:我的调试信息\r\n"); 56 | TRACE("GameDebug: 人物名=%s\r\n", r->GetRoleName()); 57 | TRACE("GameDebug: 人物等级=%d\r\n", r->nbClassValue); 58 | TRACE("GameDebug: 人物名声=%s\r\n", r->szReputation); 59 | TRACE("GameDebug: 人物血量HP=%d//%d\r\n", r->ndRoleHP, r->ndRoleMaxHP); 60 | TRACE("GameDebug: 人物内功MP=%d//%d\r\n", r->ndRoleMP, r->ndRoleMaxMP); 61 | TRACE("GameDebug: 人物愤怒值=%d\r\n", r->ndRoleAnger); 62 | TRACE("GameDebug: 人物金币=%d\r\n", r->nqMoney); 63 | TGOODSLIST_PROPERTY* g = goods.getData(); 64 | try { 65 | for (int i = 0; i < nGoodsNum; i++) { 66 | if (g->mtGoodsList[i].ndGoodsNum == 0) { 67 | continue; 68 | } 69 | TRACE("GameDebug: 人物第%d格数据:%s\r%s\r%d\r\n", i, 70 | g->mtGoodsList[i].szGoodsName, 71 | g->mtGoodsList[i].szGoodsIntro, 72 | g->mtGoodsList[i].ndGoodsNum 73 | ); 74 | } 75 | } 76 | catch (...) { 77 | MessageBox(TEXT("读取背包数据异常(Dialog)"), TEXT("Error"), MB_OK); 78 | } 79 | 80 | if (g->UseGoodsForName("回城符(泫勃派)")) { 81 | TRACE("GameDebug: 使用 回城符(泫勃派) 成功"); 82 | } 83 | 84 | 85 | // 进行数据修改 86 | } 87 | 88 | 89 | // 连接主线程 90 | void CMainDialogWnd::OnBnClickedButton2() 91 | { 92 | // TODO: 在此添加控件通知处理程序代码 93 | HookMainThread(); 94 | } 95 | 96 | 97 | void CMainDialogWnd::OnBnClickedButton3() 98 | { 99 | // TODO: 在此添加控件通知处理程序代码 100 | UnHookMainThread(); 101 | } 102 | 103 | 104 | void CMainDialogWnd::OnBnClickedButton4() 105 | { 106 | // TODO: 在此添加控件通知处理程序代码 107 | msgUseGoodsForName("金创药(小)"); 108 | } 109 | 110 | 111 | void CMainDialogWnd::OnBnClickedButton5() 112 | { 113 | // TODO: 在此添加控件通知处理程序代码 114 | msgTest(NULL); 115 | } 116 | 117 | 118 | void CMainDialogWnd::OnBnClickedButton6() 119 | { 120 | // TODO: 在此添加控件通知处理程序代码 121 | testActionMsg(NULL); 122 | } 123 | 124 | 125 | VOID CALLBACK ExeAction( 126 | HWND hwnd, 127 | UINT uMsg, 128 | UINT_PTR idEvent, 129 | DWORD dwTime 130 | ) { 131 | // 做对上一个怪物的死亡状态的判断 132 | 133 | testActionMsg(NULL); 134 | } 135 | 136 | const int PLAYID = 111; 137 | void CMainDialogWnd::OnBnClickedCheck1() 138 | { 139 | // TODO: 在此添加控件通知处理程序代码 140 | UpdateData(TRUE); 141 | if (m_autoKillMon) { 142 | SetTimer(PLAYID, 1000, &ExeAction); 143 | } 144 | else { 145 | KillTimer(PLAYID); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /InjectDLL/InjectDLL.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {77A2B029-61A5-4FC5-97B5-55D3B58944B5} 24 | Win32Proj 25 | InjectDLL 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | MultiByte 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | ..\\bin\ 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | ..\\lib\ 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | true 109 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | true 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | Level3 122 | MaxSpeed 123 | true 124 | true 125 | true 126 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | 148 | 149 | Console 150 | true 151 | true 152 | true 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /GameData/GameData.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | NotUsing 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 16.0 35 | {8FD39511-E20D-429E-B6D3-DF7CBDEA519B} 36 | Win32Proj 37 | GameData 38 | 10.0 39 | 40 | 41 | 42 | StaticLibrary 43 | true 44 | v142 45 | MultiByte 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | DynamicLibrary 56 | true 57 | v142 58 | Unicode 59 | 60 | 61 | DynamicLibrary 62 | false 63 | v142 64 | true 65 | Unicode 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | true 87 | ..\\lib\ 88 | 89 | 90 | true 91 | 92 | 93 | false 94 | 95 | 96 | false 97 | 98 | 99 | 100 | NotUsing 101 | Level3 102 | Disabled 103 | true 104 | WIN32;_DEBUG;GAMEDATA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 105 | true 106 | pch.h 107 | MultiThreadedDebug 108 | 109 | 110 | Windows 111 | true 112 | false 113 | 114 | 115 | 116 | 117 | Use 118 | Level3 119 | Disabled 120 | true 121 | _DEBUG;GAMEDATA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 122 | true 123 | pch.h 124 | 125 | 126 | Windows 127 | true 128 | false 129 | 130 | 131 | 132 | 133 | Use 134 | Level3 135 | MaxSpeed 136 | true 137 | true 138 | true 139 | WIN32;NDEBUG;GAMEDATA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 140 | true 141 | pch.h 142 | 143 | 144 | Windows 145 | true 146 | true 147 | true 148 | false 149 | 150 | 151 | 152 | 153 | Use 154 | Level3 155 | MaxSpeed 156 | true 157 | true 158 | true 159 | NDEBUG;GAMEDATA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 160 | true 161 | pch.h 162 | 163 | 164 | Windows 165 | true 166 | true 167 | true 168 | false 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /MFC_DLL/MFC_DLL.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {9E6BC9E0-5420-4BAC-A296-2C8FB63F8AEA} 24 | MFCDLLProj 25 | MFCDLL 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | Static 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v142 40 | true 41 | Unicode 42 | Static 43 | 44 | 45 | DynamicLibrary 46 | true 47 | v142 48 | Unicode 49 | Static 50 | 51 | 52 | DynamicLibrary 53 | false 54 | v142 55 | true 56 | Unicode 57 | Static 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | true 79 | ..\\lib\ 80 | 81 | 82 | true 83 | 84 | 85 | false 86 | 87 | 88 | false 89 | 90 | 91 | 92 | Use 93 | Level3 94 | Disabled 95 | true 96 | WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) 97 | pch.h 98 | ..\\GameData\ 99 | 100 | 101 | Windows 102 | .\MFC_DLL.def 103 | GameData.lib 104 | ..\\lib\ 105 | 106 | 107 | false 108 | _DEBUG;%(PreprocessorDefinitions) 109 | 110 | 111 | 0x0804 112 | _DEBUG;%(PreprocessorDefinitions) 113 | $(IntDir);%(AdditionalIncludeDirectories) 114 | 115 | 116 | 117 | 118 | Use 119 | Level3 120 | Disabled 121 | true 122 | _WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) 123 | pch.h 124 | 125 | 126 | Windows 127 | .\MFC_DLL.def 128 | 129 | 130 | false 131 | _DEBUG;%(PreprocessorDefinitions) 132 | 133 | 134 | 0x0804 135 | _DEBUG;%(PreprocessorDefinitions) 136 | $(IntDir);%(AdditionalIncludeDirectories) 137 | 138 | 139 | 140 | 141 | Use 142 | Level3 143 | MaxSpeed 144 | true 145 | true 146 | true 147 | WIN32;_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) 148 | pch.h 149 | 150 | 151 | Windows 152 | true 153 | true 154 | .\MFC_DLL.def 155 | 156 | 157 | false 158 | NDEBUG;%(PreprocessorDefinitions) 159 | 160 | 161 | 0x0804 162 | NDEBUG;%(PreprocessorDefinitions) 163 | $(IntDir);%(AdditionalIncludeDirectories) 164 | 165 | 166 | 167 | 168 | Use 169 | Level3 170 | MaxSpeed 171 | true 172 | true 173 | true 174 | _WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) 175 | pch.h 176 | 177 | 178 | Windows 179 | true 180 | true 181 | .\MFC_DLL.def 182 | 183 | 184 | false 185 | NDEBUG;%(PreprocessorDefinitions) 186 | 187 | 188 | 0x0804 189 | NDEBUG;%(PreprocessorDefinitions) 190 | $(IntDir);%(AdditionalIncludeDirectories) 191 | 192 | 193 | 194 | 195 | 196 | 197 | Create 198 | Create 199 | Create 200 | Create 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rxjh 2 | 热血江湖外挂 3 | # 外挂编写(一) 4 | 5 | ## 学习案例:热血江湖 6 | 7 | ## 使用环境:[Visual Studio 2019](https://visualstudio.microsoft.com/zh-hans/vs/) 8 | 9 | # 学习使用的工具:[逆向工具集](https://github.com/JiaJinRong12138/reverseTools) 10 | 11 | ## 注:更新日志: 12 | 13 | - 1.0:最新版人物信息基址:0x02C166D8;最新版背包存放基址:0x02E3B3E4 14 | - 2.0:最新版物品使用call 为0x00838480 15 | - 3.0: 16 | - 人物基址:0x02C176D8‬; 17 | - 背包存放基址:0x02E3C3E4; 18 | - 游戏主窗口基址:0x01195F88; 19 | - 使用物品的CALL:0x008384F0; 20 | - 人物动作基址:0x02E3CD58; 21 | - 动作使用的CALL:0x007139E0; 22 | - 所有对象数组:0x2E64A28; 23 | - 怪物基址:0x427FBA0 24 | - 角色对象基址:0x427FBA0 25 | 26 | ## 人物属性数据分析 27 | 28 | ### 注: 29 | 30 | - 一般游戏开发的时候,相关的数据都是放到一个结构或者是一个类中,那么这些数据的内存地址相距的比较近; 31 | - 一般内存地址使用CE工具逆向出来后表示为Client.exe+278A75C,表示软件地址加上偏移量为其基址 32 | 33 | ### HP值和MP值 34 | 35 | - 生命值PH: Client.exe+278A75C = 02B8A758 36 | - 内功值MH: Client.exe+278A75C = 02B8A75C 37 | 38 | ### 金币值 39 | 40 | - 进行商品的买卖实现金币值的变动 41 | - 基址:Client.exe+278A7BC = 02B8A7BC 42 | 43 | ### 其他人物属性分析 44 | 45 | - OD软件的使用 46 | - 使用dd 02B8A758 查找到人物属性基址块 47 | - 人物属性值以及对应的内存地址 48 | - 基址 02B8A6D8 49 | - +0:人物名字 50 | - +80:生命值(红/HP) 51 | - +84:内功值(蓝/MP) 52 | - +88:愤怒值 53 | - +8C:最大生命值 54 | - +90:最大内功值 55 | - +94:最大值愤怒值 56 | - +98:当前经验值 57 | - +A0:升级到下一级要的经验值 58 | - 势力 59 | - +36:名声 60 | - +34:一字节空间表示等级 61 | - +35:一字节空间表示 几转 62 | - +AC:历练 63 | - 制造 64 | - 熟练度 65 | - 灵兽持有 66 | - 精力 67 | - +C8:攻击 68 | - 武器命中 69 | - +CC:防御 70 | - 武器防御 71 | - +D0:命中 72 | - 对人战斗 73 | - +D4:回避 74 | - 对怪攻击 75 | - 武功回避 76 | - 对怪防御 77 | - +B0:心 78 | - +B4:气 79 | - +B8:体 80 | - +BC:魂 81 | - +E4:金币值 82 | - 气功值分析 83 | - 气功点数:基址 + F0 = 02b8a7c8 84 | - 第num个气功的点数:(一个字节)02B8A6D8+0f0+4*num 85 | - 可能是第num个气功的ID(没有就为0):02B8A6D8+0f0+4*num+2 86 | 87 | ## 通过注入游戏进程读取游戏内数据 88 | 89 | - 注入DLL 90 | 91 | - 创建MFC DLL 92 | 93 | ![创建MFC_DLL](https://i.loli.net/2019/07/11/5d26ffb5af90c21949.png) 94 | 95 | ![](https://i.loli.net/2019/07/11/5d270041a363831087.png) 96 | 97 | ![](https://i.loli.net/2019/07/11/5d27010a5c79033592.png) 98 | 99 | - 在添加窗口后,需要进行配置,才能在动态链接库注入后显示窗口 100 | 101 | - 为窗口添加Class 102 | 103 | ![](https://i.loli.net/2019/07/11/5d27076e05b7953340.png) 104 | 105 | - 修改MFC_DLL.cpp的代码 106 | 107 | - ```C++ 108 | // MFC_DLL.cpp: 定义 DLL 的初始化例程。 109 | // 110 | 111 | #include "pch.h" 112 | #include "framework.h" 113 | #include "MFC_DLL.h" 114 | 115 | // 包含含有主窗口的class1的头文件 116 | #include "CMainDialogWnd.h" 117 | 118 | 119 | #ifdef _DEBUG 120 | #define new DEBUG_NEW 121 | #endif 122 | 123 | 124 | BEGIN_MESSAGE_MAP(CMFCDLLApp, CWinApp) 125 | END_MESSAGE_MAP() 126 | 127 | 128 | // CMFCDLLApp 构造 129 | 130 | CMFCDLLApp::CMFCDLLApp() 131 | { 132 | // TODO: 在此处添加构造代码, 133 | // 将所有重要的初始化放置在 InitInstance 中 134 | } 135 | 136 | 137 | // 唯一的 CMFCDLLApp 对象 138 | 139 | CMFCDLLApp theApp; 140 | 141 | 142 | // CMFCDLLApp 初始化 143 | 144 | // 定义全局的窗口变量 145 | CMainDialogWnd* PMainDialog; 146 | 147 | BOOL CMFCDLLApp::InitInstance() 148 | { 149 | CWinApp::InitInstance(); 150 | 151 | // 添加显示窗口的代码 152 | // 创建对象,划分空间 153 | PMainDialog = new CMainDialogWnd; 154 | //DoModal 是以阻塞的方式来运行 155 | PMainDialog->DoModal(); 156 | // 释放空间 157 | delete PMainDialog; 158 | return TRUE; 159 | } 160 | 161 | ``` 162 | 163 | - 使用[注入工具]()讲编译生成的DLL 注入到游戏进程中 164 | 165 | ![](https://i.loli.net/2019/07/11/5d2707df083dc26429.png) 166 | 167 | - 注:DoModal() 函数是以阻塞的方式去执行的,所以会造成线程阻塞 168 | 169 | - 解决方式:将DoModal() 放到新的线程去执行 170 | 171 | ![](https://i.loli.net/2019/07/11/5d270c58f2d0b26607.png) 172 | 173 | - 实现窗口关闭后自动释放DLL 174 | 175 | ![](https://i.loli.net/2019/07/11/5d2710855d47840496.png) 176 | 177 | #### 使用代码实现动态连接库的注入 178 | 179 | - 使用到的windows API 180 | - HWND FindWindow(lpClassName, lpWindowNAme) 181 | - 通过类名指针或窗口名指针获取窗口句柄 182 | - DWORD GetWindowThreadProcessId(hwnd(窗口句柄), lpdwProcessId) 183 | - 获取窗口线程句柄的ID(lpdwProcessId) 184 | - HANDLE WINAPI OpenProcess(dwDesiredAccess(访问权限), bInheritHandle, dwProcessId) 185 | - 开启并创建一个本地进程 186 | - LPVOID WINAPI VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect) 187 | - 分配内存空间 188 | - BOOL WINAPI WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten) 189 | - 向内存中写入数据 190 | - HANDLE WINAPI CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId) 191 | - 为进程创建一个线程 192 | - DWORD WINAPI WaitForSingleObject(hHandle, dwMilliseconds) 193 | - 等待单个对象执行后再进行操作 194 | - BOOL WINAPI CloseHandle(hObject) 195 | - 关闭句柄 196 | - BOOL WINAPI VirtualFreeEx(hProcess, lpAddress, dwSize, dwFreeType) 197 | - 释放内存空间 198 | - BOOL WINAPI CloseHandle(hObject) 199 | - 关闭句柄 200 | 201 | 202 | 203 | ``` 204 | #### 代码 205 | ``` 206 | 207 | ```c++ 208 | #include 209 | #include 210 | #define GameClassName "D3D Window" 211 | #define DllPath "D:\\c_work\\MFC_DLL\\Debug\\MFC_DLL.dll" 212 | 213 | using namespace std; 214 | 215 | 216 | void InjectDll() { 217 | 218 | DWORD pid = 0; 219 | HANDLE hProcess = NULL; 220 | LPDWORD lpAddr = NULL; // 获取远程分配成功的地址 221 | DWORD size = NULL; 222 | HANDLE threadHandle = NULL; 223 | 224 | // 获取游戏窗口句柄 225 | HWND GameH = FindWindow((LPCTSTR)GameClassName, NULL); 226 | if (GameH != 0) { 227 | //句柄获取成功 228 | // 获取进程PID 229 | 230 | GetWindowThreadProcessId(GameH, &pid); 231 | if (pid != 0) { 232 | // PID 获取成功 233 | // 获取进程句柄 234 | // 开启所以权限打开进程 235 | 236 | hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE ,pid); 237 | if (hProcess != NULL) { 238 | // 打开进程成功 239 | // 分配内存空间,写入动态链接库的全路径名 240 | //D:\\c_work\\MFC_DLL\\Debug\\MFC_DLL.dll 241 | 242 | lpAddr = (LPDWORD)VirtualAllocEx(hProcess, NULL, 256, MEM_COMMIT, PAGE_READWRITE); 243 | if (lpAddr != NULL) { 244 | // 地址分配成功, 写入DLL 的全路径 245 | 246 | WriteProcessMemory(hProcess, lpAddr, DllPath, strlen(DllPath) + 1, &size); 247 | if (size >= strlen(DllPath)) { 248 | threadHandle = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, lpAddr, NULL, NULL); 249 | // 等待注入DLL 的线程执行完再执行下一步(等待的进程句柄, 等到多少毫秒) 250 | WaitForSingleObject(threadHandle, 0xFFFFFFFF); 251 | // 关闭线程 252 | CloseHandle(threadHandle); 253 | // 释放进程 254 | VirtualFreeEx(hProcess, lpAddr, 256, MEM_DECOMMIT); 255 | // 关闭句柄 256 | CloseHandle(hProcess); 257 | 258 | 259 | // 清除内存数据 260 | 261 | } 262 | else { 263 | cout << "写入DLL 失败" << endl; 264 | } 265 | } 266 | else { 267 | cout << "地址分配失败" << endl; 268 | } 269 | 270 | } 271 | else { 272 | cout << "打开进程失败" << endl; 273 | } 274 | } 275 | else { 276 | cout << "获取PID 失败" << endl; 277 | } 278 | } 279 | else { 280 | cout << "获取窗口句柄失败" << endl; 281 | } 282 | 283 | } 284 | 285 | int main() 286 | { 287 | 288 | // 添加注入DLL 代码 289 | cout << "开始注入DLL" << endl; 290 | InjectDll(); 291 | cout << "注入DLL结束" << endl; 292 | 293 | } 294 | 295 | 296 | ``` 297 | 298 | - 步骤 299 | 1. 获取窗口对应的进程的PID 300 | 2. 根据PID 获取进程 301 | 3. 获取游戏进程的PID 302 | 4. 根据PID 获取进程 303 | 5. 在目标进程分配内存空间,方便写入DLL 全路径 304 | 6. 将DLL 全路径写入到目标进程 305 | 7. 远程注入DLL 306 | 8. 等待目标进程执行完成 307 | 9. 释放进程空间 308 | 10. 关闭线程句柄 309 | 310 | ### 整合游戏内数据 311 | 312 | - 整数 313 | - QWORD 类型变量 nq前缀 //8字节 无符号整数 不能表示负数 314 | - DWORD 类型变量 nd前缀 //4字节 无符号整数 不能表示负数 315 | - WORD 类型变量 nw前缀 //2字节 无符号整数 不能表示负数 316 | - BYTE 类型变量 nb前缀 //1字节 无符号整数 不能表示负数 317 | - int 带符号类型 ni前缀 //4字节 带符号整数 可表示正负数 318 | - __int64 带符号整型 ni64_ //8字节 带符号整数 不能表示负数 319 | - UINT 类型变量 ui前缀 // 无符号整数 一般是4字节 320 | - //浮点数 321 | - float 单精度浮点数 fl前缀 322 | - double 双精度浮点数 fd前缀 323 | - 字符串 324 | - char*和char [] sz前缀 //PCHAR szp 325 | - CString str前缀 326 | - 结构名 T开头全大写 327 | - 类名 C开头单词首字大写 328 | 329 | #### 整合游戏数据步骤 330 | 331 | 1. 新建解决方案GameData 332 | 333 | 2. 创建头文件BaseGame.h和 StructGame.h 334 | 335 | ------ 336 | 337 | - BaseGame.h 338 | 339 | ```c++ 340 | #pragma once 341 | 342 | // 游戏人物的基址 343 | #define BaseRole 0x02B8A6D8 344 | 345 | ``` 346 | 347 | ------ 348 | 349 | - StructGame.h 350 | 351 | ```c++ 352 | #pragma once 353 | #include 354 | typedef unsigned __int64 QWORD; 355 | // 游戏结构以及偏移量的管理 356 | 357 | typedef struct TROLE_PROPERTY { 358 | 359 | // +0:人物名字 360 | char* szRoleName; 361 | // + 80:生命值(红 / HP) 362 | DWORD ndRoleHP; 363 | // + 84:内功值(蓝 / MP) 364 | DWORD ndRoleMP; 365 | // + 88:愤怒值 366 | DWORD ndRoleAnger; 367 | // + 8C:最大生命值 368 | DWORD ndRoleMaxHP; 369 | // + 90:最大内功值 370 | DWORD ndRoleMaxMP; 371 | // + 94:最大值愤怒值 372 | QWORD nqRoleMaxAnger; 373 | // + 98:当前经验值 374 | QWORD nqRoleExprienceNow; 375 | // + A0:升级到下一级要的经验值 376 | DWORD ndRoleExperienceNext; 377 | // + 36:名声 378 | char* szReputation; 379 | // + 34:一字节空间表示等级 380 | BYTE nbClassValue; 381 | // + 35:一字节空间表示 几转 382 | BYTE nbJZ; 383 | // + AC:历练 384 | DWORD ndExprience; 385 | // + C8:攻击 386 | DWORD ndAttack; 387 | // + CC:防御 388 | DWORD ndDefense; 389 | // + D4:回避 390 | DWORD ndAvoid; 391 | // + B0:心 392 | DWORD ndHeart; 393 | // + B4:气 394 | DWORD ndGas; 395 | // + B8:体 396 | DWORD ndBody; 397 | // + BC:魂 398 | DWORD ndSoul; 399 | // + E4:金币值 400 | QWORD nqMoney; 401 | // 气功 402 | DWORD ndQg[32]; 403 | 404 | TROLE_PROPERTY* GetData(); 405 | 406 | char* GetRoleName(); 407 | 408 | }_TROLE_PROPERTY; 409 | 410 | ``` 411 | 412 | 413 | 414 | 3. 创建源文件StructGame.cpp 415 | 416 | ------ 417 | 418 | - StructGame.cpp 419 | 420 | ```c++ 421 | #include "StructGame.h" 422 | #include "BaseGame.h" 423 | TROLE_PROPERTY* TROLE_PROPERTY::GetData() 424 | { 425 | 426 | // 添加异常处理 427 | try { 428 | // +0:人物名字 429 | szRoleName = (char*)BaseRole; 430 | // + 80:生命值(红 / HP) 431 | ndRoleHP = (DWORD)(BaseRole + 0x80); 432 | // + 84:内功值(蓝 / MP) 433 | ndRoleMP = (DWORD)(BaseRole + 0x84); 434 | // + 88:愤怒值 435 | ndRoleAnger = (DWORD)(BaseRole + 0x88); 436 | // + 8C:最大生命值 437 | ndRoleMaxHP = (DWORD)(BaseRole + 0x8c); 438 | // + 90:最大内功值 439 | ndRoleMaxMP = (DWORD)(BaseRole + 0x90); 440 | // + 94:最大值愤怒值 441 | nqRoleMaxAnger = (QWORD)(BaseRole + 0x94); 442 | // + 98:当前经验值 443 | nqRoleExprienceNow = (QWORD)(BaseRole + 0x98); 444 | // + A0:升级到下一级要的经验值 445 | ndRoleExperienceNext = (DWORD)(BaseRole + 0xA0); 446 | // + 36:名声 447 | szReputation = (char*)(BaseRole + 0x36); 448 | // + 34:一字节空间表示等级 449 | nbClassValue = *(BYTE*)(BaseRole + 0x34); 450 | // + 35:一字节空间表示 几转 451 | nbJZ = *(BYTE*)(BaseRole + 0x35); 452 | // + AC:历练 453 | ndExprience = (DWORD)(BaseRole + 0xac); 454 | // + C8:攻击 455 | ndAttack = (DWORD)(BaseRole + 0xc8); 456 | // + CC:防御 457 | ndDefense = (DWORD)(BaseRole + 0xcc); 458 | // + D4:回避 459 | ndAvoid = (DWORD)(BaseRole + 0xd4); 460 | // + B0:心 461 | ndHeart = (DWORD)(BaseRole + 0xb0); 462 | // + B4:气 463 | ndGas = (DWORD)(BaseRole + 0xb4); 464 | // + B8:体 465 | ndBody = (DWORD)(BaseRole + 0x8c); 466 | // + BC:魂 467 | ndSoul = (DWORD)(BaseRole + 0xbc); 468 | // + E4:金币值 469 | nqMoney = (QWORD)(BaseRole + 0xe4); 470 | 471 | for (int i = 0; i < 32; i++) { 472 | ndQg[i] = *(BYTE*)(BaseRole + 0xf0 + 4 * (i + 1)); 473 | } 474 | } 475 | catch (...) { 476 | // 处理所有的异常 477 | OutputDebugStringA("读取人物数据异常\r\n"); 478 | } 479 | 480 | 481 | 482 | return this; 483 | } 484 | 485 | // 获取角色的名称、 486 | char* TROLE_PROPERTY::GetRoleName() { 487 | return GetData()->szRoleName; 488 | } 489 | 490 | ``` 491 | 492 | 493 | 494 | ### VS2019 导入静态链接库(lib)、配置输出路径的方式 495 | 496 | - 配置链接库路径 497 | 498 | - 配置 附加包含目录 499 | 500 | ![](https://i.loli.net/2019/07/12/5d282a710f95f93418.png) 501 | 502 | - 配置 添加库目录 503 | 504 | ![](https://i.loli.net/2019/07/12/5d282aa5ca58875840.png) 505 | 506 | - 配置编译输出路径 507 | 508 | - 修改输出目录 509 | 510 | ![](https://i.loli.net/2019/07/12/5d282b31d492535906.png) 511 | 512 | 513 | 514 | ### 游戏中的物品使用 515 | 516 | - 在游戏中,对应的物品都会有一个结构/类,包含了物品的一些信息 517 | - 使用物品实际上调用了应该CALL 518 | 519 | ##### 以金疮药为例 520 | 521 | - 寻CALL 的过程 522 | 523 | - 使用CE工具找到对象地址指针 524 | 525 | - 去查看访问改指针的地址 526 | 527 | - 使用OD 工具对这些地址进行动态调试 528 | 529 | - 远程注入代码(使用金疮药) 530 | 531 | - ```汇编 532 | push 1 533 | push 1 534 | push 0 535 | mov ecx, 21DF06D0 536 | call 00838470 537 | ``` 538 | 539 | ##### 背包数据的分析 540 | 541 | - 背包在游戏中一般会写成应该结构体/类来存放物品对象 542 | - 物品对象在背包中使用数组的形式存在 543 | - 汇编中数组的访问方式一般是 **数组基址 + 4 * i**(' i '为数组下标) 544 | - 查找背包数组基址: 545 | - 找到背包的物品格 546 | - 反复讲里面的物品拿出/放入 547 | - 使用CE工具进程分析 548 | - **结果** 549 | - 存放背包基址的内存空间:0x02DAF3E4 550 | - 第num 个格子的数据获取 551 | - ***背包基址+num\*4+0x43C** 552 | - 注:0x43 是偏移量 553 | - 物品对象指针 + 0x64 = 物品名字 554 | - 物品对象指针 + 0xf9 = 对物品的描述 555 | - 物品对象指针 + 0xC4C = 物品剩余数量 556 | 557 | 558 | 559 | ### 封装背包数据 560 | 561 | #### 封装背包结构体 562 | 563 | ```c++ 564 | // 物品结构 565 | typedef struct TBACKPACK_GOODS { 566 | 567 | // *物品对象指针 + 0x64 = 物品名字 568 | char* szGoodsName; 569 | // * 物品对象指针 + 0xf9 = 对物品的描述 570 | char* szGoodsIntro; 571 | // * 物品对象指针 + 0xC4C = 物品剩余数量 572 | DWORD ndGoodsNum; 573 | 574 | } _TBACKPACK_GOODS; 575 | 576 | // 背包结构 577 | typedef struct TGOODSLIST_PROPERTY { 578 | _TBACKPACK_GOODS mtGoodsList[nGoodsNum]; 579 | 580 | // 对数据的初始化 581 | TGOODSLIST_PROPERTY* getData(); 582 | }_TGOODSLIST_PROPERTY; 583 | ``` 584 | 585 | #### 实现初始化方法(getDate()) 586 | 587 | ```c++ 588 | TGOODSLIST_PROPERTY* TGOODSLIST_PROPERTY::getData() 589 | { 590 | 591 | // 通过获取背包基址对每样物品进行分析 592 | 593 | // *物品对象指针 + 0x64 = 物品名字 594 | #define GOODSNAME 0x64 595 | // * 物品对象指针 + 0xf9 = 对物品的描述 596 | #define GOODSINTRO 0xf9 597 | // * 物品对象指针 + 0xC4C = 物品剩余数量 598 | #define GOODSNUM 0xc4c 599 | 600 | // 背包公式: ndBaseAddr + num*4 + 0x43c 601 | try { 602 | // 读取背包基址 603 | DWORD ndBase = *(DWORD*)(BaseBackpack); 604 | // 第一个物品的地址 605 | DWORD ndFirstGoodsBase = ndBase + 4 * 0 + 0x43c; 606 | // 第一个物品的对象 607 | DWORD ndObj = NULL; 608 | for (int i = 0; i < nGoodsNum; i++) { 609 | ndObj = *(DWORD*)(ndFirstGoodsBase + 4 * i); // 取出第i个对象的地址 610 | if (ndObj == NULL) { 611 | // 如果读取数据为0===> 背包这一格没有物品 612 | this->mtGoodsList[i].ndGoodsNum = 0; 613 | continue; 614 | } 615 | // 读取物品的名字 616 | this->mtGoodsList[i].szGoodsName = (char*)(ndObj + GOODSNAME); 617 | // 读取物品的介绍 618 | this->mtGoodsList[i].szGoodsIntro = (char*)(ndObj + GOODSINTRO); 619 | // 读取物品的剩余数量 620 | this->mtGoodsList[i].ndGoodsNum = *(DWORD*)(ndObj + GOODSNUM); 621 | 622 | } 623 | } 624 | catch (...) { 625 | // 处理所有异常 626 | OutputDebugStringA("读取背包数据异常\r\n"); 627 | MessageBox(NULL, "读取背包数据异常(StructGame)", "Error", MB_OK); 628 | } 629 | 630 | return this; 631 | } 632 | 633 | 634 | ``` 635 | 636 | #### 调试调用 637 | 638 | ```c++ 639 | void CMainDialogWnd::OnBnClickedButton1() 640 | { 641 | TROLE_PROPERTY role; 642 | TROLE_PROPERTY* r = role.GetData(); 643 | TGOODSLIST_PROPERTY goods; 644 | 645 | TRACE("GameDebug:我的调试信息\r\n"); 646 | TRACE("GameDebug: 人物名=%s\r\n", r->GetRoleName()); 647 | TRACE("GameDebug: 人物等级=%d\r\n", r->nbClassValue); 648 | TRACE("GameDebug: 人物名声=%s\r\n", r->szReputation); 649 | TRACE("GameDebug: 人物血量HP=%d//%d\r\n", r->ndRoleHP, r->ndRoleMaxHP); 650 | TRACE("GameDebug: 人物内功MP=%d//%d\r\n", r->ndRoleMP, r->ndRoleMaxMP); 651 | TRACE("GameDebug: 人物愤怒值=%d\r\n", r->ndRoleAnger); 652 | TRACE("GameDebug: 人物金币=%d\r\n", r->nqMoney); 653 | TGOODSLIST_PROPERTY* g = goods.getData(); 654 | try { 655 | for (int i = 0; i < nGoodsNum; i++) { 656 | if (g->mtGoodsList[i].ndGoodsNum == 0) { 657 | continue; 658 | } 659 | TRACE("GameDebug: 人物第%d格数据:%s\r%s\r%d\r\n", i, 660 | g->mtGoodsList[i].szGoodsName, 661 | g->mtGoodsList[i].szGoodsIntro, 662 | g->mtGoodsList[i].ndGoodsNum 663 | ); 664 | } 665 | } 666 | catch (...) { 667 | MessageBox(TEXT("读取背包数据异常(Dialog)"), TEXT("Error"), MB_OK); 668 | } 669 | 670 | 671 | // 进行数据修改 672 | } 673 | 674 | 675 | ``` 676 | 677 | #### 文件结构 678 | 679 | ![](https://i.loli.net/2019/07/23/5d3707690948b56906.png) 680 | 681 | ## 背包物品的使用 682 | 683 | ### 之前Call 的分析 684 | 685 | ``` 686 | push 背包物品下标 687 | push 1 688 | push 0 689 | mov ecx, 背包基址 690 | call 00838470 691 | 692 | ``` 693 | 694 | #### 封装函数 695 | 696 | ``` 697 | UseGoods(char* szGoodsName) 698 | { 699 | // 若存在则使用它 700 | return 1; 701 | } 702 | 703 | ``` 704 | 705 | ### 背包物品使用代码 706 | 707 | - 定义基址 708 | 709 | ```c++ 710 | // 添加背包物品使用CALL 的地址 ===> 通过背包物品下标进行物品的使用 711 | #define BaseCall_UseGoodsForIndex 0x00838470 712 | 713 | ``` 714 | 715 | - 定义结构 716 | 717 | ```c++ 718 | // 背包结构 719 | typedef struct TGOODSLIST_PROPERTY { 720 | // 背包列表 721 | _TBACKPACK_GOODS mtGoodsList[nGoodsNum]; 722 | 723 | // 对数据的初始化 724 | TGOODSLIST_PROPERTY* getData(); 725 | 726 | // 使用背包物品 727 | int UseGoodsForIndex(DWORD ndIndex); 728 | 729 | // 通过名字查询下标,存在返回下标,不存在返回FALSE 730 | int GetGoodsIndexByName(char* szGoodsName); 731 | 732 | // 根据物品的名字进行使用 733 | int UseGoodsForName(char* szGoodsName); 734 | }_TGOODSLIST_PROPERTY; 735 | 736 | ``` 737 | 738 | - 实现方法 739 | 740 | ```c++ 741 | // 通过物品下标使用物品 742 | int TGOODSLIST_PROPERTY::UseGoodsForIndex(DWORD ndIndex) { 743 | 744 | try { 745 | // 使用内联汇编 746 | __asm { 747 | mov eax, ndIndex 748 | push eax 749 | push 1 750 | push 0 751 | // 读取背包地址 752 | mov ecx, [BaseBackpack] 753 | mov eax, BaseCall_UseGoodsForIndex 754 | call eax 755 | } 756 | } 757 | catch (...) { 758 | OutputDebugStringA("物品使用异常"); 759 | } 760 | 761 | return TRUE; 762 | 763 | } 764 | 765 | int TGOODSLIST_PROPERTY::UseGoodsForName(char* szGoodsName) 766 | { 767 | // 查找物品的下标 768 | DWORD ndIndex = this->GetGoodsIndexByName(szGoodsName); 769 | if (ndIndex != -1) { 770 | this->UseGoodsForIndex(ndIndex); 771 | return TRUE; 772 | } 773 | return FALSE; 774 | } 775 | 776 | int TGOODSLIST_PROPERTY::GetGoodsIndexByName(char* szGoodsName) { 777 | // 遍历整个背包,看是否存在该物品 778 | TGOODSLIST_PROPERTY* g = this->getData();// 初始化背包结构 779 | for (int i = 0; i < nGoodsNum; i++) { 780 | // 比较字符串,判断该物品是否存在 781 | if (strcmp(szGoodsName, g->mtGoodsList[i].szGoodsName) == 0) { 782 | return i; 783 | } 784 | } 785 | 786 | return -1; 787 | } 788 | 789 | 790 | ``` 791 | 792 | - 调用方法,实现物品的使用 793 | 794 | ```c++ 795 | if (g->UseGoodsForName("回城符(泫勃派)")) { 796 | TRACE("GameDebug: 使用 回城符(泫勃派) 成功"); 797 | } 798 | 799 | 800 | ``` 801 | 802 | - 文件结构 803 | 804 | ![](https://i.loli.net/2019/07/24/5d38542dcc65255168.png) 805 | 806 | ## 编写自定义的DbgPrintMine方法用于打印格式化调式信息 807 | 808 | ```c++ 809 | // DbgPrintMine.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 810 | // 811 | 812 | #include 813 | #include 814 | using namespace std; 815 | 816 | // 定义变参函数 817 | void DbgPrintMine(char* pszFormat, ...) { 818 | #ifdef _DEBUG 819 | // 如果在DEBUG 版本下才执行以下代码 820 | // 定义list 821 | va_list argList; 822 | // 初始化list 823 | va_start(argList, pszFormat); 824 | // 定义字符串缓冲区 825 | char szBufFormat[0x1000]; 826 | 827 | // 定义调试前缀 828 | char szBufFormat_Game[0x1008] = "Game:"; 829 | 830 | 831 | // 获取参数 va_arg(list, paramType) 832 | /*int i = va_arg(argList, int); 833 | int j = va_arg(argList, int); 834 | char* szK = va_arg(argList, char*);*/ 835 | 836 | 837 | vsprintf_s(szBufFormat, pszFormat, argList); 838 | strcat_s(szBufFormat_Game, szBufFormat); 839 | OutputDebugStringA(szBufFormat_Game); 840 | 841 | 842 | // 清除list 843 | va_end(argList); 844 | #endif 845 | 846 | } 847 | 848 | 849 | int main() 850 | { 851 | DbgPrintMine((char*)"%d, %d, %s\n", 1, 2, "贾谨荣"); 852 | system("pause"); 853 | } 854 | 855 | 856 | 857 | 858 | ``` 859 | 860 | ## 注:多线程访问数据造成异常的原因以及解决方式 861 | 862 | #### 造成异常的原因: 863 | 864 | - 游戏主线程与外挂线程同时访问共享数据区域,造成程序异常 865 | - 让两个线程依次使用共享数据或者将注入线程到主线程 866 | 867 | #### 模拟游戏主线程和辅助线程同时执行 868 | 869 | ![](https://i.loli.net/2019/07/25/5d396c0068fd480536.png) 870 | 871 | - 代码 872 | 873 | ```c++ 874 | // 定义变参函数 875 | void DbgPrintMine(char* pszFormat, ...) { 876 | #ifdef _DEBUG 877 | // 如果在DEBUG 版本下才执行以下代码 878 | // 定义list 879 | va_list argList; 880 | // 初始化list 881 | va_start(argList, pszFormat); 882 | // 定义字符串缓冲区 883 | char szBufFormat[0x1000]; 884 | 885 | // 定义调试前缀 886 | char szBufFormat_Game[0x1008] = "Game:"; 887 | 888 | 889 | // 获取参数 va_arg(list, paramType) 890 | /*int i = va_arg(argList, int); 891 | int j = va_arg(argList, int); 892 | char* szK = va_arg(argList, char*);*/ 893 | 894 | 895 | vsprintf_s(szBufFormat, pszFormat, argList); 896 | strcat_s(szBufFormat_Game, szBufFormat); 897 | OutputDebugStringA(szBufFormat_Game); 898 | 899 | 900 | // 清除list 901 | va_end(argList); 902 | #endif 903 | 904 | } 905 | 906 | DWORD g_ndGameData[10] = { 111, 222, 333, 444, 555, 666, 777, 888, 999, 000 }; 907 | DWORD* g_pndGameData[10]; 908 | 909 | void UseGoods(char* szGoodsName) { 910 | 911 | for (int i = 0; i < 10; i++) { 912 | DbgPrintMine("%s, %d\r\n", szGoodsName, *g_pndGameData[i]); 913 | Sleep(1 * 1000); 914 | } 915 | return; 916 | } 917 | 918 | DWORD WINAPI GameMainThreadProc(LPVOID lpData) { 919 | while (TRUE) { 920 | // 初始化内存 921 | memset(g_pndGameData, NULL, sizeof(g_pndGameData)); 922 | for (int i = 0; i < 10; i++) { 923 | g_pndGameData[i] = g_ndGameData + i; // &g_ndGameData[i] 924 | Sleep(1000); 925 | } 926 | // 物品使用的CALL 927 | UseGoods("游戏主线程"); 928 | } 929 | } 930 | 931 | DWORD WINAPI GameMyThreadProc(LPVOID lpData) { 932 | while (TRUE) { 933 | // 初始化内存 934 | 935 | UseGoods("外挂线程:222"); 936 | Sleep(1 * 1000); 937 | } 938 | } 939 | 940 | // 游戏主线程 941 | void CDataExceptionTestDlg::OnBnClickedButton1() 942 | { 943 | // TODO: 在此添加控件通知处理程序代码 944 | CreateThread(NULL, NULL, GameMainThreadProc, NULL, 0, NULL); 945 | } 946 | 947 | // 外挂线程 948 | void CDataExceptionTestDlg::OnBnClickedButton2() 949 | { 950 | // TODO: 在此添加控件通知处理程序代码 951 | CreateThread(NULL, NULL, GameMyThreadProc, NULL, 0, NULL); 952 | } 953 | 954 | 955 | ``` 956 | 957 | - 异常 958 | 959 | ![](https://i.loli.net/2019/07/25/5d396c8ded2eb52094.png) 960 | 961 | #### 解决方式 962 | 963 | - 将程序注入到主线程 964 | 965 | - 使用临界区 966 | 967 | - 1 968 | 969 | ![](https://i.loli.net/2019/07/25/5d3970363d1b650747.png) 970 | 971 | - 2、代码 972 | 973 | ```c++ 974 | // 定义变参函数 975 | void DbgPrintMine(char* pszFormat, ...) { 976 | #ifdef _DEBUG 977 | // 如果在DEBUG 版本下才执行以下代码 978 | // 定义list 979 | va_list argList; 980 | // 初始化list 981 | va_start(argList, pszFormat); 982 | // 定义字符串缓冲区 983 | char szBufFormat[0x1000]; 984 | 985 | // 定义调试前缀 986 | char szBufFormat_Game[0x1008] = "Game:"; 987 | 988 | 989 | // 获取参数 va_arg(list, paramType) 990 | /*int i = va_arg(argList, int); 991 | int j = va_arg(argList, int); 992 | char* szK = va_arg(argList, char*);*/ 993 | 994 | 995 | vsprintf_s(szBufFormat, pszFormat, argList); 996 | strcat_s(szBufFormat_Game, szBufFormat); 997 | OutputDebugStringA(szBufFormat_Game); 998 | 999 | 1000 | // 清除list 1001 | va_end(argList); 1002 | #endif 1003 | 1004 | } 1005 | 1006 | // 定义临界区; 1007 | CRITICAL_SECTION lpCriticalSection; 1008 | 1009 | DWORD g_ndGameData[10] = { 111, 222, 333, 444, 555, 666, 777, 888, 999, 000 }; 1010 | DWORD* g_pndGameData[10]; 1011 | 1012 | void UseGoods(char* szGoodsName) { 1013 | // 进入临界区 1014 | EnterCriticalSection(&lpCriticalSection); 1015 | 1016 | for (int i = 0; i < 10; i++) { 1017 | DbgPrintMine("%s, %d\r\n", szGoodsName, *g_pndGameData[i]); 1018 | Sleep(1 * 100); 1019 | } 1020 | // 离开临界区 1021 | LeaveCriticalSection(&lpCriticalSection); 1022 | 1023 | return; 1024 | } 1025 | 1026 | DWORD WINAPI GameMainThreadProc(LPVOID lpData) { 1027 | while (TRUE) { 1028 | // 进入临界区 1029 | EnterCriticalSection(&lpCriticalSection); 1030 | 1031 | // 初始化内存 1032 | memset(g_pndGameData, NULL, sizeof(g_pndGameData)); 1033 | for (int i = 0; i < 10; i++) { 1034 | g_pndGameData[i] = g_ndGameData + i; // &g_ndGameData[i] 1035 | Sleep(1000); 1036 | } 1037 | // 离开临界区 1038 | LeaveCriticalSection(&lpCriticalSection); 1039 | 1040 | // 腾出有点时间片给外挂线程使用 1041 | Sleep(1 * 1000); 1042 | // 物品使用的CALL 1043 | UseGoods("游戏主线程"); 1044 | } 1045 | } 1046 | 1047 | DWORD WINAPI GameMyThreadProc(LPVOID lpData) { 1048 | while (TRUE) { 1049 | // 初始化内存 1050 | 1051 | UseGoods("外挂线程:222"); 1052 | Sleep(1 * 1000); 1053 | } 1054 | } 1055 | 1056 | // 游戏主线程 1057 | void CDataExceptionTestDlg::OnBnClickedButton1() 1058 | { 1059 | // TODO: 在此添加控件通知处理程序代码 1060 | CreateThread(NULL, NULL, GameMainThreadProc, NULL, 0, NULL); 1061 | } 1062 | 1063 | // 外挂线程 1064 | void CDataExceptionTestDlg::OnBnClickedButton2() 1065 | { 1066 | // TODO: 在此添加控件通知处理程序代码 1067 | CreateThread(NULL, NULL, GameMyThreadProc, NULL, 0, NULL); 1068 | } 1069 | 1070 | 1071 | void CDataExceptionTestDlg::OnBnClickedOk() 1072 | { 1073 | // TODO: 在此添加控件通知处理程序代码 1074 | CDialogEx::OnOK(); 1075 | } 1076 | 1077 | 1078 | void CDataExceptionTestDlg::OnBnClickedButton3() 1079 | { 1080 | // TODO: 在此添加控件通知处理程序代码 1081 | // 初始化临界区 1082 | InitializeCriticalSection(&lpCriticalSection); 1083 | } 1084 | 1085 | 1086 | ``` 1087 | 1088 | ## 将代码注入游戏的主线程 1089 | 1090 | - 关键词 1091 | 1092 | ```c++ 1093 | SetWindowsHooksExa UnhookWindowsHookEx CWPSTRUCT 1094 | 1095 | ``` 1096 | 1097 | ### 定义方法 1098 | 1099 | ```c++ 1100 | #pragma once 1101 | 1102 | // HookGameMainThread.h 1103 | #define MSG_USEGOODSFORNAME 1 //使用物品的消息种类 1104 | 1105 | // 挂载主线程 1106 | DWORD HookMainThread(); 1107 | 1108 | // 卸载主线程 1109 | DWORD UnHookMainThread(); 1110 | 1111 | DWORD msgUseGoodsForName(char* szpName); 1112 | 1113 | ``` 1114 | 1115 | ### 实现方法 1116 | 1117 | ```c++ 1118 | // HookGameMainThread.cpp 1119 | #include "StructGame.h" 1120 | #include "HookGameMainThread.h" 1121 | 1122 | HHOOK g_hhkGame; 1123 | const DWORD MyMsgCode = RegisterWindowMessageA("MyMsgCode"); 1124 | // 回调函数 1125 | LRESULT CALLBACK GameWndProc( 1126 | int nCode, 1127 | WPARAM wParam, 1128 | LPARAM lParam 1129 | ) { 1130 | CWPSTRUCT* lpArg = (CWPSTRUCT*)lParam; 1131 | if (nCode == HC_ACTION) { 1132 | if (lpArg->hwnd == GetGameWndHandle() && lpArg->message == MyMsgCode) { 1133 | DbgPrintMine((char*)("消息传到 %s\r\n"), lpArg->lParam); 1134 | switch (lpArg->wParam) 1135 | { 1136 | case MSG_USEGOODSFORNAME: { 1137 | TGOODSLIST_PROPERTY goods; 1138 | TGOODSLIST_PROPERTY* g = goods.getData(); 1139 | if (g->UseGoodsForName((char*)lpArg->lParam)) { 1140 | DbgPrintMine((char*)("使用 %s 成功"), lpArg->lParam); 1141 | } 1142 | }; break; 1143 | default: 1144 | break; 1145 | } 1146 | return 1; 1147 | } 1148 | } 1149 | return CallNextHookEx(g_hhkGame, nCode, wParam, lParam); 1150 | } 1151 | DWORD HookMainThread() { 1152 | 1153 | HWND hGame = GetGameWndHandle(); 1154 | DWORD ndThreadId = GetWindowThreadProcessId(hGame, NULL); 1155 | if (ndThreadId != 0) { 1156 | // 安装钩子 1157 | g_hhkGame = SetWindowsHookEx(WH_CALLWNDPROC, GameWndProc, NULL, ndThreadId); 1158 | } 1159 | return 1; 1160 | } 1161 | 1162 | 1163 | DWORD UnHookMainThread() { 1164 | UnhookWindowsHookEx(g_hhkGame); 1165 | return 1; 1166 | } 1167 | 1168 | DWORD msgUseGoodsForName(char* szpName) { 1169 | // 传递消息(句柄、自定义的注册消息、自定义消息类别、消息内容(字符串)) 1170 | SendMessageA(GetGameWndHandle(), MyMsgCode, MSG_USEGOODSFORNAME, (LPARAM)szpName); 1171 | return 1; 1172 | } 1173 | 1174 | ``` 1175 | 1176 | ### 调用方法 1177 | 1178 | ```c++ 1179 | // 连接主线程 1180 | void CMainDialogWnd::OnBnClickedButton2() 1181 | { 1182 | // TODO: 在此添加控件通知处理程序代码 1183 | HookMainThread(); 1184 | } 1185 | 1186 | 1187 | void CMainDialogWnd::OnBnClickedButton3() 1188 | { 1189 | // TODO: 在此添加控件通知处理程序代码 1190 | UnHookMainThread(); 1191 | } 1192 | 1193 | 1194 | void CMainDialogWnd::OnBnClickedButton4() 1195 | { 1196 | // TODO: 在此添加控件通知处理程序代码 1197 | msgUseGoodsForName("金创药(小)"); 1198 | } 1199 | 1200 | ``` 1201 | 1202 | ### 文件结构 1203 | 1204 | ![](https://i.loli.net/2019/07/27/5d3c0b3353ba674453.png) 1205 | 1206 | ### 运行效果 1207 | 1208 | ![](https://i.loli.net/2019/07/27/5d3c0b5f3718e26663.png) 1209 | 1210 | ## 分析怪物列表 1211 | 1212 | - 分析思路:从怪物明显的属性入手:名字、**血量**等 1213 | 1214 | 1*4+427EBA0 //怪物列表基址(1-5) 1215 | 1216 | +8 种类/2E:怪物 1217 | 1218 | +354 显示血条 1219 | 1220 | +C 怪物选中参数 1221 | 1222 | +5f4 怪物血量 1223 | 1224 | +5f8 怪物等级 1225 | 1226 | +360 怪物名字 1227 | 1228 | +1060 怪物位置X 1229 | 1230 | +1068 怪物位置Y 1231 | 1232 | +3C0 怪物生命状态 0活/1死 1233 | 1234 | [0427EBA0] //角色对象指针 1235 | 1236 | +8 //角色分类31人物/2E 1237 | 1238 | +18 //角色名字 1239 | 1240 | ## 封装怪物对象属性 1241 | 1242 | - 定义基址 1243 | 1244 | ```c++ 1245 | // 怪物列表基址 1246 | #define BaseMonseterList 0x427EBA4 1247 | 1248 | ``` 1249 | 1250 | - 定义结构 1251 | 1252 | ```c++ 1253 | // 怪物结构 1254 | typedef struct TMonseterObj { 1255 | //+5f4 怪物血量 1256 | DWORD ndHp; 1257 | //+ 5f8 怪物等级 1258 | DWORD ndLevel; 1259 | //+ 360 怪物名字 1260 | char* szMName; 1261 | //+ 1060 怪物位置X 1262 | float flX; 1263 | //+ 1068 怪物位置Y 1264 | float flY; 1265 | //+ 3C0 怪物生命状态 0活 / 1死 1266 | BOOL IsDead; 1267 | }_TMonseterObj; 1268 | 1269 | // 怪物列表 1270 | #define MONSETERNUM 20 1271 | typedef struct TMonseterList { 1272 | 1273 | _TMonseterObj tMonList[MONSETERNUM]; 1274 | 1275 | // 初始化 1276 | TMonseterList* getData(); 1277 | 1278 | // 打印信息 1279 | BOOL dbgPrintMsg(); 1280 | }_TMonseterList; 1281 | 1282 | ``` 1283 | 1284 | - 实现结构方法 1285 | 1286 | ```c++ 1287 | TMonseterList* TMonseterList::getData() 1288 | { 1289 | DWORD ndObj = NULL; 1290 | //memset(this, 0, sizeof(TMonseterList)); 1291 | try 1292 | { 1293 | for (int i = 0; i < MONSETERNUM; i++) { 1294 | ndObj = *(DWORD*)(BaseMonseterList + 4 * i); 1295 | if (ndObj == 0) { 1296 | this->tMonList[i].ndLevel = 0; 1297 | continue; 1298 | } 1299 | // 怪物名字 1300 | this->tMonList[i].szMName = (char*)(ndObj + 0x360); 1301 | // 怪物血量 1302 | this->tMonList[i].ndHp = *(DWORD*)(ndObj + 0x5f4); 1303 | // 怪物等级 1304 | this->tMonList[i].ndLevel = *(DWORD*)(ndObj + 0x5f8); 1305 | // 怪物位置X 1306 | this->tMonList[i].flX = *(float*)(ndObj + 0x1060); 1307 | // 怪物位置Y 1308 | this->tMonList[i].flY = *(float*)(ndObj + 0x1068); 1309 | // 怪物生命状态 1310 | this->tMonList[i].IsDead = *(BOOL*)(ndObj + 0x3c0); 1311 | } 1312 | } 1313 | catch (...) 1314 | { 1315 | // 处理所有的异常 1316 | DbgPrintMine((char*)"读取怪物数据异常"); 1317 | } 1318 | return this; 1319 | } 1320 | 1321 | BOOL TMonseterList::dbgPrintMsg() { 1322 | for (int i = 0; i < MONSETERNUM; i++) { 1323 | if (tMonList[i].ndLevel == 0) { 1324 | continue; 1325 | } 1326 | DbgPrintMine((char*)("%s,等级:%d级;血量:%d;当前位置X:%f Y:%f;生命状态:%d"), 1327 | tMonList[i].szMName, 1328 | tMonList[i].ndLevel, 1329 | tMonList[i].ndHp, 1330 | tMonList[i].flX, 1331 | tMonList[i].flY, 1332 | tMonList[i].IsDead); 1333 | } 1334 | return TRUE; 1335 | } 1336 | 1337 | ``` 1338 | 1339 | - 在HOOK 内定义测试方法 1340 | 1341 | ```c++ 1342 | #define MSG_TEST 2 // 测试使用消息 1343 | 1344 | // 测试怪物 1345 | DWORD msgTest(LPVOID lpData); 1346 | 1347 | ``` 1348 | 1349 | - 实现 1350 | 1351 | ```c++ 1352 | // HookGameMainThread.cpp 1353 | #include "StructGame.h" 1354 | #include "HookGameMainThread.h" 1355 | 1356 | HHOOK g_hhkGame; 1357 | const DWORD MyMsgCode = RegisterWindowMessageA("MyMsgCode"); 1358 | // 回调函数 1359 | LRESULT CALLBACK GameWndProc( 1360 | int nCode, 1361 | WPARAM wParam, 1362 | LPARAM lParam 1363 | ) { 1364 | CWPSTRUCT* lpArg = (CWPSTRUCT*)lParam; 1365 | if (nCode == HC_ACTION) { 1366 | if (lpArg->hwnd == GetGameWndHandle() && lpArg->message == MyMsgCode) { 1367 | DbgPrintMine((char*)("消息传到 %s\r\n"), lpArg->lParam); 1368 | switch (lpArg->wParam) 1369 | { 1370 | case MSG_USEGOODSFORNAME: { 1371 | TGOODSLIST_PROPERTY goods; 1372 | TGOODSLIST_PROPERTY* g = goods.getData(); 1373 | if (g->UseGoodsForName((char*)lpArg->lParam)) { 1374 | DbgPrintMine((char*)("使用 %s 成功"), lpArg->lParam); 1375 | } 1376 | }; break; 1377 | 1378 | //////////////////////////////////////////////////////////////////////// 1379 | case MSG_TEST: { 1380 | TMonseterList tMonList; 1381 | TMonseterList* ptMonList = tMonList.getData(); 1382 | ptMonList->dbgPrintMsg(); 1383 | }; break; 1384 | default: 1385 | break; 1386 | } 1387 | return 1; 1388 | } 1389 | } 1390 | return CallNextHookEx(g_hhkGame, nCode, wParam, lParam); 1391 | } 1392 | DWORD HookMainThread() { 1393 | 1394 | HWND hGame = GetGameWndHandle(); 1395 | DWORD ndThreadId = GetWindowThreadProcessId(hGame, NULL); 1396 | if (ndThreadId != 0) { 1397 | // 安装钩子 1398 | g_hhkGame = SetWindowsHookEx(WH_CALLWNDPROC, GameWndProc, NULL, ndThreadId); 1399 | } 1400 | return 1; 1401 | } 1402 | 1403 | 1404 | DWORD UnHookMainThread() { 1405 | UnhookWindowsHookEx(g_hhkGame); 1406 | return 1; 1407 | } 1408 | 1409 | DWORD msgUseGoodsForName(char* szpName) { 1410 | // 传递消息(句柄、自定义的注册消息、自定义消息类别、消息内容(字符串)) 1411 | SendMessageA(GetGameWndHandle(), MyMsgCode, MSG_USEGOODSFORNAME, (LPARAM)szpName); 1412 | return 1; 1413 | } 1414 | 1415 | //////////////////////////////////////////////////////////////////////// 1416 | DWORD msgTest(LPVOID lpData) 1417 | { 1418 | SendMessageA(GetGameWndHandle(), MyMsgCode, MSG_TEST, (LPARAM)lpData); 1419 | return 0; 1420 | } 1421 | 1422 | 1423 | ``` 1424 | 1425 | - 控件调用 1426 | 1427 | ```c++ 1428 | void CMainDialogWnd::OnBnClickedButton5() 1429 | { 1430 | // TODO: 在此添加控件通知处理程序代码 1431 | msgTest(NULL); 1432 | } 1433 | 1434 | 1435 | ``` 1436 | 1437 | - 目录结构 1438 | 1439 | ![img](https://img-blog.csdnimg.cn/20190731224437537.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTM1MDk3,size_16,color_FFFFFF,t_70) 1440 | 1441 | 1442 | 1443 | ## 分析动作数组(攻击和打坐) 1444 | 1445 | - 思路: 1446 | - 通过选中的对象逆向回溯出动作的数组 1447 | - 通过动作对象访问逆向回溯到攻击CALL 附近 1448 | - 封包断点bp WSASend 1449 | 1450 | 1. 通过选中动作,利用CE 查找基址 1451 | 1452 | 2. 使用OD 分析访问内存信息,得到基址 1453 | 1454 | ```汇编 1455 | 0082D8F2 8D8CB7 3C040000 LEA ECX,DWORD PTR DS:[EDI+ESI*4+43C] 1456 | 1457 | ``` 1458 | 1459 | 动作公式:[02e3bd58]+43c+4*0 1460 | 1461 | 3. **找动作的CALL** 1462 | 1463 | - 使用CE 分析动作对象的调用访问 1464 | 1465 | - 得到一下信息 1466 | 1467 | ```汇编 1468 | // 攻击 1469 | 008530CE - 6A 01 - push 01 1470 | 008530D0 - E8 0B4AFBFF - call Client.exe+407AE0 1471 | 008530D5 - 8B 8C B7 3C040000 - mov ecx,[edi+esi*4+0000043C] << 1472 | 008530DC - 85 C9 - test ecx,ecx 1473 | 008530DE - 74 62 - je Client.exe+453142 1474 | 1475 | 008544B9 - 83 BF 34160000 35 - cmp dword ptr [edi+00001634],35 1476 | 008544C0 - 75 20 - jne Client.exe+4544E2 1477 | 008544C2 - 8B 84 B7 3C040000 - mov eax,[edi+esi*4+0000043C] << 1478 | 008544C9 - 85 C0 - test eax,eax 1479 | 008544CB - 74 15 - je Client.exe+4544E2 1480 | 1481 | 1482 | ``` 1483 | 1484 | - 使用OD分析得动作CALL为 1485 | 1486 | ```汇编 1487 | mov edi, [02E3CD58] 1488 | mov esi, 下标 1489 | MOV EAX,DWORD PTR DS:[EDI+ESI*4+43C] 1490 | mov ecx, [eax+0x54] 1491 | push ecx 1492 | CALL 007139E0 1493 | 1494 | 1495 | ``` 1496 | 1497 | ## 封装动作数组功能 1498 | 1499 | - 封装动作对象 1500 | - 封装动作对象列表 1501 | - 封装使用对象功能函数 1502 | 1503 | #### 封装 1504 | 1505 | 1. 封装基址 1506 | 1507 | ```C++ 1508 | // 人物动作使用的CALL 的基址 1509 | #define BaseActionCall 0x00713970 1510 | 1511 | ``` 1512 | 1513 | 2. 封装结构 1514 | 1515 | ```c++ 1516 | // 动作对象的结构 1517 | typedef struct TActionObj { 1518 | 1519 | // 对象名字 1520 | char* szpName; 1521 | // 调用CALL 的参数 1522 | DWORD ndActionID; 1523 | 1524 | }_TActionObj; 1525 | 1526 | // 动作对象数组 1527 | #define ActionNum 18 1528 | typedef struct TCActionList { 1529 | 1530 | // 定义动作数组 1531 | _TActionObj tList[ActionNum]; 1532 | 1533 | // 初始化 1534 | TCActionList* getData(); 1535 | 1536 | // 打印信息 1537 | BOOL TestActionMsg(); 1538 | 1539 | // 使用动作通过下标 1540 | BOOL UseActionByIndex(DWORD ndIndex); 1541 | 1542 | // 使用动作通过名字 1543 | BOOL UseActionByName(char* szpName); 1544 | 1545 | }_TCActionList; 1546 | 1547 | ``` 1548 | 1549 | 3. 实现结构方法 1550 | 1551 | ```c++ 1552 | TCActionList* TCActionList::getData() 1553 | { 1554 | //dc [[02e3bd58]+ 43c + 4 * 0] + 64 1555 | //+ 64 动作名字 1556 | 1557 | //[[02e3bd58]+ 43c + 4 * 0] + 54 1558 | //+ 54 调用CALL参数 1559 | 1560 | DWORD ndFirstObj = 0; 1561 | DWORD ndObj; 1562 | try { 1563 | ndFirstObj = (*(DWORD*)(BaseActionList))+0x43C; 1564 | for (int i = 0; i < ActionNum; i++) { 1565 | ndObj = *(DWORD*)(ndFirstObj + 4 * i); 1566 | if (ndObj == NULL) { 1567 | tList[i].ndActionID = 0; 1568 | continue; 1569 | } 1570 | tList[i].szpName = (char*)(ndObj + 0x64); 1571 | tList[i].ndActionID = *(DWORD*)(ndObj + 0x54); 1572 | } 1573 | } 1574 | catch (...) { 1575 | DbgPrintMine((char*)("内存读取异常")); 1576 | } 1577 | 1578 | return this; 1579 | } 1580 | 1581 | BOOL TCActionList::TestActionMsg() 1582 | { 1583 | for (int i = 0; i < ActionNum; i++) { 1584 | if (tList[i].ndActionID == 0) { 1585 | continue; 1586 | } 1587 | DbgPrintMine((char*)("动作名:%s, 动作ID:%X"), 1588 | tList[i].szpName, 1589 | tList[i].ndActionID); 1590 | 1591 | } 1592 | return TRUE; 1593 | } 1594 | 1595 | 1596 | 1597 | DWORD getObjByIndex(char* szpName) { 1598 | TCActionList tList; 1599 | TCActionList* ptList = tList.getData(); 1600 | for(int i = 0; i < ActionNum; i++) { 1601 | if (strcmp(szpName, ptList->tList[i].szpName) == 0) { 1602 | return i; 1603 | } 1604 | } 1605 | return -1; 1606 | } 1607 | 1608 | BOOL UseAction(DWORD ndIndex) { 1609 | TCActionList tList; 1610 | TCActionList* ptList = tList.getData(); 1611 | DWORD ndPrarm = ptList->tList[ndIndex].ndActionID; 1612 | try { 1613 | __asm { 1614 | mov ecx, ndPrarm 1615 | push ecx 1616 | mov eax, BaseActionCall 1617 | call eax 1618 | } 1619 | } 1620 | catch (...) { 1621 | DbgPrintMine((char*)("动作使用失败")); 1622 | return FALSE; 1623 | } 1624 | return TRUE; 1625 | } 1626 | 1627 | BOOL TCActionList::UseActionByIndex(DWORD ndIndex) 1628 | { 1629 | if (UseAction(ndIndex)) { 1630 | MessageBeep(0); 1631 | return TRUE; 1632 | } 1633 | return FALSE; 1634 | } 1635 | 1636 | BOOL TCActionList::UseActionByName(char* szpName) 1637 | { 1638 | DWORD ndIndex = getObjByIndex(szpName); 1639 | if (ndIndex != -1) { 1640 | if (UseAction(ndIndex)) { 1641 | MessageBeep(0); 1642 | return TRUE; 1643 | } 1644 | } 1645 | return FALSE; 1646 | } 1647 | 1648 | ``` 1649 | 1650 | 4. 添加消息类型 1651 | 1652 | ```c++ 1653 | #define MSG_ACTIONTEST 3 //测试动作 1654 | 1655 | ``` 1656 | 1657 | 1658 | 1659 | 5. 在主线程内调用结构体方法 1660 | 1661 | ```c++ 1662 | case MSG_ACTIONTEST: { 1663 | TCActionList* ptLIst = tList.getData(); 1664 | ptLIst->TestActionMsg(); 1665 | //ptLIst->UseActionByIndex(1); 1666 | ptLIst->UseActionByName((char*)("攻击")); 1667 | }; break; 1668 | 1669 | ``` 1670 | 1671 | 6. 发送消息到主线程 1672 | 1673 | ```c++ 1674 | DWORD testActionMsg(LPVOID lpData) { 1675 | SendMessageA(GetGameWndHandle(), MyMsgCode, MSG_ACTIONTEST, (LPARAM)lpData); 1676 | return 0; 1677 | } 1678 | 1679 | ``` 1680 | 1681 | 1682 | 1683 | 7. 绑定控件,执行方法 1684 | 1685 | ```c++ 1686 | void CMainDialogWnd::OnBnClickedButton6() 1687 | { 1688 | // TODO: 在此添加控件通知处理程序代码 1689 | testActionMsg(NULL); 1690 | } 1691 | 1692 | ``` 1693 | 1694 | 1695 | 1696 | - 文件结构 1697 | 1698 | ![img](https://img-blog.csdnimg.cn/20190808170008912.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTM1MDk3,size_16,color_FFFFFF,t_70) 1699 | 1700 | ## 选怪功能实现 1701 | 1702 | - 实现怪物选中 1703 | - 可能情况: 1704 | - 选怪变量被赋值 1705 | - 怪物是否被选中的属性 1706 | 1707 | #### 选怪功能相关地址 1708 | 1709 | - 玩家: 1710 | 1711 | [2E63A24] //存放的玩家对象的地址 1712 | 1713 | +3428 玩家是否被选中 1714 | 1715 | - 怪物: 1716 | 1717 | [2E63A24]+1A64 1718 | 1719 | 选中怪物时,传入怪物的选中ID 1720 | 1721 | 没选中怪物时,值为0xFFFF 1722 | 1723 | ## 选怪功能的封装 1724 | 1725 | 1726 | 1727 | ## 计算怪物与玩家的距离 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | # 更新ING 1734 | 1735 | --------------------------------------------------------------------------------