════════════════════════════════════════════════════════════ 助手调用验证 · 易语言示例(贴进你的辅助工程即跑) 前提:DLL 注入方式运行于游戏进程内(跟你寻路call同环境), 工程里已有 全局_进程句柄、#NPC基址值、内存_读整数型、 十六到十、十到十六、调试输出。 验证什么: ① 指针链逐环打印(哪环断了看得一清二楚): NPC对话对象 →(+0x34B4)→ 助手窗口 →(+0x3938)→ 开始按钮 →(+0x364)控件ID(应=49) →(+4)父窗口 →(+0)虚表(应=基址+0xC79A68) ② 测试1/2:新路 call [父窗口虚表+4](0x68b2b0)发 0x31/0x32 ③ 测试3:你已验证的旧路 0xA3F700 做对照 ⚠ 请在游戏主线程环境调用本子程序(同你寻路call的调用时机) ════════════════════════════════════════════════════════════ .版本 2 .DLL命令 API_取模块句柄, 整数型, "kernel32.dll", "GetModuleHandleA" .参数 模块名, 文本型 ' ──────────────────────────────────────────── ' 主测试子程序:游戏中挂机状态随便什么时候调用都行 ' ──────────────────────────────────────────── .子程序 测试_助手调用验证, , 公开 .局部变量 基址, 整数型 .局部变量 NPC对象, 整数型 .局部变量 助手窗口, 整数型 .局部变量 开始按钮, 整数型 .局部变量 控件ID, 整数型 .局部变量 父窗口, 整数型 .局部变量 虚表, 整数型 .局部变量 期望虚表, 整数型 基址 = API_取模块句柄 ("YGOnline.exe") .如果真 (基址 = 0) 基址 = 4194304 ' 0x400000 .如果真结束 调试输出 ("[0] 基址=" + 十到十六 (基址)) ' ---- 环1:NPC对话对象(你旧路在用的同一条链)---- NPC对象 = 内存_读整数型 (全局_进程句柄, 内存_读整数型 (全局_进程句柄, #NPC基址值) + 十六到十 ("414")) 调试输出 ("[1] NPC对话对象=" + 十到十六 (NPC对象)) .如果真 (NPC对象 = 0 或 NPC对象 = -1) 调试输出 ("×环1断:NPC基址链读失败") 返回 () .如果真结束 ' ---- 环2:助手窗口(对话对象+0x34B4,特征码上下文里的成员)---- 助手窗口 = 内存_读整数型 (全局_进程句柄, NPC对象 + 十六到十 ("34B4")) 调试输出 ("[2] 助手窗口(+34B4)=" + 十到十六 (助手窗口)) .如果真 (助手窗口 = 0) 调试输出 ("×环2断:+34B4 为 0") 返回 () .如果真结束 ' ---- 环3:开始按钮 + 控件ID(应=49 即 0x31)---- 开始按钮 = 内存_读整数型 (全局_进程句柄, 助手窗口 + 十六到十 ("3938")) 控件ID = 内存_读整数型 (全局_进程句柄, 开始按钮 + 十六到十 ("364")) 调试输出 ("[3] 开始按钮=" + 十到十六 (开始按钮) + " 控件ID=" + 到文本 (控件ID) + "(期望49)") .如果真 (控件ID ≠ 49) 调试输出 ("×环3断:+34B4 指向的不是助手窗口(把上面几行发我)") 返回 () .如果真结束 ' ---- 环4:父窗口 + 虚表校验(应=基址+0xC79A68)---- 父窗口 = 内存_读整数型 (全局_进程句柄, 开始按钮 + 4) 虚表 = 内存_读整数型 (全局_进程句柄, 父窗口) 期望虚表 = 基址 + 十六到十 ("C79A68") 调试输出 ("[4] 父窗口=" + 十到十六 (父窗口)) 调试输出 ("[5] 虚表=" + 十到十六 (虚表) + " 期望=" + 十到十六 (期望虚表)) .如果真 (虚表 ≠ 期望虚表) 调试输出 ("×环4断:父窗口不是总控窗口,新路不可用(把[3][4][5]发我)") 返回 () .如果真结束 ' ---- 测试1:新路 发 0x31 开始挂机 ---- 调试输出 (">> 测试1:新路 call [虚表+4] 发 0x31(看游戏是否开始挂机)") 新路_发UI命令 (父窗口, 49) 延时 (3000) ' ---- 测试2:新路 发 0x32 停止挂机 ---- 调试输出 (">> 测试2:新路发 0x32(看挂机是否停止)") 新路_发UI命令 (父窗口, 50) 延时 (3000) ' ---- 测试3:新路再开(确认可反复)---- 调试输出 (">> 测试3:新路再发 0x31") 新路_发UI命令 (父窗口, 49) 延时 (3000) ' ---- 测试4:旧路对照(你已验证的写法原样跑一遍)---- 调试输出 (">> 测试4:旧路 0xA3F700 + 0x31 对照") 旧路_开助手 () 调试输出 ("全部完成,把控制台 5 行指针值 + 游戏反应告诉我") ' ──────────────────────────────────────────── ' 新路:置入机器码,call [父窗口虚表+4] ' 全静态字节,不依赖任何 call 地址/基址, ' 动态值只有 ecx(参数1=父窗口地址在 [ebp+8]) ' ──────────────────────────────────────────── .子程序 新路_发UI命令, , 公开 .参数 父窗口地址, 整数型 .参数 命令ID, 整数型 置入代码 ({ 96 }) ' pushad 置入代码 ({ 106, 0 }) ' push 0 lParam 置入代码 ({ 255, 117, 12 }) ' push [ebp+0xC] wParam=命令ID 置入代码 ({ 104, 244, 3, 0, 0 }) ' push 0x3F4 msg=1012 置入代码 ({ 139, 77, 8 }) ' mov ecx,[ebp+8] this=父窗口 置入代码 ({ 139, 17 }) ' mov edx,[ecx] edx=虚表 置入代码 ({ 255, 82, 4 }) ' call [edx+4] ★槽#1=0x68B2B0 置入代码 ({ 97 }) ' popad ' ──────────────────────────────────────────── ' 旧路:你已验证的 0xA3F700 写法(对照用,原样保留) ' 注意:ECX 必须保持是本子程序第一个局部变量([ebp-4]) ' ──────────────────────────────────────────── .子程序 旧路_开助手, , 公开 .局部变量 ECX, 整数型 ECX = 内存_读整数型 (全局_进程句柄, 内存_读整数型 (全局_进程句柄, #NPC基址值) + 十六到十 ("414")) .如果真 (ECX = 0 或 ECX = -1) 返回 () .如果真结束 置入代码 ({ 96 }) ' pushad 置入代码 ({ 106, 0 }) ' push 0 置入代码 ({ 106, 49 }) ' push 0x31 置入代码 ({ 139, 77, 252 }) ' mov ecx,[ebp-4] ECX=第一个局部变量 置入代码 ({ 184, 0, 247, 163, 0 }) ' mov eax,0xA3F700 置入代码 ({ 255, 208 }) ' call eax 置入代码 ({ 97 }) ' popad ' ──────────────────────────────────────────── ' 验证结果怎么判读(跑完对照): ' ① 5 行指针值全通 + 测试1~3 游戏有反应 ' → 新路成立,以后可以不用硬编码任何 call 地址 ' ② 环3 就断(控件ID≠49) ' → +34B4 不是助手窗口,把值发我,我换成员偏移再找 ' ③ 环4 断(虚表≠期望) ' → 按钮的父窗口不是总控窗口,发我 [3][4][5] 的值 ' ④ 指针全对但游戏没反应 ' → 大概率调用线程不对,换到你寻路call同款时机再试 ' ────────────────────────────────────────────