← 返回总索引时间制道具(箱子)对象逆向 · 续期方案🔑 卡密引导06_时间制道具对象/时间制道具对象逆向_续期方案.html

时间制道具(箱子)对象逆向 · 续期方案

热血江湖 YGOnline.exe  |  CE 实机验证  |  2026-09-20
目标:定位道具到期时间对象 → 验证改写可行性 → 输出易语言实现

一、结论速览

已验证到期时间就存在道具记录结构里,用 5 个 WORD 连存(年/月/日/时/分),直接改它即时生效。

实测:把新箱子内存中的时间改为 2027/1/1 0:0,游戏工具提示立即显示「使用期間:2027年1月1日 0時0分為止」。客户端直接读这 10 个字节。

重要限制到期时间由服务器权威持有,重新登录后会被服务器下发数据覆盖回原值。

实测:改完显示 2027/1/1 → 重新登录 → 恢复为原本的 2026/9/27。内存里发现了网络封包缓冲区(55 AA AA 55 魔数),里面有服务器下发的原始时间数据。

二、记录结构(实测定型)

每条时间制道具记录是独立分配的对象,记录步长 0x40(两条记录地址恰好相差 64 字节)。结构如下:

偏移内容类型说明
-0x2080 3A 09 00 = 604800dword记录指纹(7天 = 604800 秒道具时长)
-0x1C实例唯一 IDdword区分不同道具实例
-0x0CFF FF FF FFdword空槽标记
-0x0401 00 00 00dword有效标志
+0x00年 / 月 / 日 / 时 / 分5 × WORD到期时间 ← 客户端显示源
+0x14到期 epochdword派生缓存(改它不影响显示)
+0x1874 60 3E 1Fdword会话戳(同一会话内各记录同值)

实测的两条记录

旧箱(已过期)  记录基址 0x5D4BFFA4     到期 2026/9/20 9:29
新箱(未使用)  记录基址 0x67042F1C     到期 2026/9/27 12:04

三、定位方法(地址无关)

记录地址不固定:重登后进程 PID 变了(11848 → 16460),两个箱子的地址全部改变。所以必须用特征扫描动态定位。

1. 全内存搜 80 3A 09 00(604800 小端)
2. 对每个命中地址 A,读 A+0x20 处的 5 个 WORD
3. 校验:年 2000~2100、月 1~12、日 1~31、时 0~23、分 0~59
4. 全部合法 → 一条真实的时间制道具记录

实测数据全内存搜 80 3A 09 00 原始命中 43 处,经合法性校验后只剩 1~2 处为真记录。

其余是:代码常量(604800 这个数字在程序里到处用)、浮点数巧合、字符串巧合、网络封包副本。校验步骤绝不可省。

四、改写(续期)

改写只需写 5 个 WORD,共 10 字节:

内存.写短整数 (记录基址 + 0x00, 新年)
内存.写短整数 (记录基址 + 0x02, 新月)
内存.写短整数 (记录基址 + 0x04, 新日)
内存.写短整数 (记录基址 + 0x06, 新时)
内存.写短整数 (记录基址 + 0x08, 新分)

epoch 字段(+0x14)是派生缓存,不用改 —— 实测改完年月日时分后 epoch 不联动,说明客户端不使用它做显示判定。

五、易语言实现(精易模块)

5.1 扫描 + 读取

.程序集变量 箱子数, 整数型
.程序集变量 箱子时间地址, 整数型, "0"
.程序集变量 箱子年, 整数型, "0"
.程序集变量 箱子月, 整数型, "0"
.程序集变量 箱子日, 整数型, "0"
.程序集变量 箱子时, 整数型, "0"
.程序集变量 箱子分, 整数型, "0"

.子程序 读箱子列表, 整数型, 公开
.参数 进程ID, 整数型

.局部变量 内存, 类_内存
.局部变量 命中, 整数型, "0"
.局部变量 命中数, 整数型
.局部变量 i, 整数型
.局部变量 基址, 整数型
.局部变量 年, 整数型
.局部变量 月, 整数型
.局部变量 日, 整数型
.局部变量 时, 整数型
.局部变量 分, 整数型

箱子数 = 0
清除数组 (箱子时间地址)
清除数组 (箱子年)
清除数组 (箱子月)
清除数组 (箱子日)
清除数组 (箱子时)
清除数组 (箱子分)

.如果真 (进程ID = 0)
    写日志 (自定义时间 () + "【读箱子】进程ID无效,中止!" + #换行符)
    返回 (0)
.如果真结束

内存.打开进程 (进程ID)

' 搜特征 80 3A 09 00
命中数 = 内存.搜索 ({ 128, 58, 9, 0 }, 命中)
写日志 (自定义时间 () + "【读箱子】扫描完成,原始命中 " + 到文本 (命中数) + " 处" + #换行符)

.计次循环首 (命中数, i)
    基址 = 命中 [i]

    ' ⚠️ 必须用「读短整数」(2字节),不能用「读整数」(会连读成 dword)
    年 = 内存.读短整数 (基址 + 32)
    月 = 内存.读短整数 (基址 + 34)
    日 = 内存.读短整数 (基址 + 36)
    时 = 内存.读短整数 (基址 + 38)
    分 = 内存.读短整数 (基址 + 40)

    .如果真 (年 ≥ 2000 且 年 ≤ 2100 且 月 ≥ 1 且 月 ≤ 12 且 日 ≥ 1 且 日 ≤ 31 且 时 ≤ 23 且 分 ≤ 59)
        加入成员 (箱子时间地址, 基址 + 32)
        加入成员 (箱子年, 年)
        加入成员 (箱子月, 月)
        加入成员 (箱子日, 日)
        加入成员 (箱子时, 时)
        加入成员 (箱子分, 分)
        箱子数 = 箱子数 + 1
    .如果真结束
.计次循环尾 ()

写日志 (自定义时间 () + "【读箱子】校验通过 " + 到文本 (箱子数) + " 条" + #换行符)
返回 (箱子数)

5.2 续期改写

.子程序 续期箱子, 整数型, 公开
.参数 进程ID, 整数型
.参数 原年, 整数型
.参数 原月, 整数型
.参数 原日, 整数型
.参数 原时, 整数型
.参数 原分, 整数型
.参数 新年, 整数型
.参数 新月, 整数型
.参数 新日, 整数型
.参数 新时, 整数型
.参数 新分, 整数型

.局部变量 内存, 类_内存
.局部变量 命中, 整数型, "0"
.局部变量 命中数, 整数型
.局部变量 i, 整数型
.局部变量 基址, 整数型
.局部变量 改动数, 整数型

内存.打开进程 (进程ID)
命中数 = 内存.搜索 ({ 128, 58, 9, 0 }, 命中)
改动数 = 0

.计次循环首 (命中数, i)
    基址 = 命中 [i]

    ' 精确匹配原时间,避免误改其他道具
    .如果真 (内存.读短整数 (基址 + 32) = 原年 且 内存.读短整数 (基址 + 34) = 原月 且 内存.读短整数 (基址 + 36) = 原日 且 内存.读短整数 (基址 + 38) = 原时 且 内存.读短整数 (基址 + 40) = 原分)

        内存.写短整数 (基址 + 32, 新年)
        内存.写短整数 (基址 + 34, 新月)
        内存.写短整数 (基址 + 36, 新日)
        内存.写短整数 (基址 + 38, 新时)
        内存.写短整数 (基址 + 40, 新分)

        改动数 = 改动数 + 1
        写日志 (自定义时间 () + "【续期】已改为 " + 到文本 (新年) + "年" + 到文本 (新月) + "月" + 到文本 (新日) + "日 " + 到文本 (新时) + "時" + 到文本 (新分) + "分  地址:" + 取十六进制文本 (基址 + 32) + #换行符)
    .如果真结束
.计次循环尾 ()

返回 (改动数)

六、精易模块命令对照

用途精易命令备注
建对象类_内存 局部变量需先声明
打开进程内存.打开进程 (进程ID)不调用则所有操作失败
搜特征内存.搜索 (字节集, 结果数组)结果数组传址,返回命中数
读 2 字节内存.读短整数 (地址)读年月日时分必用
读 4 字节内存.读整数 (地址)—
写 2 字节内存.写短整数 (地址, 值)续期改写用
读字节集内存.读字节集 (地址, 长度)—

七、避坑清单(实测踩过)

1. 读 WORD 用错命令 → 全错

内存里年份字节: EA 07  (小端 = 2026)

✅ 内存.读短整数(基址+32)  → 2 字节 → 2026
❌ 内存.读整数(基址+32)    → 4 字节 → 把年+月连读
                              EA 07 09 00 = 0x000907EA = 591850  ✗

2. 不校验会有 43 条垃圾 —— 校验年月日范围这一步是排除假命中的唯一手段,不能省。

3. 地址每次都会变 —— 重登、换地图、切换角色都会重排。必须每次重新扫描,绝不能写死地址。

4. 服务器会覆盖(最关键的坑) —— 重新登录后服务器重发道具列表,内存改动被冲回原值。已实测确认。

要让续期真正持久,只能:(a) 助手定时重写(登录后立即写、检测到被还原就补写),或 (b) 从网络封包层改写服务器下发的时间字段。

5. 服务器端是否校验真实时间 —— 尚未验证

目前只证明了「客户端显示受内存控制」。真正开箱使用时,服务器是否接受这个被改写的时间,需要一次实际开箱测试才能判定。
建议:把已过期的旧箱子改成未来时间后立即尝试使用(不要重登、不要换图)。能开出来 = 服务器不校验;被拒 = 服务器另有真实时间源。

八、网络封包缓冲区(旁证)

内存中发现了封包缓冲区,格式为 55 AA AA 55 魔数 + 44 00 44 00 长度头,内部同时包含新旧两箱的到期时间字段(间隔 0x40):

...55 AA AA 55 44 00 44 00...
EA 07 09 00 14 00 09 00 1D 00   ← 旧箱 2026/9/20 9:29
EA 07 09 00 1B 00 0C 00 04 00   ← 新箱 2026/9/27 12:04

这证明到期时间的源头是服务器下发,内存中的记录是服务器数据的落地副本 —— 这正是"重登后被覆盖"的原因。

九、验证记录

时间操作结果
12:14重登后扫描新箱定位到 0x66F1FCFC,旧箱未在指纹列表(后确认仍在)
12:20改新箱「分」04→05写入成功,epoch 不联动
12:23改新箱为 2027/1/1 0:0游戏提示显示 2027年1月1日 0時0分 ✓ 客户端读 ymdhm 确认
12:25重新登录游戏时间恢复原值 ✗ 服务器覆盖确认
12:42换位 + 重登后重扫旧箱仍被扫到(0x65176A2C 一带),证明特征扫描地址无关 ✓
热血江湖助手 · 分析资料站← 报告总目录助手主页