' ============================================================ ' 热血江湖 · 时间制道具(箱子)读取与续期模块 ' 逆向成果:YGOnline.exe 实机验证(CE) ' 日期:2026-09-20 ' ' 原理:扫特征 80 3A 09 00(604800 = 7天秒数,记录指纹) ' 校验 5×WORD(年月日时分)合法性 → 定位真记录 ' 特点:地址无关,重登/换图/换位后照样能用 ' ' ⚠️ 关键限制:服务器权威持有到期时间,重登后会被下发数据覆盖 ' ============================================================ .版本 2 .支持库 spec .程序集变量 箱子数, 整数型 .程序集变量 箱子时间地址, 整数型, "0" .程序集变量 箱子年, 整数型, "0" .程序集变量 箱子月, 整数型, "0" .程序集变量 箱子日, 整数型, "0" .程序集变量 箱子时, 整数型, "0" .程序集变量 箱子分, 整数型, "0" ' ============================================================ ' 读取:扫描内存,列出所有时间制道具 ' 参数:进程ID(外部传入) ' 返回:找到的有效记录条数 ' ============================================================ .子程序 读箱子列表, 整数型, 公开 .参数 进程ID, 整数型 .局部变量 内存, 类_内存 .局部变量 命中, 整数型, "0" .局部变量 命中数, 整数型 .局部变量 i, 整数型 .局部变量 基址, 整数型 .局部变量 年, 整数型 .局部变量 月, 整数型 .局部变量 日, 整数型 .局部变量 时, 整数型 .局部变量 分, 整数型 ' 清空上次结果 箱子数 = 0 清除数组 (箱子时间地址) 清除数组 (箱子年) 清除数组 (箱子月) 清除数组 (箱子日) 清除数组 (箱子时) 清除数组 (箱子分) .如果真 (进程ID = 0) 写日志 (自定义时间 () + "【读箱子】进程ID无效,中止!" + #换行符) 返回 (0) .如果真结束 内存.打开进程 (进程ID) ' === 1. 搜特征:80 3A 09 00 = 604800(7天秒数,记录指纹)=== 命中数 = 内存.搜索 ({ 128, 58, 9, 0 }, 命中) 写日志 (自定义时间 () + "【读箱子】内存扫描完成,原始命中 " + 到文本 (命中数) + " 处" + #换行符) .如果真 (命中数 ≤ 0) 写日志 (自定义时间 () + "【读箱子】没扫到任何记录!" + #换行符) 返回 (0) .如果真结束 ' === 2. 逐个校验(排除代码常量/浮点巧合/字符串巧合)=== .计次循环首 (命中数, i) 基址 = 命中 [i] ' 时间字段在 基址+0x20,5 个 WORD 连存:年 月 日 时 分 ' ⚠️ 必须用「读短整数」(2字节),不能用「读整数」(会连读成 dword) 年 = 内存.读短整数 (基址 + 32) 月 = 内存.读短整数 (基址 + 34) 日 = 内存.读短整数 (基址 + 36) 时 = 内存.读短整数 (基址 + 38) 分 = 内存.读短整数 (基址 + 40) ' 合法性校验:不通过的直接丢弃 .如果真 (年 ≥ 2000 且 年 ≤ 2100 且 月 ≥ 1 且 月 ≤ 12 且 日 ≥ 1 且 日 ≤ 31 且 时 ≤ 23 且 分 ≤ 59) 加入成员 (箱子时间地址, 基址 + 32) 加入成员 (箱子年, 年) 加入成员 (箱子月, 月) 加入成员 (箱子日, 日) 加入成员 (箱子时, 时) 加入成员 (箱子分, 分) 箱子数 = 箱子数 + 1 .如果真结束 .计次循环尾 () 写日志 (自定义时间 () + "【读箱子】校验通过 " + 到文本 (箱子数) + " 个时间制道具" + #换行符) 返回 (箱子数) ' ============================================================ ' 续期:把匹配原时间的记录改成新时间 ' 参数:原时间(用于精确匹配)+ 新时间 ' 返回:改动成功的条数 ' ============================================================ .子程序 续期箱子, 整数型, 公开 .参数 进程ID, 整数型 .参数 原年, 整数型 .参数 原月, 整数型 .参数 原日, 整数型 .参数 原时, 整数型 .参数 原分, 整数型 .参数 新年, 整数型 .参数 新月, 整数型 .参数 新日, 整数型 .参数 新时, 整数型 .参数 新分, 整数型 .局部变量 内存, 类_内存 .局部变量 命中, 整数型, "0" .局部变量 命中数, 整数型 .局部变量 i, 整数型 .局部变量 基址, 整数型 .局部变量 改动数, 整数型 .如果真 (进程ID = 0) 写日志 (自定义时间 () + "【续期】进程ID无效,中止!" + #换行符) 返回 (0) .如果真结束 内存.打开进程 (进程ID) 命中数 = 内存.搜索 ({ 128, 58, 9, 0 }, 命中) 改动数 = 0 .计次循环首 (命中数, i) 基址 = 命中 [i] ' 精确匹配原时间,避免误改其他道具 .如果真 (内存.读短整数 (基址 + 32) = 原年 且 内存.读短整数 (基址 + 34) = 原月 且 内存.读短整数 (基址 + 36) = 原日 且 内存.读短整数 (基址 + 38) = 原时 且 内存.读短整数 (基址 + 40) = 原分) ' === 写入 5 个 WORD(改写到期时间)=== 内存.写短整数 (基址 + 32, 新年) 内存.写短整数 (基址 + 34, 新月) 内存.写短整数 (基址 + 36, 新日) 内存.写短整数 (基址 + 38, 新时) 内存.写短整数 (基址 + 40, 新分) 改动数 = 改动数 + 1 写日志 (自定义时间 () + "【续期】箱子已改为 " + 到文本 (新年) + "年" + 到文本 (新月) + "月" + 到文本 (新日) + "日 " + 到文本 (新时) + "時" + 到文本 (新分) + "分 地址:" + 取十六进制文本 (基址 + 32) + #换行符) .如果真结束 .计次循环尾 () 写日志 (自定义时间 () + "【续期】完成,共改动 " + 到文本 (改动数) + " 处" + #换行符) 返回 (改动数) ' ============================================================ ' 取第 N 个箱子的时间文本(含过期判断) ' ============================================================ .子程序 取箱子文本, 文本型, 公开 .参数 序号, 整数型 .局部变量 当前时间, 日期时间型 .局部变量 现在值, 整数型 .局部变量 到期值, 整数型 当前时间 = 取现行时间 () 现在值 = 取年份 (当前时间) × 10000 + 取月份 (当前时间) × 100 + 取日 (当前时间) 到期值 = 箱子年 [序号] × 10000 + 箱子月 [序号] × 100 + 箱子日 [序号] .如果 (到期值 < 现在值) 返回 (到文本 (箱子年 [序号]) + "年" + 到文本 (箱子月 [序号]) + "月" + 到文本 (箱子日 [序号]) + "日 " + 到文本 (箱子时 [序号]) + "時" + 到文本 (箱子分 [序号]) + "分【已過期】") .否则 返回 (到文本 (箱子年 [序号]) + "年" + 到文本 (箱子月 [序号]) + "月" + 到文本 (箱子日 [序号]) + "日 " + 到文本 (箱子时 [序号]) + "時" + 到文本 (箱子分 [序号]) + "分【有效】") .如果结束 ' ============================================================ ' 打印全部箱子到日志 ' ============================================================ .子程序 打印箱子日志, 公开 .局部变量 i, 整数型 .如果真 (箱子数 = 0) 写日志 (自定义时间 () + "【读箱子】没有找到箱子!" + #换行符) 返回 () .如果真结束 .计次循环首 (箱子数, i) 写日志 (自定义时间 () + "【箱子" + 到文本 (i) + "】" + 取箱子文本 (i) + " 地址:" + 取十六进制文本 (箱子时间地址 [i]) + #换行符) .计次循环尾 () ' ============================================================ ' 调用示例:读取 ' ============================================================ .子程序 _按钮_读箱子_被单击 .局部变量 进程ID, 整数型 进程ID = 取进程ID ("YGOnline.exe") .如果真 (进程ID = 0) 写日志 (自定义时间 () + "【读箱子】游戏没运行!" + #换行符) 返回 () .如果真结束 读箱子列表 (进程ID) 打印箱子日志 () ' ============================================================ ' 调用示例:把旧箱子(2026/9/20 9:29)续期到 2027/1/1 0:0 ' ============================================================ .子程序 _按钮_续期旧箱_被单击 .局部变量 进程ID, 整数型 .局部变量 数, 整数型 进程ID = 取进程ID ("YGOnline.exe") .如果真 (进程ID = 0) 写日志 (自定义时间 () + "【续期】游戏没运行!" + #换行符) 返回 () .如果真结束 数 = 续期箱子 (进程ID, 2026, 9, 20, 9, 29, 2027, 1, 1, 0, 0) .如果 (数 > 0) 写日志 (自定义时间 () + "【续期】旧箱子续期成功,改动 " + 到文本 (数) + " 处!" + #换行符) .否则 写日志 (自定义时间 () + "【续期】没找到旧箱子(地址可能已变),请重新扫描!" + #换行符) .如果结束 ' ============================================================ ' 记录结构速查表 ' ============================================================ ' 记录基址 - 0x20 : 80 3A 09 00 = 604800(7天秒数,记录指纹) ' 记录基址 - 0x1C : 实例唯一 ID(dword) ' 记录基址 - 0x0C : FF FF FF FF(空槽标记) ' 记录基址 - 0x04 : 01 00 00 00(有效标志) ' 记录基址 + 0x00 : 年/月/日/时/分(5×WORD)← 到期时间,客户端显示源 ' 记录基址 + 0x14 : 到期 epoch(dword,派生缓存,改它无效) ' 记录基址 + 0x18 : 74 60 3E 1F(会话戳) ' ' 记录步长:0x40(64 字节) ' ' 实测记录(已失效,仅供对照): ' 旧箱 记录基址 0x5D4BFFA4 到期 2026/9/20 9:29 ' 新箱 记录基址 0x67042F1C 到期 2026/9/27 12:04 ' ============================================================