结论先说:能找到实物,也能逐字节复刻;但 exe/dll 里没有静态模板数据块。
新角色的内挂配置是「代码 memset 清零 + 写 4 个字节 + 读文件覆盖」现场生成的。
| 层 | 能不能找到 | 证据 |
|---|---|---|
| 实物档 | ✅ 能找到 | 客户端目录里 loldsx3.aut、benchi004.aut 是纯出厂骨架,各 11 个非零字节 |
| 静态模板 | ❌ 不存在 | 15,072,256 B 的 YGOnline.exe + 16 个 dll 全扫「页头模式」→ 0 命中;整表长度 0x2E24 全文件 0 命中 |
| 生成代码 | ✅ 已定位 | YGOnline.exe 的 0x00A81D10 函数,memset + 4 字节写入,反汇编见下 |
所以我给你的是 复刻出来的模板文件,不是从 exe 里"挖"出来的:
tools/rxjh_初始模板_AA42.aut 11812 B md5 3f0eba04248a6caa41162a581e703ebb
tools/rxjh_初始模板_4316.aut 11812 B md5 352d2deb00b81f819df9cabe1d3d6de5
_AA42 那份与真实存档 loldsx3.aut 的 MD5 完全相同(差异 0 字节),不是"猜出来的近似值"。
这是 .aut 的加载入口。关键三步:
00A81D10 push ebp
00A81D11 mov ebp, esp
00A81D13 sub esp, 0x118
...
00A81D33 push 0x100 ; 局部缓冲 256 B
00A81D3A lea eax, [ebp-0x104]
00A81D41 call 0xfe36f0 ; memset(buf, 0, 0x100)
00A81D53 push 0x2e20 ; ★ 11808 = 整表长度
00A81D58 push 0 ; 填 0
00A81D5A mov ecx, [ebp-0x108]
00A81D60 add ecx, 0x564 ; obj + 0x564 = 页区基址
00A81D67 call 0xfe36f0 ; ★ memset(obj+0x564, 0, 11808)
; —— 给"当前页"写 4 个 01 ——
00A81D6F movzx edx, byte ptr [0x3bf9518] ; ★ 全局当前页号(byte)
00A81D76 imul eax, edx, 0x5c4 ; × 页大小 1476
00A81D82 mov byte ptr [ecx+eax+0x564], 1 ; 页内 0x000 = 01
00A81D9D mov byte ptr [ecx+eax+0x565], 1 ; 页内 0x001 = 01
00A81DB8 mov byte ptr [ecx+eax+0x56c], 1 ; 页内 0x008 = 01
00A81DD3 mov byte ptr [ecx+eax+0x56d], 1 ; 页内 0x009 = 01
; —— 拼路径 + 打开 ——
00A81DDB push 0x3bf3200 ; 游戏根目录
00A81DE0 push 0x1871b60 ; 账号名
00A81DE5 push 0x10e3918 ; 格式串
00A81DEA push 0x100
00A81DF5 push edx
00A81DF6 call 0x882c40 ; sprintf
00A81DFE push 0x10acd04 ; "rb"
00A81E0A call 0xfef2f6 ; fopen
00A81E18 cmp [ebp-0x10c], 0 ; fopen 失败?
00A81E1F je 0xa81fb1 ; 失败 → 跳过读取(保留 memset 结果)
00A81E4A call 0xfef5a3 ; fread(4 字节文件头)
00A81E52 cmp [ebp-0x118], 0x67
这 4 个 01 就是骨架里那 4 个 1(页内 0x000 0x001 0x008 0x009),和 loldsx3.aut 的非零字节严丝合缝。
0x010E3918)%s\client\%s.aut
即 <游戏根目录>\client\<账号名>.aut。.aut 文件名就是账号名,一个账号一个文件。
[0x3BF9518]一个独立全局 byte,不是控件字段。所有「当前页」相关读写都用它 × 0x5C4 定位。翻页时改的是这里。
0xA81E52 处按读到的 4 字节文件头分四路:
| 文件头 | 页数 × 页大小 | 说明 |
|---|---|---|
0x67 | 8 × 0x4E8 (1256) | 最老的紧凑布局 |
0x68 | 4 × 0x5C0 (1472) | 4 槽版,无第二页 |
0x69 | 1 × 0x1710 (5904) | 单页整块 |
0x6A | 整表 0x2E20 (11808) | 当前格式,文件头 6A 00 00 00 |
当前 .aut 里那 4 字节 6A 00 00 00 就是这么来的 —— 它是格式版本号,不是随便的填充。
读失败/文件不存在时不清空,直接保留 memset 后的骨架 → 这就是"新角色默认档"的产生方式。
00A883AD call 0xfef2f6 ; fopen(..., "wb") ← 模式串 0x010B4344 = "wb"
00A883CC call 0xa892d0 ; 保存前整理/回填
00A883F6 call 0x1025f16 ; fwrite(4 字节文件头)
00A88405 push 1
00A88407 push 0x2e20 ; ★ 11808
00A8840C mov ecx, [ebp-0x10c]
00A88412 add ecx, 0x564
00A88419 call 0x1025f16 ; fwrite(obj+0x564, 11808, 1, fp)
写盘 = 4 字节头 + 整表 11808 字节,没有压缩、没有加密、没有校验和。所以内存导出与文件可以做到 MD5 完全一致(这一点之前已实测)。
memset 之后还有一个"补默认值"函数:
00A7FD70 cmp [ebp+8], 0 ; 传入了模板指针?
00A7FD74 je 0xa7fd97
00A7FD95 rep movsd es:[edi], [esi] ; ★ 复制 0x171 个 dword = 0x5C4 = 整页
00A7FDAB movzx eax, [页内 0x000]
00A7FDB1 jne 0xa7fdca
00A7FDB3 push 0 / push 0xc / push 0x3f4
00A7FDBC call [vtable+4] ; 页标记为 0 → 建控件/置初值 (0x3F4, 0xC)
00A7FDE2 movzx ecx, [页内 0x001]
00A7FDE4 jne 0xa7fdfd
00A7FDE6 push 0 / push 0xe / push 0x3f4
00A7FDFA call [vtable+4] ; 页标记为 0 → (0x3F4, 0xE)
00A7FE0D movss xmm0, [0x10ae174] ; ★ 20.0f
00A7FE15 comiss xmm0, [页内 0x004]
00A7FE1D jbe 0xa7fe40
00A7FE37 movss [页内 0x004], xmm0 ; 小于 20.0 就抬到 20.0
注意这里补的是页内 0x004(运行时字段,落盘为 0),不是 0x00C/0x010。
0x10AE160)| VA | 值 | 可能的含义 |
|---|---|---|
0x10AE160 | 0.3 | 低血阈值 |
0x10AE164 | 0.7 | 高血阈值 |
0x10AE168 | 0.8 | — |
0x10AE16C | 2.5 | — |
0x10AE170 | 13.0 | — |
0x10AE174 | 20.0 | 页内 0x004 下限 |
0x10AE180 | 40.0 | — |
0x10AE184 | 160.0 | — |
0x10AE188 | 320.0 | — |
0x10AE18C | 5440.0 | — |
相对文件偏移:
0x000 6A 文件头(格式版本 0x6A)
0x004-0x005 01 01 页标记(页内 0x000)
0x00A-0x00B AA 42 版本标记(页内 0x006)= 0x42AA
0x00C-0x00D 01 01 页内 0x008
0x013 3F 页内 0x00C = float 0.5 的低字节
0x017 3F 页内 0x010 = float 0.5 的低字节
0x4BE-0x4BF AA 42 版本镜像(页内 0x4BA)
其余 11801 字节全为 0。
01 01 都没有 → 只能靠点面板新建,或工具 copy 复制过去。0x074~0x096 全 0)—— 所以"新号默认开 30/31"是错的,那几个号是人手工勾的。AA 42(= 0x42AA):2025 年那批号创建时的程序版本16 43(= 0x4316):当前客户端版本两份模板只差这 4 个字节(0x00A/0x00B 和 0x4BE/0x4BF)。
选哪个:
_AA42_4316cd D:/AI空间/rxjh/tools
# 新建一个账号档(账号名 = 文件名)
python rxjh_aut.py new 新账号名
# 或者从模板复制一份改个名
copy rxjh_初始模板_4316.aut "D:\rxjh2025\client\新账号名.aut"
放到 D:\rxjh2025\client\ 下,角色第一次登录就读这份。
python rxjh_aut.py default 我的模板.aut --version 0x42AA
python rxjh_aut.py default - --version 0x42AA # 只打印字节不写盘
python rxjh_aut.py default 带开关.aut --switches 30,31 # 顺带打开 30/31
python rxjh_aut.py clone orzo 新账号名
会整槽复制,并自动:保留目标档的版本标记、把实时血蓝字段归 0.5。
| 项 | 状态 |
|---|---|
页内 0x00C / 0x010 的 0.5 由哪行代码写 | 初始化函数不写;0xA892D0(保存前整理)是嫌疑点。实测结果确定是 0.5,模板已按结果写死 |
版本标记 AA 42 的写入点 | 未定位(代码里没搜到 0x42AA 立即数,只有 0x546E62 一处数据引用) |
| 35 项开关 ↔ 面板勾选的映射 | 已证伪「35 项 = 面板勾选」,见 内挂35项开关_实测对照_20261019.md |
| 面板勾选到底存哪 | 三选一未定:① 不落盘 ② 0x4A8~0x550 第二组设置 ③ YB*.cfg |