2022-11-17 更新:
Dankagu Net Enc – 网络通信加密算法
资源汇总:https://pan.baidu.com/s/1eoeaeHBbgw8sHEhsrJVHag
许久不见,又一次来拆一个游戏了。
il2cpp的发展有些太快,两个月前我原本尝试了一下拆idoly pride,然而因为反射调用实在是太多,代码里面全都是动态函数指针,跟踪起来实在是过于艰难,也就放弃了。昨天东方弹幕神乐开放后,一个是为了首先能进去游戏,然后也想着再试一试拆算法逻辑,所以再来一次拆解。
(更新于9月4日)
- 开幕雷击
首先一上来,global-metadata被动了手脚。
UnityFramework直接扔进ida里面先搞一个string list出来,直接搜global-metadata就能找到一个函数调用,跟进去没走几步,看到一个对着内存key异或的地方,真行。
$in = fopen('global-metadata-enc.dat', 'rb'); $out = fopen('global-metadata.dat', 'wb'); $size = unpack('V', fread($in, 4)); $key = array_map('chr', [0xE, 0x75, 0x3B, 0x8E, 0, 0x14, 0xE6, 0xB2]); $enc = fread($in, $size[1]); for ($i=8; $i<strlen($enc); $i++) { $enc[$i] = $enc[$i] ^ $key[$i % 8]; } fwrite($out, $enc);
- 越狱检测
首先一上来就给人卡在touch to start了,大概猜一下就能猜到它是检测了越狱。在dump.cs里畅游了快两个小时的时候,终于是找到了TakshoAuthorizer::GameStart(),底下跟踪之后调用了SecurityChecker::CheckGameStart(),一看就很可疑。
然后,虽然没有直接找到到底在哪里,但是各种调用SecureLibAPI类的函数,过去一看有个isRooted,套娃调用is_p_jb_o_c,然后分别调用 __ccs __cf __cg __csid __cfc __detd __ch __cipl检查各种方面。事实上,因为这开发组不知道从哪里翻来的上古检测逻辑,这一大串我只有cfc检查文件被查到了,剩下的全都不会触发。
这些检查项目所有的字符串全部用了一个奇特的混淆,把每个char都变成了一个int,读取的时候按顺序读int,& 0xff,然后^ 0x19。
至于那个我撞到了的路径检查,他直接用了一个nsstring转了json,最初我尝试了一下直接把那些路径tar一下,确实可以进游戏了。后来我就试了一下直接把string挂了个hook,检测他开头匹配了那个json的话,就换成一个空json,也能进游戏了。这样就不需要再每次删文件了。
- 资源加密
在dump里面直接搜着Encrypt,就路过了一个EncryptorManager类,看起来里面有着各种各样的不同密钥。
解密逻辑主要分为两个,一个是RijndaelEncryptor,看名字就知道是用了Rijndael,进去大略看了一眼用的RFC2898生成key和iv。
而资源之类的则是用了一个叫做LightWeightEncryptor的,初始化的时候用seed生成了一个异或表,表内数据由XorShift类进行生成。数据进来的时候还会带有一个salt,本身就是查表时候会额外有一个偏移量。
这部分代码见 https://gist.github.com/esterTion/26e8500dbec9956fc89eef7daeb97e81
8/10 update
- 内嵌db
其实这个原本是想要找一下具体的判定区间的。不过打开后发现自带的里面没有判定数据,只有判定分值系数。感觉似乎判定数据是可以服务器下发随时变的?看不懂。
以 Raw/db/master_gamedata.dat 为例,使用 lwe(0x99737BBF, 11, 256),解密之后是个.tar.gz,里面放着一个json
- 本地设置存档(Documents/saves)
这里面其实也没有太多有用的东西,不过本地存着的manifest用的salt会在存档里面写着。
不同的存档各自使用不同的seed初始化一个XorShift类,然后对存档数据调用XorShift::SwizzleBytes加解密。加密表如下:
998741 abp 38741151 rgm 45782187 hako 100 dialog_show 200 boost_setting 300 gacha 400 nakayoshicloud 400 announcement_ 500 playmode_ 600 system_setting 700 friend 800 sort_filter 7784741 club 58714163 tmp 5458143 tos
解开之后,0-15是文件头,16-31是checksum,32往后直接是json数据
- 资源manifest
这个算是挺莫名奇妙的一个逻辑,首先最外层要先用1004的lwe打开(编号含义见EncryptorManager类),然后再用1001的Rijndael解开,揭开后里面是一个.tar.gz,存放着一个FlatBuffer。这开发组在这走迷宫呢?放这么多层套娃,真是不嫌累啊?
然后参照上面存档说的,这个地方唯一不确定参数的是1004 lwe用的salt。但实际上,依然可以暴力尝试找出salt来。取数据前16字节,过一遍lwe,过一遍rijn,然后检查开头是不是1f8b就行了。
拿到FlatBuffer,首先肯定是要抄一份schema出来的,照着生成的类也不算很麻烦,然后可以选择扔给flatc让它直接开,也可以生成类然后自己用sdk调用读取。(flatc生成的json,为啥field周围没引号??)
namespace D4L.TakashoFes.Master; table AssetPathRaw { entry:[AssetPathRawEntry]; } table AssetPathRawEntry { ID:uint64; AssetPath:string; HashedPath:string; FileHash:string; FileSize:uint32; FileRev:uint32; FileType:uint32; DownloadOption:uint32; } file_identifier "D4AO"; root_type AssetPathRaw;
DownloadOption & 0xfff就是每个资源自己的salt了
暂时更新这些进展,grpc目前有点懒得搞了,一个是麻烦,而且反正更新的时候抓个manifest就可以拿新卡面了,也没啥必要非搞个更新检查,毕竟都没人真的看
Bonus round:
こんにちは、コメント失礼します。
東方ダンマクカグラのデータをダウンロードしたいのですが
百度のサイト(https://pan.baidu.com/s/1eoeaeHBbgw8sHEhsrJVHag)が使えない?使用するのが困難ので、ファイルをGoogle Driveなどのサイトにも配布していただけないでしょうか?
よろしくお願いいたします。m(_ _)m
sorry but I don’t have enough space to host all the files on places like google drive or mega, this is the only place I know that I can host these files long term, without needing to reupload every month or so.
e佬您好,我看到放出来json里没有安卓素材的salt,然后在filelist里看见有差不多的,安卓的manifest也是是直接用1004的lwe开吗?还是也要过一遍Rijndael 1001,我按您说的试了下解出来的不太对劲,解的是这个
{
"Platform": "android",
"DataVersion": 1280,
"Enable": 2,
"DB": "arg_t_android_r_00001280_20220116-040000_1642273200",
"OpenAt": 1642273200,
"Salt": 2449,
"HashPath": "1/10/1280-2-66ea03bdca2f6f83b6901aae100b94c1344bd51f"
}
感謝大佬指教
用了2001 也是不行後發現要用PHP64版本才會成功
不過DB和SAVE 還未成功 但資源和manifest都成功了
而且找到了大佬說1004 lwe 用的salt 在GRPC
CommonFeatureset.PlayerApi.OndemandMaster.GetEntriesV1的這個AssetUploadV2+v1_2_0_any+g154裡有回
看了一下裡面應該還有未來數據的manifest 想必大佬應該早就弄了cronjob自動下載
JSON LIST在這裡 過幾天會刪
https://drive.google.com/file/d/1zZETUA8Ni6G3nARw_Yd0UMxRgNV6BIu-/view