# E2TXT 源码常量基址对照表 > **来源**:`D:\AI空间\rxjh\旧版本更新.代码\常量.e.txt`(E2TXT 1.2 反编译产物) > **对象**:`旧版本更新.e` 当前工程 > **目的**:把工程里**实际在用的常量基址**逐条列出来,并与《基址全量复验报告》的静态结论对表 > **生成**:2026-09-18 --- ## 一、结论速览 | 项 | 结果 | |---|---| | 常量总数 | **209** 条(含精易模块/魔鬼作坊模块带进来的通用常量) | | 其中地址类(≥ 0x1000) | **18** 条 | | 明确是**游戏内存基址** | **9** 条 | | 与静态复验对表 | **9/9 全部吻合** ✅ | | ★ 交叉互证 | `发包call地址值` / `发包Call_ECX值` = 静态从「NPC选项CALL基址」特征推出的同两个地址 | | 关键澄清 | `封包Eax基址` **不是基址**,是代码地址(发包取址点) | | ⚠ 发现 bug | `助手_发命令` 的 `.参数 控件地址` **丢了 `整数型`** → ④ 点控件必然失败(详见第八节) | | 额外收获 | 从内联偏移反推出一套完整的**对象字段结构表**(第五节) | **一句话**:工程里写死的 9 个游戏基址**全部经静态复验确认有效**;两个发包常量与独立特征路线**完全对得上**; 另外揪出一处会让「点控件」失效的类型声明缺失。 --- ## 二、地址类常量全表(18 条,按地址降序) | 常量名 | 十进制 | 十六进制 | 性质 | 工程内引用 | |---|---|---|---|---| | `坐标基址值` | 62859468 | `0x03BF28CC` | 人物对象基址 | 5 | | `人物基址值` | 62859468 | `0x03BF28CC` | 同上(**同址**) | 6 | | `怪物基址值` | 62799464 | `0x03BE3E68` | 实体数组基址 | 15 | | `商店基址值` | 62665660 | `0x03BC33BC` | ⚠ 静态 0 引用 | 3 | | `状态栏基址值` | 62535804 | `0x03BA387C` | BUFF/状态列表(当**列表基址**用) | 2 | | `凝神珠背包基址值` | 62512364 | `0x03B9DCEC` | 凝神珠背包 | 3 | | `背包基址值` | 62512352 | `0x03B9DCE0` | 物品容器 | **41** | | `当前血量值` | 60230256 | `0x03970A70` | 血量全局变量 | **74** | | `NPC基址值` | 25412908 | `0x0183C52C` | NPC 数组 + **助手链路头** | 9 | | `仓库基址值` | 25338588 | `0x0182A2DC` | ⚠ 静态 0 引用 | — | | `发包Call_ECX值` | 25097080 | `0x017EF378` | 发包 ECX 全局变量 | 1 | | `地图基址值` | 18743428 | `0x011E0084` | 当前地图 ID | 9 | | `发包call地址值` | 7782528 | `0x0076C080` | **代码地址**(发包 call 目标) | 1 | | `x坐标偏移值` | 8068 | `0x1F84` | 对象字段偏移 | 4 | | `y坐标偏移值` | 8076 | `0x1F8C` | 对象字段偏移 | 3 | > 另外 3 条是地图枚举(`虎峡谷 25100` / `南林 6001` / `冰宫 5001`),不是地址。 > `当前血量` = `"03970A70"`(**字符串**形式)与 `当前血量值` = `60230256`(**数值**形式)指向同一地址,是历史遗留的双写。 --- ## 三、与《基址全量复验报告》逐条对表 静态复验(`verify_all2.py`,含 SIB 变址修正后)给出的指令引用数 vs 本常量表: | 常量名 | 地址 | 静态引用数 | 判定 | 对表 | |---|---|---|---|---| | `怪物基址值` | `0x03BE3E68` | 1487 | ✅ | 一致 | | `人物基址值` / `坐标基址值` | `0x03BF28CC` | 2503 | ✅ | 一致(同址) | | `背包基址值` | `0x03B9DCE0` | 3417 | ✅ | 一致 | | `凝神珠背包基址值` | `0x03B9DCEC` | 78 | ✅ | 一致 | | `状态栏基址值` | `0x03BA387C` | 897 | ✅ | 一致 | | `地图基址值` | `0x011E0084` | 3 | ✅(引用极少,需活体验证) | 一致 | | `NPC基址值` | `0x0183C52C` | 10268 | ✅ | 一致 | | `仓库基址值` | `0x0182A2DC` | **0** | ⚠ 待复核 | 一致(静态也是 0) | | `商店基址值` | `0x03BC33BC` | **0** | ⚠ 待复核 | 一致(静态也是 0) | **九条全部对上**,没有一条工程常量与静态结论矛盾 —— 说明这套静态判据是可靠的。 --- ## 四、★ 两条「非基址」常量的真面目 ### 4.1 `发包call地址值` = `0x0076C080` —— 不是基址,是函数地址 静态复验的 B 组特征里有一条 **`NPC选项CALL基址`**,走 call 类规则: ``` 命中点 0x00C79138 → +adj 0x00C79154 → 读到 rel32 = 0xFFAF2F28 (-0x50D0D8) 目标 = 0x00C79154 + 4 + (-0x50D0D8) = 0x0076C080 ← 与常量表完全一致 ✅ ``` ### 4.2 `发包Call_ECX值` = `0x017EF378` —— 同一个特征的另一半 静态复验里同一条特征的 **`NPC选项基址`**: ``` 命中点 0x00C79138 → +adj 0x00C7914F → 读出 0x017EF378 ← 与常量表完全一致 ✅ ``` ### 4.3 工程里怎么用这两个常量 `发包Call` → `置入发包`(`窗口程序集_MainDialogWnd.form.e.txt:9769`)机器码原文等价于: ```asm push [ebp+8] ; 封包长度 push [ebp+12] ; 封包指针 mov ecx, [ebp+16] ; #发包Call_ECX值 的地址 mov ecx, [ecx] ; ecx = [0x017EF378] cmp ecx, 0x10000 jg +4 leave ; ret 0x10 ; ecx 太小 → 不进游戏、直接返回 call [ebp+20] ; call [0x0076C080] leave ; ret 0x10 ``` > **这是本次最有价值的一条互证**:一条静态特征路线(字节搜索 + rel32 解析)与工程里写死的两个常量, > 独立地指向**同两个地址**。两条路都走通了 → 这两个发包入口可以放心用。 --- ## 五、代码内联偏移 —— 对象字段结构(新收获) 除常量外,代码里还有 35 个内联 `十六到十("…")` 字面量。整理出这套对象字段图: ### 5.1 对象类型标识(`对象+8`) | 值 | 含义 | 出处 | |---|---|---| | `0x2E` | **怪物** | `if 读整数(对象+8) == 0x2E`(8 处) | | `0x31` | **人物** | `if 读整数(对象+8) == 0x31` ' 31=人物 | > ⚠ 注意:`0x31` 在**对象类型**里是「人物」,在**助手控件 ID** 里是「开始挂机」。两套体系,别混。 ### 5.2 人物对象(type = `0x31`) | 偏移 | 内容 | |---|---| | `+0x18` | 名字(文本,BIG5) | | `+0xC` | 对象ID | ### 5.3 怪物/通用对象(type = `0x2E`) | 偏移 | 内容 | 备注 | |---|---|---| | `+0xC` | 槽位 ID | | | `+0x14` | 全服 ID(发包值) | | | `+0x74` / `+0x78` | 当前血 / 最大血 | 旧一套 | | `+0x364` | **名字**(文本,BIG5) | | | `+0x5F4` / `+0x5F8` / `+0x5FC` | 当前血 / 最大血 / 等级 | 新一套 | | `+0x1F84` / `+0x1F8C` | 坐标 X / Y(**小数**) | 与 `#x坐标偏移值` 同 | | `+0x2780` | 等级 | | | `+0x12FC` / `+0x130C` | 坐标 X / Y(= `0x107C+0x280` / `0x1084+0x288`) | 另一条寻址路径 | > 同一字段存在**新旧两套偏移**(`0x74/0x78` vs `0x5F4/0x5F8`、`0x2780` vs `0x5FC`), > 说明客户端版本升级时字段搬过家,工程里两套都留着。**以 `0x5F4/0x5F8/0x5FC` 这套为准**(代码里在用的是它)。 ### 5.4 选中目标 / 对话 | 表达式 | 含义 | 出处 | |---|---|---| | `[#坐标基址值 + 0x1D24]` | **选中目标 ID / 对话 ID**(可读可写) | 读:判「金香玉选中成功」;写:`返回(内存_写整数型(… + 0x1D24, 对话ID))` | > 与静态反汇编互为印证:`0x7DB9D0 mov [eax+0x1d24], edx`(`eax = [0x3BF28CC]`,即 `人物基址值`)。 ### 5.5 助手控件相关内联偏移 | 偏移 | 含义 | |---|---| | `+0x414` | **助手窗口**偏移(`[NPC基址值]` 解引用后 +0x414) | | `+0x36C0` ~ `+0x3B00` | 控件指针槽扫描区间(步长 4,共 74 槽) | | `+0x364` | 控件**命令 ID** | | `+0x3938` | 开始挂机按钮槽 | | `+0x393C` | 停止挂机按钮槽 | | `0x400000` / `0x1200000` | 虚表合法性校验区间(= `.text` 段) | > `0x400000` 这个值就是 `ImageBase` —— 工程靠「虚表指针必须落在 `.text` 内」来判定控件指针有效,思路正确。 --- ## 六、常量引用排行(哪些基址是承重墙) | 排行 | 常量名 | 引用次数 | 说明 | |---|---|---|---| | 1 | `当前血量值` | **74** | 血检最频繁,改地址风险最高 | | 2 | `背包物品位置值` | 51 | 偏移 | | 3 | `背包物品名称值` | 42 | 偏移 | | 4 | `背包基址值` | **41** | ★ 全工程最吃重的基址 | | 5 | `背包物品数量值` | 28 | 偏移 | | 6 | `背包物品编号值` | 27 | 偏移 | | 7 | `物品分类值` | 26 | 偏移 | | 8 | `石头大小值` / `石头属性值` | 20 / 17 | 偏移 | | 9 | `怪物基址值` | **15** | ★ | | 10 | `地图基址值` | **9** | ★ | | 11 | `NPC基址值` | **9** | ★ 助手链路头 | | 12 | `人物基址值` | 6 | ★ | | 13 | `坐标基址值` | 5 | ★ | | 14 | `商店基址值` / `凝神珠背包基址值` / `y坐标偏移值` | 3 / 3 / 3 | | | 15 | `状态栏基址值` | 2 | 当列表基址用(幸运符 20 格 / 轻功 15 格) | | 16 | `仓库基址值` / `发包Call_ECX值` / `发包call地址值` / `封包Eax基址` | 1 / 1 / 1 / 1 | | > **改基址时的风险顺序**:`背包基址值`(41) > `怪物基址值`(15) > `地图基址值`(9) = `NPC基址值`(9) > > `人物基址值`(6) > `坐标基址值`(5) > `商店基址值`(3) = `凝神珠背包基址值`(3) > `状态栏基址值`(2) > > `仓库基址值`(1)。 > 而 `仓库基址值` / `商店基址值` 各只有 1~3 处引用 —— **改错影响面很小,值得优先试换**(见待复核项)。 --- ## 七、常量表里**没有**的基址 工程常量只覆盖了「写死」的那 9 条。其余靠**运行时字节特征查找**,不在这张表里: | 来源 | 数量 | 位置 | |---|---|---| | 「基址更新」FindData 特征 | 34 条 | ❗ **本 E2TXT 里没有这个子程序** | | 31007 参考模块 | 26 项 | ❗ 未使用(且静态已证全失效,0 引用) | E2TXT 里只在注释和 `进程_特征码搜索` 的调用点见到零散特征码: | 行 | 特征码 | 用途 | |---|---|---| | 1866 | `83 BC 81 3C 05 00 00 00 74 59 8B 95 74 BE FF FF` | 背包基址(已注释掉) | | 8780 / 8813 | `8B 91 EC 03 00 00 8B 82 90 03 00 00 0F B6 88 C8 06 00 00 85 C9` | NPC对话基址 | | 8781 / 8814 | `8D 4C 02 FF 8B 55 FC 8B 82 B4 34 00 00 89 48 2C` | 小助手call基址 | > 所以:**「基址更新」34 条特征来自 `辅助配置汇总.csv`,不来自这个 E2TXT 工程**。 > 该工程目前是「常量写死 + 少量特征码」的混合模式。 --- ## 八、顺带确认:工程里确实已经装了助手 v3.2 E2TXT 是**当前工程状态**的 dump,里面能找到助手链路的完整实现: | 子程序 | 行号 | 状态 | |---|---|---| | `小助手开` | 8775 | 旧版(直调 `0xA3F700`) | | `小助手关` | 8809 | 旧版 | | `遍历助手控件` | 8907 | ✅ | | `小助手开_新路` | 8934 | ✅ 读 `0x3938` 槽 | | `小助手关_新路` | 8970 | ✅ 读 `0x393C` 槽 | | `助手_发命令` | 9006 | ✅ **v3.2**(1 参数 0 局部,机器码只读 `[ebp+8]`) | | `小助手_点控件` | 9031 | ✅ v3.2 | | `助手_取槽控件` | 9074 | ✅ v3.2(虚表区间校验 `0x400000~0x1200000`) | `助手_发命令` 机器码与交付版**逐字节一致**: ``` 96 pushad 106,0 push 0 lParam 139,69,8 mov eax,[ebp+8] 控件(唯一参数) 139,128,100,3,0,0 mov eax,[eax+0x364] 命令ID 80 push eax wParam=命令ID 104,244,3,0,0 push 0x3F4 msg 139,69,8 mov eax,[ebp+8] 139,72,4 mov ecx,[eax+4] 父窗口 139,17 mov edx,[ecx] 虚表 255,82,4 call [edx+4] → 0xA3F3D0 97 popad ``` ### ⚠ 但发现一处会导致 ④ 必然失败的差异 | | 交付版(`助手验证_极简版_易语言.txt:168`) | 工程实际(E2TXT `:9007`) | |---|---|---| | 参数声明 | `.参数 控件地址, 整数型` | `.参数 控件地址` ← **类型丢了** | 全文件只有 5 个「无类型」参数,其中 4 个是你原有的辅助子程序(`当前属性` / `格子号`), 只有 `控件地址` 是本该有类型却丢了的那一个 —— **不是 E2TXT 的显示省略**(对比 `:9075 .参数 助手窗口, 整数型` 是带类型的)。 **为什么致命**:易语言里省略类型的参数是**通用型**,调用时压栈的是「通用型数据块的指针」,**不是整数本身**。 于是机器码的 `mov eax,[ebp+8]` 拿到的是块地址,`mov eax,[eax+0x364]` 读到的是栈上的垃圾 → 算出的「命令 ID」「父窗口」全错 → `mov edx,[ecx]` / `call [edx+4]` 要么无效要么直接崩。 > 你原有的 `当前属性` / `格子号` 之所以一直没出问题,是因为它们只在**易语言代码**里参与算术(`基址 + 偏移`), > 通用型会被自动拆箱。**但 `置入代码` 不拆箱** —— 这是两回事。 **修法**:把第 9007 行改成 ``` .参数 控件地址, 整数型 ``` 两个字符的事。改完 ④ `小助手_点控件` 才可能真的生效。 --- ## 九、行动建议(按性价比排序) | # | 事项 | 依据 | 影响面 | |---|---|---|---| | **0** | ★ **`助手_发命令` 参数补回 `整数型`** | 类型丢失 → 通用型传参 → 机器码读 `[ebp+8]` 拿到的是块指针 | **④ 能否生效就卡在这** | | 1 | **核对 `仓库基址值`** → 试 `0x0182B5E8` | 现用值静态 0 引用;邻居 244 引用 | 1 处引用,改错代价极低 | | 2 | **核对 `商店基址值`** → 试 `0x03BC21F8` | 现用值静态 0 引用;邻居 76 引用 | 3 处引用 | | 3 | **活体确认 `地图基址值`** | 静态仅 3 引用,全表最低 | 9 处引用 | | 4 | 攻击列表基址改用候选3 `0x03BA4C40` | 与状态列表 `0x03BA4C3C` 相邻 4 字节,204 引用 | 待接 | | 5 | 统一坐标读取偏移 | 代码里 `0x1F84` 与 `0x12FC` 两套并存 | 建议只留 `0x1F84` | > 前两项只需 CE 读两次值即可定案(见《基址活体验证清单》第 3 组)。 --- *配套:《基址全量复验报告》`03_内存逆向与基址/19_基址全量复验报告.html` · 《基址活体验证清单》`D:\AI空间\rxjh\基址活体验证清单.md`* *清点脚本:`scan_e2txt_consts.py` · 原始输出:`_consts_e2txt.txt`*