本文是助手 UI 逆向专题的总汇总,把「角色配置 → UI 资源 → 控件 ID 链路 → 点击分派 → 功能 CALL」六层证据链合并去重。原 6 份分散材料(辅助配置汇总.csv/md、助手UI分析报告、助手UI点击调用点分析、助手CALL调用链反汇编、控件ID获取链路分析)均已并入,原件已清理,本文为唯一权威版本。
分析对象:
D:\rxjh2025\client\YGOnline.exe(ImageBase 0x400000,32 位)。客户端带 XIGNCODE 反作弊,动态调试/修改仅限单机或私服环境。
配置层 角色配置 csv/UserConfig.ini(88 字段,[shitou]+[config] 两节)
↓
资源层 interface 素材 220 个 + exe 内嵌引用 2250 条(界面无配置文件,全硬编码在 exe)
↓
控件层 控件对象 0x548 字节,控件 ID 编译期硬编码,存 [+0x364](变体 +0x370 / +0x440)
↓
通知层 点击 → 引擎读 ID 当 wParam,msg=0x3F4,虚调用父窗口槽 #1(call [虚表+4])
↓
分派层 0x68B2B0(InterInGameTotalShop):cmp [ebp+0xC], ID → 跳对应功能函数
↓
功能层 0x31→0xD7DA60 启动挂机 · 0x32→0xCD9FE0 停止 · 0x33→0x6917D0 设置 · 0x34→0x690140 关闭
[shitou] 金刚石/寒玉石洗练门槛(各角色几乎一致);[config] 挂机坐标/回补/购买/开关项35转职任务.ini 共 52 航点| 项 | 值 |
|---|---|
| 挂机地图 | 全部泫渤派(除一明天一坐标 -2048/-1594,其余 369/1589) |
| 生命下限 | 500 |
| 内功下限 | 300 |
| 自动开关 | 大多数为 0 |
| 差异项 | 范围 |
|---|---|
| 回城命令 | 只有美美/霸王花 = 1 |
| 接受组队 | 前四个角色开启 |
| 蓝药总数选择框 / 维持强化 / 幸运符 / 购买满包 | 只有至尊五花肉 = 1 |
interface 资源 220 个 + exe 内嵌引用 2250 条,按模块分组:
| 模块 | 素材 | 说明 |
|---|---|---|
| 挂机助手 | 主窗口 26(window_auto01-06 等)、按钮 56(auto_play/stop/setup/close 等) | 本专题主角 |
| 自动摆摊 AutoSell | 61 | |
| 召唤/召回 | 15 | |
| 结婚系统 | 60 | |
| 炸弹/毒药自动 | 2 |
结论:界面无配置文件,资源名/控件 ID/文本 ID 全部硬编码在 exe 内。
核心结论:控件 ID(0x31~0x34 等)是编译期硬编码的立即数。
0xA2DCC0):push 0x31 与 push <资源名指针> 配对硬编码,8 个参数压栈调工厂;不存在"从配置读 ID"的机制,改 ID 只能改 exe。0x609410:两个分支——无父容器直接 new;有父容器时把相对坐标加容器 x/y 转绝对坐标(控件 x/y 是流式布局增量)。operator new(0x548) = 1352 字节控件对象。0xCB2BD0:ID 存 [+0x364];它调用的基类构造 0xA4D800 与助手窗口用同一个——窗口和按钮是同一基类的不同派生,共用 [+0]虚表 / [+4]父指针 布局,这是点击通知能用同一套虚表槽机制的原因。0xCB3B8A):mov edx, [ecx+0x364] → push 当 wParam;另有 +0x370(0xCB7317)、+0x440(0xCBD5C8)两个变体 = 三种控件变体(普通按钮/列表项/特殊控件)。0x68B2B0:[ebp+0xC] = 控件 ID,除 0x31~0x34 外还处理 0x2C、0x35~0x3C、0x3ED/0x3EE、3/8 等;msg >= 0x435 走跳转表 0x68EDC8。0xC53990 文本管理器,文本基址 0x183C520)。+0x364 不会变:构造时写一次,之后只读;旁边 +0x350~+0x360 是布局运行时数据,勿混淆。add esp,0x20 = 8 个 dword。按钮点击不是 MFC 消息映射,而是三步式虚调用:
push lParam ; 0
push wParam ; 控件 ID(如 0x31)
push 0x3F4 ; msg
mov ecx, [this+4] ; 取父窗口指针
call [虚表+4] ; 槽 #1 → 0x68B2B0
__thiscall(ret 0xC)push 0x3F4 全 exe 精确 235 处,与反汇编报告完全吻合0x31→call 0xD7DA60 启动挂机、0x32→0xCD9FE0 停止、0x33→0x6917D0 打开设置、0x34→0x690140 关闭窗口| 控件 ID | 资源名 | 含义 | 登记点 VA | 存放偏移 |
|---|---|---|---|---|
| 0x31 | auto_play | 开始挂机 | 0xA2E3E6 | +0x364 |
| 0x32 | auto_stop | 停止挂机 | 同上区域 | +0x364 |
| 0x33 | auto_setup | 设置 | 同上区域 | +0x364 |
| 0x34 | auto_close | 关闭窗口 | 同上区域 | +0x364 |
| 0x35 | auto_btn_save | 保存(双态) | 0xA2EB83 | this+0x3940 |
| 0x36 | cancel_click | 取消 | 0xA2EBF6 | this+0x3800 |
| 0xA3 | ok_click | 弹窗确定 | 0xA2F4D9 | —(文本 0x187B) |
| 0xA4 | cancel_click | 弹窗取消 | 0xA2F54F | —(文本 0x187B) |
| 0xA5 | window_auto_check.bmp | 勾选框 | 0xA2F792 | — |
| 0x94 | auto_save | 设置窗保存 | 0xA3C6BC | 0x4E8 |
| 0x97 | auto_exit | 设置窗退出 | 0xA3C713 | 0x4EC |
| 0x76 | Premuim | 高级付费按钮 | 0xA46FA0 | this+0x43C(文本 0xF83) |
结构性控件:主容器 window_head.bmp 存 this+0x36C0(与 push [ecx+0x36C0] 互证);6 张背景页;字幕页签(每页局部 ID 0x1~0x5);设置窗 11 个页签(存数组 this+i*4+0x4F0)。
边界:0xA3/A4/A5、0x94/0x97、0x76 不走 0x68B2B0——属设置窗/子弹窗,由各自窗口类 WndProc 分派(InterAutoPlay 自己的 0xA3F3D0 用跳转表)。对这些 ID 调用前必须先确认目标窗口实例。
| 函数 | VA |
|---|---|
| InterAutoPlay 构造(ID 源头) | 0xA2DCC0 |
| 控件工厂 | 0x609410 |
| 控件构造(ID→+0x364) | 0xCB2BD0 |
| 公共基类构造 | 0xA4D800 |
| 引擎取 ID(三变体) | 0xCB3B8A / 0xCB7317 / 0xCBD5C8 |
| 通知分派函数(虚表 0x1079A6C) | 0x68B2B0 |
| InterAutoPlay WndProc | 0xA3F3D0 |
| 文本管理器 / 文本基址 | 0xC53990 / 0x183C520 |
| 大 msg 跳转表 | 0x68EDC8 |
| 功能 | VA |
|---|---|
| 启动挂机(命令 0x31) | 0xD7DA60 |
| 停止挂机(命令 0x32) | 0xCD9FE0 |
| 打开设置(命令 0x33) | 0x6917D0 |
| 关闭窗口(命令 0x34) | 0x690140 |
| 项 | 值 |
|---|---|
| NPC 对话对象 | [NPC基址] + 0x414 |
| 助手窗口指针 | [对话对象 + 0x34B4] |
| 双层分发函数 | 0xA3F700(选项码 0x0B~0xA3,跳转表 0xA41588 / 字节索引 0xA41698) |
| 公共出口 | 0xA41204 |
8B 91 EC 03 00 00 8B 82 90 03 00 00 0F B6 88 C8 06 00 00 85 C9 → 命中 0x6679558D 4C 02 FF 8B 55 FC 8B 82 B4 34 00 00 89 48 2C → 命中 0xA3E676(+0x108A = 0xA3F700)ybui_callscan.py 6 条验证命令:disasm 各函数 + rtti 解析两张虚表类名bp 基址+0x28B2B0 看 [ebp+8] 是否 = 1012(0x3F4)0xD7DA60 启动挂机的发包逻辑(UI 点击 → 服务器协议的最后一环)UserConfig.ini 88 字段的写入关系(0x94/0x97 分支)push 0x3F4 调用者分组(除助手窗口外还有哪些 UI 复用同一通知机制)