好友
阅读权限10
听众
最后登录1970-1-1
|
自从到论坛之后的第一年发了几个易语言的贴,就没再发,虽然每天看,但苦于没空写,今天发一个。
缘起最近朋友玩重返德军总部通不了关,于是有了这个修改器,其它两个是之前写的了,一共三个。三款游戏:
PVZ 植物大战僵尸中文年度加强版完整版
Torchlight2 火炬之光2 V1.25.9.5 荣耀典藏版
WolfSp 重返德军总部
游戏下载连接:
PVZ:http://www.lonelystar.org/download.htm(第三方网站)
Torchlight2:https://pan.quark.cn/s/9c287fc8176b(B站up主夸克网盘)
WolfSp:可以去B站找链接下载,后面放个网盘链接
首先看WolfSp的吧,开始依然是经典CE找值,辅助工具编写这里用的是C,也可以用易语言、C++、Rust、Go、C#等
重返德军总部的只做了几个主要的辅助功能,如下是功能列表:
- 角色无敌 【WolfSp.exe + 008042E4 + 0x3D8】
- 鲁格手枪无限子弹 【WolfSp.exe + 008042F0 + 0x298】
- 盖德冲锋枪无限子弹 【WolfSp.exe + 008042F0 + 0x29C】
- 栓动步枪(k98)无限子弹 【WolfSp.exe + 008042F0 + 0x2A0】
- 汤普逊冲锋枪无限子弹 【WolfSp.exe + 008042F0 + 0x2C0】
- 消音冲锋枪无限子弹 【WolfSp.exe + 008042F0 + 0x2D8】
- 炸药无限 【WolfSp.exe + 008042F0 + 0x2E8】
- Colt手枪子弹无限 【WolfSp.exe + 008042F0 + 0x2BC】
- 红外狙击枪无限子弹 【WolfSp.exe + 008042F0 + 0x2C4】
- 手雷无限 【WolfSp.exe + 008042F0 + 0x2C8】
- 连发狙击枪无限子弹 【WolfSp.exe + 008042F0 + 0x2A4】
- 火焰喷射器无限 【WolfSp.exe + 008042F0 + 0x2B4】
- 加特林无限子弹 【WolfSp.exe + 008042F0 + 0x2B0】
- 雷电炮无限 【WolfSp.exe + 008042F0 + 0x2B8】
- 消音冲锋枪无冷却 【WolfSp.exe + 008042F0 + 0x4F0】
- 加特林无冷却 【WolfSp.exe + 008042F0 + 0x4C8】
- 红外狙击枪电池无冷却 【WolfSp.exe + 008042F0 + 0x498】
18.手榴弹无限 【WolfSp.exe + 008042F0 + 0x2A8】
由于之前写的时候已经CE都把地址都找出来了,上面已经给大家写出对应地址和偏移了,这里只截取几张图简单演示下
主要就是无限子弹和武器过热无冷却的实现,子弹无限CE的找值方法都是相同的,所以就不全截图了,不然太多了,武器冷却也一样,查减少的数值或增加的数值,反复筛选就可以。
查找指针基址,CE右键有个功能是,扫描当前指针地址,不会找的朋友们可以用CE的功能直接扫描出来那个唯一的指针,这个指针基址在有的游戏是只有唯一一个但是有的游戏会有很多个,例如GTA这种就会有很多个,但是都可以拿来用。
在GTA中,你发射火箭弹,如果要实现火箭弹无限,扫描指针地址会出现很多,但是可以拿其中一个来用并且不会失效,原因是像GTA这类游戏,监测面很多,所以每个地方都会用的火箭弹这个值,所以只要拿一个来用,就可以实现火箭弹无限。
在重返德军总部中,由于使用修改器控制了子弹无限,所以换弹夹和子弹消耗并不会引出值为负数的情况,因为弹夹子弹无限了,需要每次换弹夹才能消耗备用子弹,
但在GTA中,如果只锁定弹夹子弹,换弹之后不断射击,最终会出现后备弹夹子弹为负数的情况。
回到正题,至于基址的问题,在C语言实现中是这样的:
第一步:获取进程 PID
通过CreateToolhelp32Snapshot创建快照,遍历系统进程列表通过比较进程名拿到进程PID
第二步:获取进程句柄
在拿到进程PID后,用OpenProcess(访问权标志,pid)函数传进去访问权限和刚才获取到的进程PID拿到操作句柄
第三步:获取游戏模块基址
在拿到PID和进程句柄后,再次CreateToolhelp32Snapshot创建快照,然后循环遍历遍历该进程加载的所有模块,找到那个和exe同名的模块就是基址了
1.为什么要游戏模块基址+指针基址+偏移? & ASLR是什么?它有什么用?
之所以要模块基址+指针基址+偏移才能永久找到某一个项的真实地址,是因为操作系统的内存空间地址随机化技术,简单说就是每次程序运行都会随机给它分配一条不同的起跑线。
ASRL的作用简单来说就是为了防止被攻击
2.为什么每次获取信息都要先创建快照?
系统进程变化很快,生命周期长短都不一致,每次操作前创建快照相当于做一个副本出来操作,这样会更安全,查找也更快,如果不创建快照会导致那些问题大家可以具体查询一下。
重返德军总部的源码如下:
[C] 纯文本查看 复制代码 #include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <time.h>
#include <string.h>
// 系统功能
#define SYS_CHECK_BTN_CONNECT 71 // 连接游戏
#define SYS_CHECK_BTN_DISCONNECT 72 // 断开连接
#define SYS_CHECK_BTN_EXIT 73 // 退出软件
#define SYS_LIST_LOG 74 // 日志列表
#define SYS_CHOICE_ALL 75 // 一键勾选所有选项
#define SYS_CANCEL_CHOICE_ALL 76 // 一键取消勾选所有
#define SYS_TOP_WINDOW 77 // 置顶窗口
#define SYS_SAVE_THIS_OPTIONS 78 // 保存当前选项
#define SYS_ENV_CHECK 79 // 系统环境检测
// 角色
#define ID_CHECK_ROLE_INVINCIBLE 1001
// 枪支
#define ID_CHECK_SHOUQIANG_WUXIANZIDAN 1002 // 手枪无限子弹
#define ID_CHECK_CHONGFENGQIANG_WUXIANZIDAN 1003 // 冲锋枪无限子弹
#define ID_CHECK_SHUANDONGBUQIANG_WUXIANZIDAN 1004 // 栓动步枪无限子弹
#define ID_CHECK_TANGMUXUN_WUXIANZIDAN 1005 // 汤姆逊无限子弹
#define ID_CHECK_XIAOYIN_CHONGFENGQIANG_WUXIANZIDAN 1006 // 消音冲锋枪无限子弹
#define ID_CHECK_ZHAYAO_WUXIAN 1007 // 炸药无限
#define ID_CHECK_SHAYING_WUXIANZIDAN 1008 // 沙鹰无限子弹
#define ID_CHECK_HONGWAIJUJI_WUXIANZIDAN 1009 // 红外狙击枪无限子弹
#define ID_CHECK_SHOULEI_WUXIAN 1010 // 手雷无限
#define ID_CHECK_LIANFAJU_WUXIANZIDAN 1011 // 连发狙击枪无限子弹
#define ID_CHECK_HUOYANPENSHEQI_WUXIAN 1012 // 火焰喷射器无限子弹
#define ID_CHECK_JIATELIN_WUXIANZIDAN 1013 // 加特林无限子弹
#define ID_CHECK_LEIDIANPAO_WUXIAN 1014 // 雷电炮无限子弹
#define ID_CHECK_HUOJIANDAN_WUXIAN 1015 // 火箭弹无限
#define ID_CHECK_SHOULIUDAN_WUXIAN 1016 // 手榴弹无限
// 枪支冷却
#define ID_CHECK_XIAOYINCHONGFENGQIANG_WULENGQUE 1017 // 消音冲锋枪无冷却
#define ID_CHECK_JIATELIN_WULENGQUE 1018 // 加特林无冷却
#define ID_CHECK_HONGWAIJU_WULENGQUE 1019 // 红外狙击枪电池无冷却
/** 基址、进程、句柄数据 */
DWORD pid = 0;
HWND hLoggingList = NULL; // 列表框句柄
HANDLE hProcess = NULL; // 进程句柄
DWORD_PTR moudleBase = 0; // 游戏基址
DWORD_PTR Role_pontAddress = 0x008042E4; // 角色二级指针
DWORD_PTR Gun_pointAddress = 0x008042F0; // 武器二级指针
/*偏移数据*/
DWORD role_offset1 = 0x3D8; // 角色无敌 一级偏移
DWORD shouqiang_offset1 = 0x298; // 手枪 无限子弹 一级偏移
DWORD chongfengqiang_offset1 = 0x29C; // 冲锋枪 无限子弹 一级偏移
DWORD shuandongbuqiang_offset1 = 0x2A0; // 栓动步枪 无限子弹 一级偏移
DWORD tangpuxun_offset1 = 0x2C0; // 汤普逊冲锋枪 无限子弹 一级偏移
DWORD xiaoyinchongfengqiang_no_time_offset1 = 0x4F0; // 消音冲锋枪无冷却一级偏移
DWORD xiaoyinchongfengqiang_full_offset1 = 0x2D8; // 消音冲锋枪 无限子弹 一级偏移
DWORD zhayao_offset1 = 0x2E8; // 炸药无限 一级偏移
DWORD shaying_offset1 = 0x2BC; // 沙鹰无限子弹 一级偏移
DWORD hongwaijujiqiang_no_time_offset = 0x498; // 红外狙击枪 无冷却 一级偏移
DWORD hongwaijujiqiang_full_offset1 = 0x2C4; // 红外狙击枪 无限子弹 一级偏移
DWORD shoulei_offset1 = 0x2C8; // 手雷无限 一级偏移
DWORD lianfajujiqiang_offset1 = 0x2A4; // 连发狙击枪 无限子弹 一级偏移
DWORD huoyanpensheqi_offset1 = 0x2B4; // 火焰喷射器无限 一级偏移
DWORD jiatelin_no_time_offset1 = 0x4C8; // 加特林无冷却 一级偏移
DWORD jiatelin_full_offset1 = 0x2B0; // 加特林无限子弹 一级偏移
// DWORD huojiandan_offset1 = 0x; //火箭弹无限 一级偏移
DWORD leidianpao_offset1 = 0x2B8; // 火箭炮无限子弹 一级偏移
DWORD shouliudan_offset1 = 0x2A8; // 手榴弹 一级偏移
void AddLog(HWND hList, const char *format, ...);
DWORD GetPidByName(char *processName);
DWORD_PTR GetModuleBaseAddress(DWORD pid, char *processName);
DWORD_PTR GetMemoryAddress(DWORD_PTR two_pointer, DWORD offset);
char *processName = NULL;
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_CREATE:
CreateWindow("BUTTON", "角色无敌",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 20, 170, 30,
hwnd, (HMENU)ID_CHECK_ROLE_INVINCIBLE, NULL, NULL);
CreateWindow("BUTTON", "手枪无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 60, 170, 30,
hwnd, (HMENU)ID_CHECK_SHOUQIANG_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "冲锋枪无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 100, 170, 30,
hwnd, (HMENU)ID_CHECK_CHONGFENGQIANG_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "栓动步枪无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 140, 170, 30,
hwnd, (HMENU)ID_CHECK_SHUANDONGBUQIANG_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "汤普逊无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 180, 170, 30,
hwnd, (HMENU)ID_CHECK_TANGMUXUN_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "消音冲锋枪无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 220, 170, 30,
hwnd, (HMENU)ID_CHECK_XIAOYIN_CHONGFENGQIANG_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "炸药无限",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 260, 170, 30,
hwnd, (HMENU)ID_CHECK_ZHAYAO_WUXIAN, NULL, NULL);
CreateWindow("BUTTON", "沙鹰无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 300, 170, 30,
hwnd, (HMENU)ID_CHECK_SHAYING_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "红外狙击枪无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 340, 170, 30,
hwnd, (HMENU)ID_CHECK_HONGWAIJUJI_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "手雷无限",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 380, 170, 30,
hwnd, (HMENU)ID_CHECK_SHOULEI_WUXIAN, NULL, NULL);
CreateWindow("BUTTON", "连发狙击枪无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 20, 170, 30,
hwnd, (HMENU)ID_CHECK_LIANFAJU_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "火焰喷射器无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 60, 170, 30,
hwnd, (HMENU)ID_CHECK_HUOYANPENSHEQI_WUXIAN, NULL, NULL);
CreateWindow("BUTTON", "加特林无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 100, 170, 30,
hwnd, (HMENU)ID_CHECK_JIATELIN_WUXIANZIDAN, NULL, NULL);
CreateWindow("BUTTON", "火箭弹无限",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 140, 170, 30,
hwnd, (HMENU)ID_CHECK_HUOJIANDAN_WUXIAN, NULL, NULL);
CreateWindow("BUTTON", "雷电炮无限子弹",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 180, 170, 30,
hwnd, (HMENU)ID_CHECK_LEIDIANPAO_WUXIAN, NULL, NULL);
CreateWindow("BUTTON", "消音冲锋枪无冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 220, 170, 30,
hwnd, (HMENU)ID_CHECK_XIAOYINCHONGFENGQIANG_WULENGQUE, NULL, NULL);
CreateWindow("BUTTON", "加特林无冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 260, 170, 30,
hwnd, (HMENU)ID_CHECK_JIATELIN_WULENGQUE, NULL, NULL);
CreateWindow("BUTTON", "红外狙击枪电池无冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 300, 170, 30,
hwnd, (HMENU)ID_CHECK_HONGWAIJU_WULENGQUE, NULL, NULL);
CreateWindow("BUTTON", "手榴弹无限",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 340, 170, 30,
hwnd, (HMENU)ID_CHECK_SHOULIUDAN_WUXIAN, NULL, NULL);
/**底部按钮区 */
CreateWindow("BUTTON", "连接游戏",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
0, 430, 100, 35,
hwnd, (HMENU)SYS_CHECK_BTN_CONNECT, NULL, NULL);
CreateWindow("BUTTON", "断开连接",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
110, 430, 100, 35,
hwnd, (HMENU)SYS_CHECK_BTN_DISCONNECT, NULL, NULL);
CreateWindow("BUTTON", "勾选所有",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
0, 470, 100, 35,
hwnd, (HMENU)SYS_CHOICE_ALL, NULL, NULL);
CreateWindow("BUTTON", "取消勾选所有",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
110, 470, 100, 35,
hwnd, (HMENU)SYS_CANCEL_CHOICE_ALL, NULL, NULL);
CreateWindow("BUTTON", "退出软件",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
220, 430, 100, 35,
hwnd, (HMENU)SYS_CHECK_BTN_EXIT, NULL, NULL);
CreateWindow("BUTTON", "置顶窗口",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
220, 470, 100, 35,
hwnd, (HMENU)SYS_TOP_WINDOW, NULL, NULL);
CreateWindow("BUTTON", "保存选项",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
330, 430, 100, 35,
hwnd, (HMENU)SYS_SAVE_THIS_OPTIONS, NULL, NULL);
CreateWindow("BUTTON", "环境检测",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
330, 470, 100, 35,
hwnd, (HMENU)SYS_ENV_CHECK, NULL, NULL);
hLoggingList = CreateWindow("LISTBOX", NULL,
WS_VISIBLE | WS_CHILD | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | WS_BORDER,
430, 20, 340, 500,
hwnd, (HMENU)SYS_LIST_LOG, NULL, NULL);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case SYS_CHECK_BTN_CONNECT:
processName = "WolfSP.exe";
pid = GetPidByName(processName);
if (pid == 0)
{
MessageBox(hwnd, "未找到游戏,请先启动游戏", "提示", MB_OK | MB_ICONWARNING);
return 0;
}
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL)
{
DWORD error = GetLastError();
char error_msg[64];
sprintf(error_msg, "无法打开进程,错误代码:0x%X", error);
MessageBox(hwnd, error_msg, "提示", MB_OK | MB_ICONWARNING);
return 0;
}
else
{
MessageBox(hwnd, "连接游戏成功", "提示", MB_OK);
}
moudleBase = GetModuleBaseAddress(pid, processName);
if (moudleBase == 0)
{
MessageBox(hwnd, "无法获取游戏模块基址!", "提示", MB_OK | MB_ICONWARNING);
// MessageBox(hwnd, "获取游戏失败", "提示", MB_OK | MB_ICONWARNING);
return 0;
}
else
{
MessageBox(hwnd, "修改器已成功挂载到游戏!", "成功", MB_OK);
// MessageBox(hwnd, "修改器已成功连接到游戏!", "成功", MB_OK);
}
AddLog(hLoggingList, "正在连接游戏%s", processName);
AddLog(hLoggingList, "连接成功%s", processName);
AddLog(hLoggingList, "游戏基址: 0x%X", moudleBase);
AddLog(hLoggingList, "进程PID:%lu", pid);
// 总控定时器
SetTimer(hwnd, 1, 50, NULL);
break;
case SYS_CHECK_BTN_DISCONNECT:
if (hProcess != NULL)
{
KillTimer(hwnd, 1);
CloseHandle(hProcess);
hProcess = NULL;
AddLog(hLoggingList, "已断开与游戏的连接");
}
else
{
MessageBox(hwnd, "当前没有连接游戏,无需断开", "提示", MB_OK | MB_ICONWARNING);
}
pid = 0;
moudleBase = 0;
break;
case SYS_CHECK_BTN_EXIT:
PostQuitMessage(0);
break;
case SYS_CHOICE_ALL:
for (int id = ID_CHECK_ROLE_INVINCIBLE; id <= ID_CHECK_HONGWAIJU_WULENGQUE; id++)
{
CheckDlgButton(hwnd, id, BST_CHECKED);
}
AddLog(hLoggingList, "已选择所有功能");
break;
case SYS_CANCEL_CHOICE_ALL:
for (int id = ID_CHECK_ROLE_INVINCIBLE; id <= ID_CHECK_HONGWAIJU_WULENGQUE; id++)
{
CheckDlgButton(hwnd, id, BST_UNCHECKED);
}
AddLog(hLoggingList, "已取消所有选择项");
break;
case SYS_TOP_WINDOW:
// 开启置顶
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
AddLog(hLoggingList, "置顶窗口已开启");
break;
/** 游戏功能区 */
// 角色无敌
case ID_CHECK_ROLE_INVINCIBLE:
if (IsDlgButtonChecked(hwnd, ID_CHECK_ROLE_INVINCIBLE))
{
AddLog(hLoggingList, "角色无敌 已开启");
}
else
{
AddLog(hLoggingList, "角色无敌 已关闭");
}
break;
case ID_CHECK_SHOUQIANG_WUXIANZIDAN:
// 手枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHOUQIANG_WUXIANZIDAN))
{
AddLog(hLoggingList, "手枪无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "手枪无限子弹 已关闭");
}
break;
// 冲锋枪无限子弹
case ID_CHECK_CHONGFENGQIANG_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_CHONGFENGQIANG_WUXIANZIDAN))
{
AddLog(hLoggingList, "冲锋枪无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "冲锋枪无限子弹 已关闭");
}
break;
// 栓动步枪无限子弹
case ID_CHECK_SHUANDONGBUQIANG_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHUANDONGBUQIANG_WUXIANZIDAN))
{
AddLog(hLoggingList, "栓动步枪无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "栓动步枪无限子弹 已关闭");
}
break;
// 汤普逊无限子弹
case ID_CHECK_TANGMUXUN_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_TANGMUXUN_WUXIANZIDAN))
{
AddLog(hLoggingList, "汤普逊无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "汤普逊无限子弹 已关闭");
}
break;
// 消音冲锋枪无限子弹
case ID_CHECK_XIAOYIN_CHONGFENGQIANG_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_XIAOYIN_CHONGFENGQIANG_WUXIANZIDAN))
{
AddLog(hLoggingList, "消音冲锋枪无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "消音冲锋枪无限子弹 已关闭");
}
break;
// 消音冲锋枪无冷却
case ID_CHECK_XIAOYINCHONGFENGQIANG_WULENGQUE:
if (IsDlgButtonChecked(hwnd, ID_CHECK_XIAOYINCHONGFENGQIANG_WULENGQUE))
{
AddLog(hLoggingList, "消音冲锋枪无冷却 已开启");
}
else
{
AddLog(hLoggingList, "消音冲锋枪无冷却 已关闭");
}
break;
// 炸药无限
case ID_CHECK_ZHAYAO_WUXIAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_ZHAYAO_WUXIAN))
{
AddLog(hLoggingList, "炸药无限 已开启");
}
else
{
AddLog(hLoggingList, "炸药无限 已关闭");
}
break;
// 沙鹰无限子弹
case ID_CHECK_SHAYING_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHAYING_WUXIANZIDAN))
{
AddLog(hLoggingList, "沙鹰无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "沙鹰无限子弹 已关闭");
}
break;
// 红外狙击枪无限子弹
case ID_CHECK_HONGWAIJUJI_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_HONGWAIJUJI_WUXIANZIDAN))
{
AddLog(hLoggingList, "红外狙击枪无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "红外狙击枪无限子弹 已关闭");
}
break;
// 红外狙击枪无冷却
case ID_CHECK_HONGWAIJU_WULENGQUE:
if (IsDlgButtonChecked(hwnd, ID_CHECK_HONGWAIJU_WULENGQUE))
{
AddLog(hLoggingList, "红外狙击枪无冷却 已开启");
}
else
{
AddLog(hLoggingList, "红外狙击枪无冷却 已关闭");
}
break;
// 手雷无限
case ID_CHECK_SHOULEI_WUXIAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHOULEI_WUXIAN))
{
AddLog(hLoggingList, "手雷无限 已开启");
}
else
{
AddLog(hLoggingList, "手雷无限 已关闭");
}
break;
// 连发狙击枪无限子弹
case ID_CHECK_LIANFAJU_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_LIANFAJU_WUXIANZIDAN))
{
AddLog(hLoggingList, "连发狙击枪无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "连发狙击枪无限子弹 已关闭");
}
break;
// 火焰喷射器无限子弹
case ID_CHECK_HUOYANPENSHEQI_WUXIAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_HUOYANPENSHEQI_WUXIAN))
{
AddLog(hLoggingList, "火焰喷射器无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "火焰喷射器无限子弹 已关闭");
}
break;
// 加特林无限子弹
case ID_CHECK_JIATELIN_WUXIANZIDAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_JIATELIN_WUXIANZIDAN))
{
AddLog(hLoggingList, "加特林无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "加特林无限子弹 已关闭");
}
break;
// 火箭弹无限
case ID_CHECK_HUOJIANDAN_WUXIAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_HUOJIANDAN_WUXIAN))
{
AddLog(hLoggingList, "火箭弹无限 已开启");
}
else
{
AddLog(hLoggingList, "火箭弹无限 已关闭");
}
break;
// 雷电炮无限子弹
case ID_CHECK_LEIDIANPAO_WUXIAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_LEIDIANPAO_WUXIAN))
{
AddLog(hLoggingList, "雷电炮无限子弹 已开启");
}
else
{
AddLog(hLoggingList, "雷电炮无限子弹 已关闭");
}
break;
case ID_CHECK_SHOULIUDAN_WUXIAN:
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHOULIUDAN_WUXIAN))
{
AddLog(hLoggingList, "手榴弹已开启 已开启");
}
else
{
AddLog(hLoggingList, "手榴弹已关闭 已关闭");
}
break;
case ID_CHECK_JIATELIN_WULENGQUE:
if (IsDlgButtonChecked(hwnd, ID_CHECK_JIATELIN_WULENGQUE))
{
AddLog(hLoggingList, "加特林无冷却 已开启");
}
else
{
AddLog(hLoggingList, "加特林无冷却 已关闭");
}
}
break;
case WM_TIMER:
if (hProcess != NULL && moudleBase != 0)
{
// 角色无敌
if (IsDlgButtonChecked(hwnd, ID_CHECK_ROLE_INVINCIBLE))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Role_pontAddress, role_offset1);
int maxHP = 100;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &maxHP, 4, NULL);
}
}
// 手枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHOUQIANG_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, shouqiang_offset1);
int max = 5;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 冲锋枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_CHONGFENGQIANG_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, chongfengqiang_offset1);
int max = 32;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 栓动步枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHUANDONGBUQIANG_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, shuandongbuqiang_offset1);
int max = 5;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 汤普逊冲锋枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_TANGMUXUN_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, tangpuxun_offset1);
int max = 30;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 消音冲锋枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_XIAOYIN_CHONGFENGQIANG_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, xiaoyinchongfengqiang_full_offset1);
int max = 30;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 消音冲锋枪无冷却
if (IsDlgButtonChecked(hwnd, ID_CHECK_XIAOYINCHONGFENGQIANG_WULENGQUE))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, xiaoyinchongfengqiang_no_time_offset1);
int max = 0;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 炸药无限
if (IsDlgButtonChecked(hwnd, ID_CHECK_ZHAYAO_WUXIAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, zhayao_offset1);
int max = 10;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 沙鹰(科尔特)无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHAYING_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, shaying_offset1);
int max = 8;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 红外狙击枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_HONGWAIJUJI_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, hongwaijujiqiang_full_offset1);
int max = 8;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 手雷无限
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHOULEI_WUXIAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, shoulei_offset1);
int max = 8;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 连发狙击枪无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_LIANFAJU_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, lianfajujiqiang_offset1);
int max = 8;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 火焰喷射器无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_HUOYANPENSHEQI_WUXIAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, huoyanpensheqi_offset1);
int max = 20;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 加特林无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_JIATELIN_WUXIANZIDAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, jiatelin_full_offset1);
int max = 777;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 雷电炮无限子弹
if (IsDlgButtonChecked(hwnd, ID_CHECK_LEIDIANPAO_WUXIAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, leidianpao_offset1);
int max = 23;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 加特林无冷却
if (IsDlgButtonChecked(hwnd, ID_CHECK_JIATELIN_WULENGQUE))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, jiatelin_no_time_offset1);
int max = 8;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 手榴弹无限
if (IsDlgButtonChecked(hwnd, ID_CHECK_SHOULIUDAN_WUXIAN))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, shouliudan_offset1);
int max = 10;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
// 红外狙击枪电池无冷却
if (IsDlgButtonChecked(hwnd, ID_CHECK_HONGWAIJU_WULENGQUE))
{
DWORD_PTR real_mem_address = GetMemoryAddress(Gun_pointAddress, hongwaijujiqiang_no_time_offset);
int max = 250;
if (real_mem_address != 0)
{
WriteProcessMemory(hProcess, (LPVOID)real_mem_address, &max, 4, NULL);
}
}
}
break;
/* Upon destruction, tell the main thread to stop */
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
/* All other messages (a lot of them) are processed using default procedures */
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc; /* A properties struct of our window */
HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
MSG msg; /* A temporary location for all messages */
/* zero out the struct and set the stuff we want to modify */
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc; /* This is where we will send messages to */
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
/* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = "WindowClass";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon */
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "WindowClass", "重返德军总部WolFsp修改器", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /* x */
CW_USEDEFAULT, /* y */
785, /* width */
570, /* height */
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
/*
This is the heart of our program where all input is processed and
sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
this loop will not produce unreasonably high CPU usage
*/
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
/* If no error is received... */
TranslateMessage(&msg); /* Translate key codes to chars if present */
DispatchMessage(&msg); /* Send it to WndProc */
}
return msg.wParam;
}
void AddLog(HWND hList, const char *format, ...)
{
char finalLog[512];
char timerStr[32];
char contenStr[256];
// 获取当前时间
SYSTEMTIME st;
GetLocalTime(&st);
sprintf(timerStr, "[%02d:%02d:%02d]", st.wHour, st.wMinute, st.wSecond);
// 处理格式化字符串
va_list agrs;
va_start(agrs, format);
vsnprintf(contenStr, sizeof(contenStr), format, agrs);
va_end(agrs);
// 拼接字符串
sprintf(finalLog, "%s%s", timerStr, contenStr);
// 发送给Win32 ListBox控件
int index = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)finalLog);
// 让列表始终滚动看到最新消息
SendMessage(hList, LB_SETCURSEL, index, 0);
}
// 获取PID
DWORD GetPidByName(char *processName)
{
DWORD pid = 0;
// 创建快照
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
// 遍历进程
if (Process32First(hSnapshot, &pe))
{
do
{
if (stricmp(pe.szExeFile, processName) == 0)
{
pid = pe.th32ProcessID;
break;
}
/* code */
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
}
return pid;
}
// 获取进程模块基址
DWORD_PTR GetModuleBaseAddress(DWORD pid, char *processName)
{
DWORD_PTR modelBase = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(MODULEENTRY32);
if (Module32First(hSnap, &modEntry))
{
do
{
if (stricmp(modEntry.szModule, processName) == 0)
{
modelBase = (DWORD_PTR)modEntry.modBaseAddr;
break;
}
/* code */
} while (Module32Next(hSnap, &modEntry));
}
CloseHandle(hSnap);
}
return modelBase;
}
// 计算在内存中的真实地址
DWORD_PTR GetMemoryAddress(DWORD_PTR two_pointer, DWORD offset)
{
if (!hProcess || !moudleBase)
{
return 0;
}
DWORD p1 = 0;
DWORD_PTR absoluteBaseAddr = moudleBase + two_pointer;
ReadProcessMemory(hProcess, (LPCVOID)absoluteBaseAddr, &p1, 4, NULL);
if (p1 == 0)
{
return 0;
}
// AddLog(hLoggingList,"当前内存地址: 0x%X",p1);
return p1 + offset;
}
【植物大战僵尸】
再来说PVZ吧,植物大战僵尸是经典游戏了,植物大战僵尸的逻辑和重返德军总部、火炬2的是大有不同的
在实现修改的方法上最能体现,主要的一个区别是,PVZ的每个游戏方法都是独立的,但重返德军总部
火炬之光2都是玩家和NPC公用同一个方法来进行血量加减和CD值冷却。
例如:在德军总部中,你如果找到了之前说的那个sub,你想像修改PVZ的阳光一样,将sub改为add或者说
sub->add
dec->inc
mov eax,0
cmp ebp,01
test edi,00
如果修改某个加减或者赋值、比较的话,你会发现NPC和玩家同时血量无敌,无需换弹夹(无限子弹)、爆发伤害
所以PVZ给了你一个新的东西,僵尸、植物这些是分开的,但是僵尸有的逻辑是共用的,植物和植物之间也是有共用方法的
所以在实现植物无敌的时候,只需要修改sub为add或者mov赋僵尸的伤害值为0就是植物无敌了,植物无敌可以从高坚果身上,
找个人认为是比较明显的。
这也是PVZ这类游戏,为什么可以直接修改内存中的操作码来实现修改器功能,开发者写的区分方法是最大功臣(今晚开发加鸡腿),
如果采用共用体那还是和重返德军总部火炬2一样的,要借助定时器不断的写内存值。
PVZ这里也是之前写的了,CE不再做截图了,就是搜索值的问题,通过值的变化找到内存地址,然后找到偏移和指针基址,
PVZ的地址比德军总部和火炬2更直接,找到对应的汇编指令,修改其字节即可。
汇编这里需要知道基本的:
pop,push,ret
sub,add,inc,dec,cmp,mov,test
je,jne,jz,jnz,jl,jle,jae
这些常见的汇编指令都代表什么意思
这里列几个PVZ的场景说一下:
迷雾透视:
迷雾透视这里就是一个颜色值,可以把这个颜色值改的小一点就实现了既有迷雾,但透视的夜视仪效果
这里的注意点是,迷雾分了两块。
毁灭菇爆炸无弹坑
毁灭蘑爆炸无弹坑,这里是个定时器时间判断,时间归0弹坑就恢复正常草地,所以还是未知初始值—减少的数值
种植植物增加阳光
种植植物增加阳光,种一颗植物,减少阳光后搜索,找到地址后查看汇编,sub修改为add,注意字节数要和原来的对齐
玉米加农炮无冷却
和毁灭蘑一样,也是定时器,但是要比毁灭菇的短,好像是4000,毁灭菇是8000,整个PVZ冷却时间最长的好像就是毁灭菇弹坑
- 僵尸秒杀 0054D0BA sub 2B 6C 24 20 修改:31,ED,nop,nop
- 无视僵尸防具 0054CDD4 sub 2B,C8 修改:xor 31,C9
- 迷雾透视:00426157和00426160 BA,FF000000和BA,C8000000 mov 修改:BA,0x值,BA,0x值
- 植物无敌:0054BA6A add 83,46,40,FC 修改:nop 0x90 0x90 ox90 0x90
- 毁灭菇爆炸无弹坑:00474D27 mov C7,40,18,50460000 修改:C7,40,18,00000000
- 磁力菇无冷却:0046F9EA mov C7,46,54,DC050000 修改:C7,40,54,00000000
- 土豆地雷无冷却:0046C679 mov C7,40,54,DC050000 修改:C7,40,54,00000000
- 种植植物无需阳光:00427694 mov 2B,F3 修改:0x90,0x90
- ..................
【重点】修改汇编指令后,前后字节数必须对齐,不然就要0x90也就是用NOP填充,尽量对齐,不用NOP填充,有的游戏会闪退,例如德军部队.
植物大战僵尸源码:
[C] 纯文本查看 复制代码 #include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include<psapi.h>
//【僵尸部分】
#define ID_CHECKBOX_ZOMBIES_KILL 1001
#define ID_CHECKBOX_ZOMBIES_PROTECT_KILL 1002
//【植物部分】
#define ID_CHECKBOX_PLANT_ADD_SUN 2001
#define ID_CHECKBOX_ALL_PLANT_CARD_NO_TIME 2002
#define ID_CHECKBOX_CRON_CANNON_NO_TIME 2003
#define ID_CHECKBOX_BIG_FLOWER_NO_TIME 2004
#define ID_CHECKBOX_PLANT_INVINCIBLE 2005
#define ID_CHECKBOX_CILIGU_NO_COOLING 2006
#define ID_CHECKBOX_HUIMIEGU_BOBM_NO_PIT 2007
#define ID_CHECKBOX_POTATO_BOBM_NO_TIME 2008
#define ID_CHECKBOX_ADD_PLANT_NO_SUN 2009
//【其它部分】
#define ID_CHECKBOX_MIST_PERSPECTIVE 3001
static HANDLE hProcess = NULL;
static DWORD_PTR baseAddr = 0x400000;
void Plant(HANDLE hProcess , int char_order,int flag, DWORD_PTR baseAddr);
void Zombies(HANDLE hProcess , int char_order,int flag, DWORD_PTR baseAddr);
void Other(HANDLE hProcess,int char_order,int flag,DWORD_PTR baseAddr);
void Memory_Modification(HANDLE hProcess, LPVOID targetAddr, unsigned char* compile_order, size_t order_sizeof);
LRESULT CALLBACK WindowProc(HWND hwnd_init, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_CREATE: {
// --- 只在窗口创建时连接一次游戏 ---
const char* windowName = "Plants vs. Zombies";
HWND hwnd = FindWindowA(NULL, windowName);
if(!hwnd) {
MessageBox(hwnd_init,"连接游戏失败","错误",MB_ICONERROR);
return -1;
}
//获取系统进程 PID
DWORD pid;
GetWindowThreadProcessId(hwnd,&pid);
//获取操作句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
if(!hProcess) {
MessageBox(hwnd_init, "无法打开进程,请以管理员身份运行!", "错误", MB_ICONERROR);
return -1;
}
MessageBox(hwnd_init,"成功连接游戏","提示",MB_OK);
//【僵尸秒杀】
CreateWindow("BUTTON","僵尸秒杀",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20,20,150,30,
hwnd_init, (HMENU)ID_CHECKBOX_ZOMBIES_KILL, NULL, NULL);
//【僵尸防具无视】
CreateWindow("BUTTON","无视僵尸防具",
WS_VISIBLE | WS_CHILD |BS_AUTOCHECKBOX,
20,60,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_ZOMBIES_PROTECT_KILL,NULL,NULL
);
//【种植植物增加阳光】
CreateWindow("BUTTON","种植植物加阳光",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,20,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_PLANT_ADD_SUN,NULL,NULL
);
//【大食花无需等待】
CreateWindow("BUTTON","大食花无需冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,60,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_BIG_FLOWER_NO_TIME,NULL,NULL
);
//【玉米加农炮无需冷却】
CreateWindow("BUTTON","玉米加农炮无冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,100,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_CRON_CANNON_NO_TIME,NULL,NULL
);
//【所有植物卡片无冷却】
CreateWindow("BUTTON","植物卡片无冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,140,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_ALL_PLANT_CARD_NO_TIME,NULL,NULL
);
//【植物无敌】
CreateWindow("BUTTON","植物无敌",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,180,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_PLANT_INVINCIBLE,NULL,NULL
);
//【磁力菇无冷却】
CreateWindow("BUTTON","磁力菇无冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,220,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_CILIGU_NO_COOLING,NULL,NULL
);
//【毁灭菇爆炸无弹坑】
CreateWindow("BUTTON","毁灭菇爆炸无弹坑",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,260,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_HUIMIEGU_BOBM_NO_PIT,NULL,NULL
);
//【土豆地雷无冷却】
CreateWindow(
"BUTTON","土豆地雷无需冷却",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,300,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_POTATO_BOBM_NO_TIME,NULL,NULL
);
//【种植植物无需阳光】
CreateWindow(
"BUTTON","种植植物无需阳光",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
200,340,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_ADD_PLANT_NO_SUN,NULL,NULL
);
//【迷雾透视】
CreateWindow("BUTTON","迷雾透视",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
380,20,150,30,
hwnd_init,(HMENU)ID_CHECKBOX_MIST_PERSPECTIVE,NULL,NULL
);
break;
}
case WM_COMMAND:
//【僵尸秒杀】
if(LOWORD(wParam)==ID_CHECKBOX_ZOMBIES_KILL) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Zombies(hProcess,ID_CHECKBOX_ZOMBIES_KILL,1,baseAddr);
MessageBox(hwnd_init,"僵尸秒杀已开启","提示",MB_OK);
} else {
Zombies(hProcess,ID_CHECKBOX_ZOMBIES_KILL,0,baseAddr);
MessageBox(hwnd_init,"僵尸秒杀关闭","提示",MB_OK);
}
}
//【无视僵尸防具】
if(LOWORD(wParam)==ID_CHECKBOX_ZOMBIES_PROTECT_KILL) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Zombies(hProcess,ID_CHECKBOX_ZOMBIES_PROTECT_KILL,1,baseAddr);
MessageBox(hwnd_init,"无视僵尸防具已开启","提示",MB_OK);
} else {
Zombies(hProcess,ID_CHECKBOX_ZOMBIES_PROTECT_KILL,0,baseAddr);
MessageBox(hwnd_init,"无视僵尸防具关闭","提示",MB_OK);
}
}
//【种植植物加阳光】
if(LOWORD(wParam)==ID_CHECKBOX_PLANT_ADD_SUN) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_PLANT_ADD_SUN,1,baseAddr);
MessageBox(hwnd_init,"种植植物加阳光已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_PLANT_ADD_SUN,0,baseAddr);
MessageBox(hwnd_init,"种植植物加阳光关闭","提示",MB_OK);
}
}
//【大食花无冷却】
if(LOWORD(wParam)==ID_CHECKBOX_BIG_FLOWER_NO_TIME) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_BIG_FLOWER_NO_TIME,1,baseAddr);
MessageBox(hwnd_init,"大食花无冷却已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_BIG_FLOWER_NO_TIME,0,baseAddr);
MessageBox(hwnd_init,"大食花无冷却已关闭","提示",MB_OK);
}
}
//【玉米加农炮无冷却】
if(LOWORD(wParam)==ID_CHECKBOX_CRON_CANNON_NO_TIME) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_CRON_CANNON_NO_TIME,1,baseAddr);
MessageBox(hwnd_init,"玉米加农炮无冷却已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_CRON_CANNON_NO_TIME,0,baseAddr);
MessageBox(hwnd_init,"玉米加农炮无冷却已关闭","提示",MB_OK);
}
}
//【植物卡片无冷却】
if(LOWORD(wParam)==ID_CHECKBOX_ALL_PLANT_CARD_NO_TIME) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_ALL_PLANT_CARD_NO_TIME,1,baseAddr);
MessageBox(hwnd_init,"玉植物卡片无冷却已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_ALL_PLANT_CARD_NO_TIME,0,baseAddr);
MessageBox(hwnd_init,"植物卡片无冷却已关闭","提示",MB_OK);
}
}
//【植物无敌】
if(LOWORD(wParam)==ID_CHECKBOX_PLANT_INVINCIBLE) {
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_PLANT_INVINCIBLE,1,baseAddr);
MessageBox(hwnd_init,"植物无敌已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_PLANT_INVINCIBLE,0,baseAddr);
MessageBox(hwnd_init,"植物无敌已关闭","提示",MB_OK);
}
}
//【磁力菇无冷却】
if(LOWORD(wParam)==ID_CHECKBOX_CILIGU_NO_COOLING) {
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_CILIGU_NO_COOLING,1,baseAddr);
MessageBox(hwnd_init,"磁力菇无冷却已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_CILIGU_NO_COOLING,0,baseAddr);
MessageBox(hwnd_init,"磁力菇无冷却已关闭","提示",MB_OK);
}
}
//【毁灭菇爆炸无弹坑】
if(LOWORD(wParam)==ID_CHECKBOX_HUIMIEGU_BOBM_NO_PIT) {
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_HUIMIEGU_BOBM_NO_PIT,1,baseAddr);
MessageBox(hwnd_init,"毁灭菇爆炸无弹坑已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_HUIMIEGU_BOBM_NO_PIT,0,baseAddr);
MessageBox(hwnd_init,"毁灭菇爆炸无弹坑关闭","提示",MB_OK);
}
}
//【土豆地雷无冷却】
if(LOWORD(wParam)==ID_CHECKBOX_POTATO_BOBM_NO_TIME) {
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_POTATO_BOBM_NO_TIME,1,baseAddr);
MessageBox(hwnd_init,"土地地雷无冷却已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_POTATO_BOBM_NO_TIME,0,baseAddr);
MessageBox(hwnd_init,"土地地雷无冷却已关闭","提示",MB_OK);
}
}
//【种植植物无需阳光】
if(LOWORD(wParam)==ID_CHECKBOX_ADD_PLANT_NO_SUN) {
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Plant(hProcess,ID_CHECKBOX_ADD_PLANT_NO_SUN,1,baseAddr);
MessageBox(hwnd_init,"种植植物无需阳光已开启","提示",MB_OK);
} else {
Plant(hProcess,ID_CHECKBOX_ADD_PLANT_NO_SUN,0,baseAddr);
MessageBox(hwnd_init,"种植植物无需阳光已关闭","提示",MB_OK);
}
}
//【迷雾透视】
if(LOWORD(wParam)==ID_CHECKBOX_MIST_PERSPECTIVE) {
//获取候选状态
LRESULT checked = SendMessage((HWND)lParam,BM_GETCHECK,0,0);
if(checked==BST_CHECKED) {
Other(hProcess,ID_CHECKBOX_MIST_PERSPECTIVE,1,baseAddr);
MessageBox(hwnd_init,"迷雾透视已开启","提示",MB_OK);
} else {
Other(hProcess,ID_CHECKBOX_MIST_PERSPECTIVE,0,baseAddr);
MessageBox(hwnd_init,"迷雾透视已关闭","提示",MB_OK);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd_init,uMsg,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
const char CLASS_NAME[] = "Plants vs. Zombies";
WNDCLASS wc = {0};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClass(&wc);
HWND hwnd_init = CreateWindowEx(0, CLASS_NAME, "我的植物大战僵尸修改器",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
640, 480, NULL, NULL, hInstance, NULL);
if (hwnd_init == NULL) {
return 0;
}
ShowWindow(hwnd_init, nCmdShow);
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
//植物功能
void Plant(HANDLE hProcess , int char_order,int flag, DWORD_PTR baseAddr) {
if(hProcess==NULL) {
MessageBox(NULL, "错误:句柄为空!", "调试信息", MB_OK);
return;
}
//获取系统时间
SYSTEMTIME st;
GetLocalTime(&st);
switch(char_order) {
//【种植物加阳光】
case ID_CHECKBOX_PLANT_ADD_SUN: {
DWORD_PTR SunOffset= 0x27694;
unsigned char addCode[] = {0x03,0xF3};
unsigned char subCode[] = {0x2B,0xF3};
LPVOID targetAddr = (LPVOID)(baseAddr + SunOffset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,addCode,sizeof(addCode));
} else {
Memory_Modification(hProcess,targetAddr,subCode,sizeof(subCode));
}
break;
}
//【植物卡片冷却】
case ID_CHECKBOX_ALL_PLANT_CARD_NO_TIME: {
DWORD_PTR Plants_Card_Cd_Offset = 0x9CE02;
unsigned char nopCode[] = {0x90,0x90};
unsigned char normalCode[] = {0x7E,0x16};
LPVOID targetAddr = (LPVOID)(baseAddr+Plants_Card_Cd_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,nopCode,sizeof(nopCode));
} else {
Memory_Modification(hProcess,targetAddr,normalCode,sizeof(normalCode));
}
break;
}
//【玉米加农炮无冷却】
case ID_CHECKBOX_CRON_CANNON_NO_TIME: {
DWORD_PTR Corn_cannon_Offset = 0x73196;
unsigned char Cron_cannon_No_cd[] = {0xC7, 0x47, 0x54, 0x00, 0x00, 0x00, 0x00};
unsigned char Cron_cannon_normal_cd[] = { 0xC7, 0x47, 0x54, 0xB8, 0x0B, 0x00, 0x00 };
LPVOID targetAddr = (LPVOID)(baseAddr+Corn_cannon_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,Cron_cannon_No_cd,sizeof(Cron_cannon_No_cd));
} else {
Memory_Modification(hProcess,targetAddr,Cron_cannon_normal_cd,sizeof(Cron_cannon_normal_cd));
}
break;
}
//【大食花无冷却】
case ID_CHECKBOX_BIG_FLOWER_NO_TIME: {
DWORD_PTR Big_Food_Flower_Offset = 0x6F90E;
unsigned char Big_Food_Flower_No_Cd[] = {0xC7,0x47,0x54,0x00,0x00,0x00,0x00};
unsigned char Big_Food_Floer_normal_cd[] = {0xC7,0x47,0x54,0xA0,0xF,0x00,0x00};
LPVOID targetAddr = (LPVOID)(baseAddr + Big_Food_Flower_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,Big_Food_Flower_No_Cd,sizeof(Big_Food_Flower_No_Cd));
} else {
Memory_Modification(hProcess,targetAddr,Big_Food_Floer_normal_cd,sizeof(Big_Food_Floer_normal_cd));
}
break;
}
//【植物无敌】
case ID_CHECKBOX_PLANT_INVINCIBLE: {
DWORD_PTR Plant_Invincible_Offset = 0x14BA6A;
unsigned char Plant_Invincible_Nop[] = {0x90,0x90,0x90,0x90};
unsigned char Plant_Invincible_Mov[] = {0x83,0x46,0x40,0xFC};
LPVOID targetAddr = (LPVOID)(baseAddr+Plant_Invincible_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,Plant_Invincible_Nop,sizeof(Plant_Invincible_Nop));
} else {
Memory_Modification(hProcess,targetAddr,Plant_Invincible_Mov,sizeof(Plant_Invincible_Mov));
}
break;
}
//【磁力菇无冷却】
case ID_CHECKBOX_CILIGU_NO_COOLING: {
DWORD_PTR CiLiGu_No_Cooling_Offset = 0x6F9EA;
unsigned char CiLiGu_No_Cooling_New_Mov[] = {0xC7,0x46,0x54,0x00,0x00,0x00,0x00};
unsigned char CiLiGu_No_Cooling_Mov[] = {0xC7,0x46,0x54,0xDC,0x05,0x00,0x00};
LPVOID targetAddr = (LPVOID)(baseAddr+CiLiGu_No_Cooling_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,CiLiGu_No_Cooling_New_Mov,sizeof(CiLiGu_No_Cooling_New_Mov));
} else {
Memory_Modification(hProcess,targetAddr,CiLiGu_No_Cooling_Mov,sizeof(CiLiGu_No_Cooling_Mov));
}
break;
}
//【毁灭菇爆炸无弹坑】
case ID_CHECKBOX_HUIMIEGU_BOBM_NO_PIT: {
DWORD_PTR HuiMieGu_Bobm_No_Pit_Offset = 0x74D27;
unsigned char HuiMieGu_Bobm_No_Pit_New_Move[] = {0xC7,0x40,0x18,0x00,0x00,0x00,0x00};
unsigned char HuiMieGu_Bobm_No_Pit_Move[] = {0xC7,0x40,0x18,0x50,0x46,0x00,0x00};
LPVOID targetAddr = (LPVOID)(baseAddr+HuiMieGu_Bobm_No_Pit_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,HuiMieGu_Bobm_No_Pit_New_Move,sizeof(HuiMieGu_Bobm_No_Pit_New_Move));
} else {
Memory_Modification(hProcess,targetAddr,HuiMieGu_Bobm_No_Pit_Move,sizeof(HuiMieGu_Bobm_No_Pit_Move));
}
break;
}
//【土豆地雷无CD】
case ID_CHECKBOX_POTATO_BOBM_NO_TIME:{
DWORD_PTR Potato_Bobm_No_Time_Offset = 0x6C679;
unsigned char Potato_Bobm_No_Time_New_Mov[] = {0xC7,0x40,0x54,0x00,0x00,0x00,0x00};
unsigned char Potato_Bobm_No_Time_Mov[] = {0xC7,0x40,0x54,0xDC,0x05,0x00,0x00};
LPVOID targetAddr = (LPVOID)(baseAddr+Potato_Bobm_No_Time_Offset);
if(flag==1){
Memory_Modification(hProcess,targetAddr,Potato_Bobm_No_Time_New_Mov,sizeof(Potato_Bobm_No_Time_New_Mov));
}else{
Memory_Modification(hProcess,targetAddr,Potato_Bobm_No_Time_Mov,sizeof(Potato_Bobm_No_Time_Mov));
}
break;
}
//【种植植物无需阳光】
case ID_CHECKBOX_ADD_PLANT_NO_SUN:{
DWORD_PTR Add_Plant_No_Sun_Offset = 0x27694;
unsigned char Add_Plant_No_Sun_New_Mov[] ={0x90,0x90};
unsigned char Add_Plant_No_Sun_Mov[] = {0x2B,0xF3};
LPVOID targetAddr = (LPVOID)(baseAddr+Add_Plant_No_Sun_Offset);
if(flag==1){
Memory_Modification(hProcess,targetAddr,Add_Plant_No_Sun_New_Mov,sizeof(Add_Plant_No_Sun_New_Mov));
}else{
Memory_Modification(hProcess,targetAddr,Add_Plant_No_Sun_Mov,sizeof(Add_Plant_No_Sun_Mov));
}
break;
}
}
}
//僵尸功能
void Zombies(HANDLE hProcess , int char_order,int flag, DWORD_PTR baseAddr) {
switch(char_order) {
case ID_CHECKBOX_ZOMBIES_KILL: {
DWORD_PTR Zombies_kill_Offset = 0x14D0BA;
unsigned char Zombies_kill_Xor[] = {0x31,0xED,0x90,0x90};
unsigned char Zombies_kill_Sub[] = {0x2B,0x6C,0x24,0x20};
LPVOID targetAddr = (LPVOID)(baseAddr + Zombies_kill_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,Zombies_kill_Xor,sizeof(Zombies_kill_Xor));
} else {
Memory_Modification(hProcess,targetAddr,Zombies_kill_Sub,sizeof(Zombies_kill_Sub));
}
break;
}
case ID_CHECKBOX_ZOMBIES_PROTECT_KILL: {
DWORD_PTR Zombies_Protect_kill_Offset = 0x14CDD4;
unsigned char Zombies_Protect_kill_Xor[] = {0x31,0xC9};
unsigned char Zombies_Protect_kill_Sub[] = {0x2B,0xC8};
LPVOID targetAddr = (LPVOID)(baseAddr + Zombies_Protect_kill_Offset);
if(flag==1) {
Memory_Modification(hProcess,targetAddr,Zombies_Protect_kill_Xor,sizeof(Zombies_Protect_kill_Xor));
} else {
Memory_Modification(hProcess,targetAddr,Zombies_Protect_kill_Sub,sizeof(Zombies_Protect_kill_Sub));
}
break;
}
}
}
//其它功能
void Other(HANDLE hProcess,int char_order,int flag,DWORD_PTR baseAddr) {
switch(char_order) {
case ID_CHECKBOX_MIST_PERSPECTIVE: {
DWORD_PTR Mist_Perspective_Offset1 = 0x26157;
DWORD_PTR Mist_Perspective_Offset2 = 0x26160;
unsigned char Mist_Perspective_New_Mov1[] = {0xBA, 0x64, 0x00, 0x00, 0x00};
unsigned char Mist_Perspective_New_Mov2[] = {0xBA, 0x64, 0x00, 0x00, 0x00};
unsigned char Mist_Perspective_Mov1[] = {0xBA, 0xFF, 0x00, 0x00, 0x00};
unsigned char Mist_Perspective_Mov2[] = {0xBA, 0xC8, 0x00, 0x00, 0x00};
LPVOID targetAddr1 = (LPVOID)(baseAddr + Mist_Perspective_Offset1);
LPVOID targetAddr2 = (LPVOID)(baseAddr + Mist_Perspective_Offset2);
if(flag==1) {
Memory_Modification(hProcess,targetAddr1,Mist_Perspective_New_Mov1,sizeof(Mist_Perspective_New_Mov1));
Memory_Modification(hProcess,targetAddr2,Mist_Perspective_New_Mov2,sizeof(Mist_Perspective_New_Mov2));
} else {
Memory_Modification(hProcess,targetAddr1,Mist_Perspective_Mov1,sizeof(Mist_Perspective_Mov1));
Memory_Modification(hProcess,targetAddr2,Mist_Perspective_Mov2,sizeof(Mist_Perspective_Mov2));
}
break;
}
}
}
//内存修改
void Memory_Modification(HANDLE hProcess, LPVOID targetAddr, unsigned char* compile_order, size_t order_sizeof) {
DWORD oldProtect;
//修改权限
VirtualProtectEx(hProcess,targetAddr,order_sizeof,PAGE_EXECUTE_READWRITE,&oldProtect);
//写入逻辑
WriteProcessMemory(hProcess,targetAddr,compile_order,order_sizeof,NULL);
//还原权限
VirtualProtectEx(hProcess,targetAddr,order_sizeof,oldProtect,&oldProtect);
}
【火炬之光2】
最后提一下火炬之光2,因为火炬之光这个功能写的最少,所以放到最后,写出几个功能后,后面的功能都是差不多的逻辑,
因为还有其它的东西需要学习,火炬2就不往下写了先,后面可能会写GTA、生化危机6/8、魔兽争霸的修改器,看时间情况了。
火炬2和德军总部差不多,共用体前面已经说过了,重要的就是找出玩家的NPC的区分,虽然函数是共用体但是指针指向和偏移是不同的,所以
也是能无敌的,火炬2这里直接上代码了,写了一下午有点累了确实。
能熟悉德军总部,火炬2这里是相同的,定时器锁血、火炬2的偏移应该比德军总部多一层好像。
三款游戏的修改器都还有没做完整的地方,大概功能是有了,有感觉兴趣往下写的大佬写完可以联动一波,互相学习,补充不足。
[C] 纯文本查看 复制代码 #include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#define TIMER_GODMODE 1001 // 角色无敌定时器
#define TIMER_MANA 1002 // 角色无限魔法定时器
#define PET_TIMER_GODMODE 1003 // 宠物无敌定时器
#define PET_TIMER_MANA 1004 // 宠物无限魔法定时器
#define ID_CHK_GOD 2001 // 角色无敌
#define ID_CHK_MANA 2002 // 无限魔法
#define ID_BTN_GOLD 2003 // 加999金币
#define ID_PET_GOD 2004 // 宠物无敌
#define ID_PET_MANA 2005 // 宠物无限魔法
#define ID_KILL_ENEMY 2006 // 秒杀怪物
#define ID_MAX_ATTACK 2007 // 爆发攻击力
#define ID_ENETY_NO_DIE 2008 // 怪物无敌
#define ID_MAX_ATTACK_SPEED 2009 // 最大攻击速递
#define ID_MANA_NO_DELAY 3001 // 施法无延迟
#define ID_GOD_PERSPECTIVE 3002 // 上帝视角
#define ID_EXP_DOUBLE 3003 // 经验值翻倍
#define ID_AUTO_PICK_UP 3004 // 自动拾取
#define ID_MAX_ATTACK_SCOPE 3005 // 最大攻击范围
HANDLE hProcess = NULL;
DWORD_PTR moduleBase = 0;
DWORD_PTR basePointerOffset = 0x024E95F4;
/**
*角色
**/
DWORD_PTR midle_offset = 0x2C;
DWORD_PTR offHP = 0x560;
DWORD_PTR offMP = 0x584;
DWORD_PTR offGold = 0x590;
/**
*宠物
**/
DWORD_PTR pet_midle_offset = 0x30;
DWORD_PTR pet_offHP = 0x560;
DWORD_PTR pet_offMP = 0x584;
/**
*怪物
**/
/**
*其它
**/
DWORD GetPidByName(const char *processName);
DWORD_PTR GetModuleBaseAddress(DWORD procId, const char *modName);
DWORD_PTR GetRealAddr(DWORD propertyOffset, DWORD entityOffset);
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_CREATE:
{
const char *processName = "Torchlight2.exe";
DWORD pid = GetPidByName(processName);
if (pid == 0)
{
MessageBox(hwnd, "未找到游戏,请先运行游戏", "提示", MB_OK | MB_ICONWARNING);
return 0;
}
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL)
{
DWORD error = GetLastError();
char errBuf[64];
sprintf(errBuf, "无法打开进程,错误代码:%lu", GetLastError());
MessageBox(hwnd, errBuf, "提示", MB_OK | MB_ICONERROR);
return 0;
}
else
{
MessageBox(hwnd, "连接游戏成功", "提示", MB_OK);
}
// 获取模块基址
moduleBase = GetModuleBaseAddress(pid, processName);
if (moduleBase == 0)
{
MessageBox(hwnd, "无法获取游戏模块基址!", "提示", MB_OK);
}
else
{
MessageBox(hwnd, "修改器已成功挂载到游戏!", "成功", MB_OK);
}
// 【角色无敌】
CreateWindow("BUTTON", "人物无敌",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 20, 120, 30,
hwnd, (HMENU)ID_CHK_GOD, NULL, NULL);
// 【角色无限魔法】
CreateWindow("BUTTON", "无限魔法",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 60, 120, 30,
hwnd, (HMENU)ID_CHK_MANA, NULL, NULL);
// 【一键加999金币】
CreateWindow("BUTTON", "加999金币",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 100, 120, 30,
hwnd, (HMENU)ID_BTN_GOLD, NULL, NULL);
// 【宠物无敌】
CreateWindow("BUTTON", "宠物无敌",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 140, 120, 30,
hwnd, (HMENU)ID_PET_GOD, NULL, NULL);
// 【宠物无限魔法】
CreateWindow("BUTTON", "宠物无限魔法",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 180, 120, 30,
hwnd, (HMENU)ID_PET_MANA, NULL, NULL);
// 【秒杀怪物】
CreateWindow("BUTTON", "秒杀怪物",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 220, 120, 30,
hwnd, (HMENU)ID_KILL_ENEMY, NULL, NULL);
// 【爆发攻击力】
CreateWindow("BUTTON", "爆发攻击力",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 260, 120, 30,
hwnd, (HMENU)ID_MAX_ATTACK, NULL, NULL);
// 【怪物无敌】
CreateWindow("BUTTON", "怪物无敌",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 300, 120, 30,
hwnd, (HMENU)ID_ENETY_NO_DIE, NULL, NULL);
// 【人物最大攻速】
CreateWindow("BUTTON", "人物最大攻速",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 300, 120, 30,
hwnd, (HMENU)ID_MAX_ATTACK_SPEED, NULL, NULL);
// 【施法无延迟】
CreateWindow("BUTTON", "施法无延迟",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
20, 340, 120, 30,
hwnd, (HMENU)ID_MANA_NO_DELAY, NULL, NULL);
// 【上帝视角】
CreateWindow("BUTTON", "上帝视角",
20, 380, 120, 30,
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
hwnd, (HMENU)ID_GOD_PERSPECTIVE, NULL, NULL);
// 【经验值翻倍】
CreateWindow("BUTTON", "经验值翻倍",
20, 420, 120, 30,
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
hwnd, (HMENU)ID_EXP_DOUBLE, NULL, NULL);
// 【自动拾取】
CreateWindow("BUTTON", "自动拾取",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
180, 20, 120, 30,
hwnd, (HMENU)ID_AUTO_PICK_UP, NULL, NULL);
// 【最大攻击范围】
CreateWindow("BUTTON", "最大攻击范围",
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
180, 60, 120, 30,
hwnd, (HMENU)ID_MAX_ATTACK_SCOPE, NULL, NULL);
break;
}
case WM_COMMAND:
// 【角色无敌】
if (LOWORD(wParam) == ID_CHK_GOD)
{
if (IsDlgButtonChecked(hwnd, ID_CHK_GOD))
{
SetTimer(hwnd, TIMER_GODMODE, 50, NULL);
}
else
{
KillTimer(hwnd, TIMER_GODMODE);
}
}
// 【无限魔法】
if (LOWORD(wParam) == ID_CHK_MANA)
{
if (IsDlgButtonChecked(hwnd, ID_CHK_MANA))
{
SetTimer(hwnd, TIMER_MANA, 50, NULL);
}
else
{
KillTimer(hwnd, TIMER_MANA);
}
}
// 【一键加999金币】
if (LOWORD(wParam) == ID_BTN_GOLD)
{
DWORD_PTR goldAddr = GetRealAddr(offGold, 0);
if (goldAddr)
{
int currentGold = 0;
ReadProcessMemory(hProcess, (LPVOID)goldAddr, ¤tGold, sizeof(int), NULL);
currentGold += 999;
WriteProcessMemory(hProcess, (LPVOID)goldAddr, ¤tGold, sizeof(int), NULL);
}
}
// 【宠物无敌】
if (LOWORD(wParam) == ID_PET_GOD)
{
if (IsDlgButtonChecked(hwnd, ID_PET_GOD))
{
SetTimer(hwnd, PET_TIMER_GODMODE, 50, NULL);
}
else
{
KillTimer(hwnd, PET_TIMER_GODMODE);
}
}
// 【宠物无限魔法】
if (LOWORD(wParam) == ID_PET_MANA)
{
if (IsDlgButtonChecked(hwnd, ID_PET_MANA))
{
SetTimer(hwnd, PET_TIMER_MANA, 50, NULL);
}
else
{
KillTimer(hwnd, PET_TIMER_MANA);
}
}
// 【秒杀敌军】
// if(LOWORD(wParam)==ID_KILL_ENEMY) {
// DWORD_PTR Kill_enemy = GetRealAddr();
// if(Kill_enemy) {
//
// }
// }
break;
case WM_TIMER:
// 【角色无敌】
if (wParam == TIMER_GODMODE)
{
DWORD_PTR hpAddr = GetRealAddr(offHP, midle_offset);
if (hpAddr)
{
float val = 1019.0f;
WriteProcessMemory(hProcess, (LPVOID)hpAddr, &val, 4, NULL);
}
}
// 【无限魔法】
if (wParam == TIMER_MANA)
{
DWORD_PTR mpAddr = GetRealAddr(offMP, midle_offset);
if (mpAddr)
{
float val = 78.0f;
WriteProcessMemory(hProcess, (LPVOID)mpAddr, &val, 4, NULL);
}
}
// 【宠物无敌】
if (wParam == PET_TIMER_GODMODE)
{
DWORD_PTR pet_hpAddr = GetRealAddr(pet_offHP, pet_midle_offset);
if (pet_hpAddr)
{
float val = 1477.0f;
WriteProcessMemory(hProcess, (LPVOID)pet_hpAddr, &val, 4, NULL);
}
}
// 【宠物无限魔法】
if (wParam == PET_TIMER_MANA)
{
DWORD_PTR pet_mpAddr = GetRealAddr(pet_offMP, pet_midle_offset);
if (pet_mpAddr)
{
float val = 100.0f;
WriteProcessMemory(hProcess, (LPVOID)pet_mpAddr, &val, 4, NULL);
}
}
break;
/* Upon destruction, tell the main thread to stop */
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
/* All other messages (a lot of them) are processed using default procedures */
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc; /* A properties struct of our window */
HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
MSG msg; /* A temporary location for all messages */
/* zero out the struct and set the stuff we want to modify */
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc; /* This is where we will send messages to */
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
/* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = "WindowClass";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon */
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "WindowClass", "火炬之光2 V1.25.9.5修改器", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /* x */
CW_USEDEFAULT, /* y */
640, /* width */
480, /* height */
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
/*
This is the heart of our program where all input is processed and
sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
this loop will not produce unreasonably high CPU usage
*/
while (GetMessage(&msg, NULL, 0, 0) > 0)
{ /* If no error is received... */
TranslateMessage(&msg); /* Translate key codes to chars if present */
DispatchMessage(&msg); /* Send it to WndProc */
}
return msg.wParam;
}
// 获取玩家的真实血量/魔法值地址辅助函数
DWORD_PTR GetRealAddr(DWORD propertyOffset, DWORD entityOffset)
{
if (!hProcess || !moduleBase)
{
return 0;
}
DWORD_PTR p1 = 0, p2 = 0;
DWORD_PTR absoluteBaseAddr = moduleBase + basePointerOffset;
if (!ReadProcessMemory(hProcess, (LPCVOID)absoluteBaseAddr, &p1, 4, NULL))
return 0;
if (!ReadProcessMemory(hProcess, (LPCVOID)(p1 + entityOffset), &p2, 4, NULL))
return 0;
return p2 + propertyOffset;
}
//
DWORD_PTR GetModuleBaseAddress(DWORD procId, const char *modName)
{
DWORD_PTR modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (strcmp(modEntry.szModule, modName) == 0)
{
modBaseAddr = (DWORD_PTR)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
CloseHandle(hSnap);
}
return modBaseAddr;
}
// 获取目标进程pid
DWORD GetPidByName(const char *processName)
{
DWORD pid = 0;
// 创建系统快照
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
// 遍历进程
if (Process32First(hSnapshot, &pe))
{
do
{
if (strcmp(pe.szExeFile, processName) == 0)
{
pid = pe.th32ProcessID;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
}
return pid;
}
【写在最后】
三款游戏的修改器打包放在下面了,有刚好玩三款游戏的大佬可以用用看看,给提出建议和不足,源码上面已经有了,源文件就不放了。
某60可能会报毒
目前火绒是不报的
需要以管理身份运行
修改器.rar
(136.62 KB, 下载次数: 17)
|
免费评分
-
查看全部评分
|