LoveinLogin gal非要装客户端的解决办法

逆向工程 实用技术 算法
30
kinotern

单机 galgame 凭什么非要我装客户端

《Love in Login》是单机的,剧情和存档都在本地。可它不让进。点开始就弹一个 Windows 对话框:「获取打开此 'sgup' 链接的应用」

image.png

系统里没有能处理这个链接的程序,于是推荐我去 Microsoft Store 找。

sgup 是韩国平台 STOVE 的自定义协议。

先看它在干什么

我没急着动手,先查这个弹窗是谁弹的。

插件目录里躺着一个 sgup_api64.dll,名字里带 sgup,第一眼就像元凶。反编译出来,它干的事是:建一块叫 SGUPSharedUserData 的共享内存,去注册表 HKCU\Software\SGUP 下读一个 WorkingDir,再从那个目录加载 Qt5Core.dll 和 sgup_local_control64.dll。整套动作都在游戏进程和已经跑起来的 STOVE 客户端之间搭桥。

它从不调用 ShellExecute,也不含 sgup:// 字样。第一眼就认错了对象。

字符串要按宽字符扫

STOVE SDK 的字符串大多是 UTF-16。我一开始用普通 strings 扫,什么都扫不到,一度以为这条路断了。换成宽字符扫之后,BaseSDK.dll 里的一句露了出来:

sgup{}://run/{}

这是一条格式串。env 留空,gameId 填上,拼出来就是 sgup://run/lovein_login_secretplus,跟游戏安装清单里那条 sgup://run/...?auto_action=PrepareAndLaunch 对得上。

同一个 DLL 里还有:

  • Please run the game using the launcher.
  • Launcher is not running and launchLauncher is false, so the game will not be restarted.
  • stove_error_need_launcher

导入表里它引了 ShellExecuteW,还引了 RegOpenKeyExW 去读 HKCU\Software\SGUP。类名 IPCForLauncher 也在。

链条到这里就清楚了。SDK 启动时想连本机运行中的 STOVE 客户端,走一套命名管道加共享内存的 IPC。连不上,分两条路走:launch_launcher 为真,就 ShellExecute 打开那个 sgup:// 链接试着把客户端拉起来,客户端没装,Windows 弹框;为假,只写一行日志,不重启进程。

游戏那边还有第二道门

弹窗是第一步。就算把它按掉,STOVE 初始化仍会失败,游戏跟着自己退出。

游戏逻辑编译在托管程序集 Assembly-CSharp.dll 里,用的是 Mono。关键在这:Mono 意味着能改托管层,不必碰原生 DLL。里面有个 PlatformManager,靠场景里几个布尔量选后端。本作有 Steam 和 STOVE 两套,这个包开的是 STOVE。

STOVE 那套叫 StoveManager。它在 Awake 里调 StovePC.Initialize,然后等回调:拿用户、查所有权,查不到就 Application.Quit()。失败路径一样,初始化或取用户出错,退进程。

换成 Steam 后端也不行

看起来有条捷径:把后端标志改成 Steam。

试了,不通。代码里到处是这种分支:非 Steam 时用 gallerySpr 这套数据,Steam 时用 gallerySprSwitch。gallerySprSwitch 是 Switch 变体的资源,这个 STOVE 包里是空的。硬切过去,第一处访问 .Length 就空引用崩溃。

那就保留 STOVE 标志,让它继续用 gallerySpr,换个地方动手。

改了四个字节

STOVE 的初始化和退出,全在 StoveManager 里。我把这几个方法的开头改成返回:

方法原字节改成
StoveManager.Initialize732A
StoveManager.QuitApplication732A
StoveAchievementHandler.UnlockAchievement02 6F16 2A
StoveAchievementHandler.SetStat02 1616 2A

2A 是 IL 的 ret。把它打在方法体第一个字节上,方法就空了,后面的指令成了不可达代码。动的是方法体开头那几个字节,长度没变,元数据没动,后面方法的偏移不会连锁变化,不用重新编译程序集。

四个里最要紧的是第一个。Initialize 一空,StovePC.Initialize 就不会被调用,原生 SDK 一次都不启动,也就没有那个 sgup://,没有弹窗。没有失败回调,就没有自杀。QuitApplication 一起清空,是保险。

成就那两个方法是剩下唯一会碰原生 STOVE 接口的地方。返回值没人用,让它返回 NoError 就行。

动手前我把整份反编译源码搜过:STOVE 相关的引用只在 StoveManager 和成就那两个类里。没有别的代码读 STOVE 的用户或所有权,也没有界面卡在等 STOVE 回调。

STOVE 不初始化,剧情和界面照走。

本文版权遵循 CC BY-NC 协议 和 本站版权政策

(。>︿<。) 已经一滴回复都不剩了哦~