某个网络游戏的第三方离线版启动器,可能是基于法务问题等的考量,在启动时会验证是否安装了正版游戏。

Screenshot 2025-10-23 204951.png (15.84 KB, 下载次数: 0)
下载附件
2025-11-1 11:03 上传
而这个启动器是开源的,而且是.net mono,但每次更新都要重新编译/用dnspy修补,也是很麻烦的
于是就有人发明了创建注册表项和占位文件来过验证的方法,但这个方法,我觉得终究是不够优雅
而众所周知的,这个离线版的客户端启动器是一个基于.NET 9的程序,在较早的版本中(4.0.0 以前)基于.NET的更早版本。
但它们的原理都是相同的。启动程序时,CLR会接管执行,然后通过JIT编译器,把IL转换成本机机器码。
而我们的修补则从IL入手。我们首先利用ILSpy工具找到验证函数的代码,
它在这里(几乎同样的源码已经由这个离线版的开发团队开源,可以看到几乎一致)

image.png (105.79 KB, 下载次数: 0)
下载附件
2025-11-1 11:04 上传
接着我们切换到IL视图,得到了这样的IL代码

image.png (5.32 KB, 下载次数: 0)
下载附件
2025-11-1 11:04 上传
它所对应的字节码就是
[Asm] 纯文本查看 复制代码07
16
FE 01
2A关键在于 07 和 16 这两个字节,在IL代码中,它们分别代表 ldloc.1 (加载局部变量1)和 ldc.i4.0(压入常量 0),它们组成了相等判断的两项.
如果我们改为
[Asm] 纯文本查看 复制代码16
16
FE 01
2A
得到的就是

image.png (5.14 KB, 下载次数: 0)
下载附件
2025-11-1 11:06 上传
显然,这永远返回“真”
同理,改为
[Asm] 纯文本查看 复制代码07
07
FE 01
2A

image.png (12.01 KB, 下载次数: 0)
下载附件
2025-11-1 11:06 上传
这一样会永远返回真。
接着就是定位这段字节序列所在的位置,只需要使用随意哪个十六进制编辑器进行搜索,
但如果直接搜索07 16 FE 01 2A我们会得到至少4个结果

image.png (69.94 KB, 下载次数: 0)
下载附件
2025-11-1 11:07 上传
但与此同时,我们注意到在这段代码前还有leave.s IL_00d4语句

image.png (27.34 KB, 下载次数: 0)
下载附件
2025-11-1 11:08 上传
因此可以确定图中1C0B942位置,即DE 00 07 16 FE 01 2A对应的就是我们要找到的位置,
保险起见我们取特征码到26 15 0B DE 00 07 16 FE 01 2A
只patch一个字节

Screenshot 2025-10-23 205048.png (113.22 KB, 下载次数: 0)
下载附件
2025-11-1 11:09 上传
测试,启动器成功启动离线版游戏,没有再弹出正版提示。这个方法也可以很方便的编写自动工具,根据特征码找到要修改的IL代码的位置,patch一个字节,优雅的解决问题

