SC 现在的资源获取方式是我最为在意的一个方面,一来,这方面的内容使用了最高级的保护措施——WebAssembly
,二来是我们要获取资源不可避免的就是与其打交道。
ToC
旧版的获取方式
对于旧版的 SC
而言,资源获取是明文的,现在你还可以看到一些明文获取资源的痕迹,比如:
简单地使用 PIXI
和 pixi-spine
,可以验证其模型是正确可用的:
(在我的记忆中,脚本文件也是明文获取的,只不过执行的时候增加了 eval
而已)
现在的获取方式
现在的获取方式就复杂多了,如下图所示:
可以看到,左边的访问路径是一串意味不明的字符串,而右边的返回内容则是以 CYWL[DI
为标志的二进制内容。通过查看多个返回的 Preview
,我们可以断言:这是一种通用的字符串加密方式。
为什么是字符串呢?因为以素材为代表的二进制文件的返回内容仍然是明文的:
由此,我们得出一个结论:SC 在发出 XHR 请求之前将路径加密,并且对于文本类型的返回内容,服务端会进行加密,客户端需要解密才能获得内容。
路径的加密
路径与文件名
路径的加密实际上用到的是文件的完整相对地址和文件名去除后缀名的部分。完整相对地址指的是以 /assets/
开头的地址,而文件名去除后缀名的部分指的则是注入 enza.fun
中的 enza
。
真正加密用到的函数是 encryptPath
,定义在 WASM
内,这里我们暂且不讲
getQueryString
大家可能留意到了,在访问的路径最后,会有一个 query
存在(?v=xxx
),但这个 query
不加也没事,所以我先摸了(
疑惑
由于现在没正式看 WASM
,所以这里我有点奇怪。照理说这种路径加密应该是可逆的吧,然后在服务器侧加一个转换,这样在之后想要修改加密方式的时候就不需要把所有文件都处理一遍了。
不过想想 SC 除了图片音频资源之外也就这么点内容,其实无所谓了(
资源的解密
资源解密的过程真正需要的其实只有一个 ArrayBuffer
。下面是来自源代码,经过修改的 decryptResource
函数:
具体的内容还是留到之后细读 WASM
吧(咕
WASM
这里只是简单的提一下,真正核心的部分还是留到之后再写(最近也没时间死磕汇编)。SC
的 WASM
是用 Emscripten
生成的,对应的 .js
文件也同样如此。我们知道,Emscripten
生成的脚本是高度泛用的,也就是说实际存在大量的内容是根本用不上的,而这部分内容又会干扰我们的理解。之后如果有时间的话,我会慢慢看这段内容的。如果没有的话,那这个系列可能就要暂时在这里停一下了
Shiny Helper
嘛,不管上面这一大堆字了,来说说虾泥助手。目前虾泥助手已经跟进了资源解密的功能,顺带摸了个 devtool
部分的胚胎。但有时候因为脚本加载速度,可能会有点小问题,这种情况下只要刷新一下就行了(
文本目前是直接输出到 Console
的,所以看起来文本量爆炸(而且有点卡)。之后会想办法做到开发者工具里的(笑)
结语
今天又死磕了一天 SC,一敲 date
发现又是快一点了,我不禁扪心自问,我究竟为什么要逆向呢?
现在想来,今天的动力源泉就是下载资源了吧。从发现花组之后的资源都带了加密之后,我就一直在想怎么把透前辈的 data.atlas
、data.json
和 data.png
提取出来。从加密到解密,总算是弄清楚 SC 这边的流程了。
不得不说的是,从 SC
这里,我学到了很多之前从未思考过的内容。前端我死磕过的也就屑站、雀魂、你校 VPN
(反代)系统,还有就是 SC
了。DLSite
之类的虽然有所接触,但说到底也就图一乐,正好有需求才研究的。
从雀魂那里,我学到的是最基础的前端逆向的知识。雀魂打包没有用到 Webpack
,我感觉充其量就是一个 Gulp+TypeScript
,所以相对来说简单一些。但事实上,雀魂中用到的反逆向内容其实也不少:混淆、压缩、生成 ES5
、还有一个个我也不知道是原来代码就写这样还是故意弄出来的回调(猫粮你们写回调真的不难受吗(
从屑站那里学到的,是常见的混淆字符串,包括 !0
就是 true
,!1
就是 false
,void 0
就是 undefined
这种最基本的等价替换,还有 Webpack 的特征识别,等等等等。你站甚至是我第一次知道 csrf
的启蒙之地,啧。
从你校反代身上学到的,是大量跨域相关的知识,以及 MITM
一个站点的需要做的各种事情,可以说是从 HTTP
请求上给我解构了一遍,我愈发发现自己在整个技术宇宙中的渺小。人的精力是有限的,我更加深刻地认识到了这点。
最后就是 SC
了,从 SC
身上,我学到了什么呢?PIXI
?Spine
?WASM
?
或许有很多,或许又没有多少,但是谁在乎呢。
本来就只是为了开心去做的啊(笑)