Berd's Playground

_(:з」∠)_

04/29
12:20
技术

Yu-RIS 引擎认证回避笔记

0x00 前言

最近在做 Yu-RIS 的游戏解包和反编译, 发现 YSTB 的数据被加密了. 寻找 XOR 表的时候本来准备打个断点康康结果发现游戏居然要我输激活码

由于 XOR 表的算法静态分析实在是太难, 这里就采用先破解游戏然后打断点导出 Key 的方式来解密 YSTB 数据. 本文主要内容还是游戏的破解过程, 不过分析完也找到了 XOR Key. 程序本身没有符号, 如果你看到奇怪的函数名或者变量名都是我加上去的

0x01 基本分析

打开游戏 (这里是 Maggot Baits 实体版镜像, 来自 HACG) 后会提示输入激活码, 验证失败后会弹出一个消息框 (不要在意乱码)

游戏没有加壳或者进行保护, 所以这个过程很简单, 直接在 MessageBox 下断点往前追几步就可以找到激活码计算函数

0x02 算法分析

进入激活码校验函数, 可以看到游戏先尝试从文件加载激活码, 如果没找到再要求用户输入

然后激活码经过了一系列魔法运算(图中只是一小部分) 由于这些运算实在是太复杂了, 暂时放弃逆出算法的想法, 尝试进行爆破

之前试过直接在校验函数外面爆破失败了, 因此先继续分析看看还有什么其他魔法

继续向下分析, 可以发现 XOR 表的计算也放在这个函数中(断点处), 并且下面红框中有疑似写入成功 Key 的部分.

可以判定这个地方已经通过校验了, 这样就确定了大致的激活码校验范围

顺便贴一下 XOR 表的生成过程(与激活码校验无关). 之前分析过英文 DL 版是将字符串 “CloclupDl” 进行一套魔法 CRC 后得出的, 但日文实体版没这么简单, 计算被放到了激活函数中.

0x03 认证回避

首先看到一处验证失败逻辑, 记下条件直接改为 jmp

往下分析, 我们输入的激活码被和 “yu-ris1” 进行拼接然后放到另外一个变量中

然后对激活码进行了一些魔法, 先不管那些运算来看这个 regKeyComplete 用来干什么

追进这个 sub_462C04, 肉眼可见这是个 SHA1 函数 (之前折腾 SM3 的经验, 开头就是五个常数放到5个寄存器很明显了, 再 Google 一下常数就能确定是 SHA1)

再看下面的 sub_43EFFC, 由于之前逆向过英文版, 我能确定这个算法是某种 CRC, 通过一个程序内的常量表对字符串计算得出一个 uint32. 稍微注意一下这里只处理了 字符串的 17 位.

现在就很清楚了, 最终校验的 finalKey 是长度为 40 + 8 的一个字符串. 这样我们就可以直接算出下面的循环计数

辣么这个循环是干什么的呢¿

结合上面的那个蜜汁表格我才发现, 这玩意是把之前的 HEX 字符串转回 byte[]

接下来分析最后的判定算法, 程序从固定的 wtfTable 中每隔 28 byte 取出一截, 用前 24 byte 和我们的 finalKeyByteArray 进行对比.

当数据匹配的时候跳出循环, 用此时被取出这一截的后 8 byte 作为两个 int 相加, 以此算出 XOR Key (XOR Key 计算部分参见 0x02).

这个 wtfTable 是怎么来的呢? 其实很简单, 就是嵌在程序里的一个资源而已, 用 Resource Hacker 之类的程序都可以解出来

我们假设游戏发行商不可能给所有用户都发完全一致的 Key , 但是 XOR 解密 Key 一定只有一个, 那么现在要干的事情很明显了. 只需要把 Key 的判断跳过, 取出任意一个 wtf 来初始化 Key 即可.

在此之前, 先验证一下我们的想法. 拆开 EXE 取出 YS_BIN, 让我们随便取几个 8 byte 算一下, 完美证明

接下来给程序打补丁, 把橙色的几个块直接用一个 jmp 跳掉即可. 别忘了给 edx 赋一个 28 的倍数

Patch 后如图, 右边是原来的数据作为对照 (好像被 Snipaste 弄糊了, 不要在意细节)

这样认证回避就完成啦 同时我也找到了 XOR Key, 真是可喜可贺 可喜可贺

Yu-RIS 引擎认证回避笔记