所有由esterTion发布的文章

DragaliaLost速览

西歪祖传底层套件

Crackify检测越狱/root

ConeShell隐藏global-metadata.dat

 coneshell_extract_metadata.php

(ConeShell推测命名来源见重拾cdb结尾)

[CriWare Key Logger]Key: 2967411924141 hex: 000002B2 E7889CAD

10/11 无责任更新:按照反馈,CRI v2.98更新了加密方法(向后兼容的更新)。本人不负责解密算法研究。

manifest加密了,解密后大概是个标准AssetBundle

主数据库依然是cdb ver2(0xDA7A 0x0002)

dragalia_lost.7z(ida db + manifest)

我甚至没打开游戏里面,反正也不会有时间玩的,卸载了

重拾cdb

结果自己到头来还是不死心啊

还是去翻腾cdb了,记录下目前进度


9/7

拿出dll跟踪调试看了一阵,发现文件解密只涉及到开头几十行,然后文件内容就已经出来了。所以感觉比想象的稍微容易一些

首先开头有一串变换,变换完后出来一个pem公钥,然后拿着公钥对0x3c开始0x100字节内容进行解密(签名验证),得到内容比对0x2c开始0x10字节

这个没搞懂干啥的,验证文件有效?

然后进行aes解密?目前逻辑还没看懂,已经验证文件头0x8开始0x20长度数据会影响解密结果,0x4 – 0x7和 0x28 – 0x2a数据用途不明,目前看来没有意义,或者可能是后期操作有关。如果弄完密钥对文件0x13c开始到结尾的数据进行解密,就完成了

然后解密完数据直接lz4解压就可以了,虽然目前卡在aes找不出密钥

而且这些是cdb ver2的,ver3按照ios程序汇编diff看是在某一步多了对某个值的位mask操作,暂时先不看


9/8

打开ios 160和167比对后看到,cdb3对第一个初始化函数的参数(原inputPtr+8)进行了变换,而且某个参数(iv?)从+4变成了+20。本想自己提前变换写回文件结果抄完失败了,然后意识到这些部分都是有重叠,所以还是得自己搞出来才行。

但是解密前那两个初始化又是巨复杂子函数,甚至我都不知道内存里面哪个是有效密钥,挨个试都出不来结果。

于是又卡关了,gg。我好苦啊,真正牛逼的都不来帮一下,就我一个鶸在这里倒腾(人家为啥要帮你(错乱))


9/8晚(9/9凌晨)

今晚依然绝赞研究,本来想到昨晚尝试失败,今天也看不懂子函数,还得苟好一阵

然后想到我能不能改dll里面的流程?因为0x4的数据和0x8的数据有重叠,能想到的就是扔到证书验证那里。于是改dll把公钥验证步骤的jnz给noop掉,然后把那个0x4的偏移改到0x3c签名区,最后在外面递进去之前把该做的新版本的变换做好。

结果扔进去后还是失败,ショック。

于是ida复制了一波流程扔进去覆盖昨晚的手抄,F5、F10、F10……然后突然成功了!?

于是复活,等一个cdb ver4


9/22 后记

这次目前好像是稳了,cy暂时没搞什么新动作。经常google关键词也看不到其他有什么研究的,全网唯一拆解?

然后是一些细节,首先是关于那个公钥验证的,后来想了想,这个部分存在的目的是防止客户端加载假冒db,虽然细节想了想好像还是有问题,真正按照路径解密再加密回去覆盖数据段(0x13c~)不就可以了吗,或者可能还有其他我没研究透的验证(后面那么大一块呢)

第二个其实是次日就搞了更新,因为当时成功的过程是因为重新从ida复制了变换代码,所以后来又换回原始dll,变换完放回结果后把ver改回2,倒也确实能用,这就让我有另一个疑惑,0x4开头的数据按代码是读了8字节,但只有4-7影响结果,8-b并没有反应,而且还是密钥部分了(8-17),而按照复制结果来看那两部分并不相同,这又是另一个疑点。不过目前没有需求也就这样咸鱼了


9/27

绝了.jpg

 

Selfsigned certificate and provisioning profile for Xcode iOS building

Doesn’t work in Xcode 10

Xcode now allows anyone with an Apple ID to build and run app, from anywhere. But, what if, I’m jailbroken and not satisfied with 7-days expiration? Or I’m trying to build an open-source app, but can’t build because the bundle id is already taken and submitted to iTunes?

Since we are jailbroken, everything should just work if we use selfsigned certificate. But somehow, Xcode just keeps asking for a “provisioning profile”, and which is kind of messy to play around. But finally I got it working.

Provisioning profile, is a Cryptographic Message Syntax (CMS) signed property list (plist), which includes team, app, and permission info.

For those who don’t want to bother with cert generating and plist signing, you can just take CodeSigning.zip, import the p12 into keychain, open provisioning profile in Xcode, and skip to the last step, and you are all set.

If you’d like to create the cert from scratch, here’s the detailed steps.

Create selfsigned certificate for code signing

Things is different here because we are going to sign the plist, so for key usage you need not only “Code Signing”, but also “Any” and “Email Protection”, everything else should be famillar if you tried to create a code signing cert in the past. Note that you need to fill in “Organizational Unit”, and this will be your team id, so don’t leave white space in here.

Choose Code Signing type and don’t forget to check the “Let me override defaults”

Fill in the Organizational Unit, everything else can leave blanked

Any and Email Protection must be included or you can’t sign the profile later

Create provision plist

Now you have a working certficate, it’s time to create the provision plist. Here is the template plist file:

Here’s a few thing you need to change in this plist.

  • Paste your certificate content after DeveloperCertificates entry. Open Terminal.app and run “security find-certificate -c “iPhone Developer” -p” and copy things between the dashes.
  • Change all the team identifier SELFSIGNED if you chose your own “Organizational Unit” name when creating cert.
  • Change the CreationDate, ExpirationDate, and TimeToLive to match your cert’s validation info.
  • (Optional) Run “uuidgen” in Terminal and change the UUID entry.

Signing the provision profile

After you modified the plist, the easiest way should be running

Though, for some reason, my machine keep running into error. If you have the same problem, export the cert and private key from keychain and sign it with openssl. (Note that the openssl cli utility comes with mac does not have cms function, you might need to compile one yourself or find another platform)

 

Configure Xcode to use the certificate and provisioning profile

So we finally got everything set up, but wait! There’s the last step.

First open the .mobileprovision file in Xcode, it will not react or pop anything, but you can check “~/Library/MobileDevice/Provisioning Profiles” directory if your generated uuid is there.

Then go to project’s “Build Setting” – Signing, select your certificate in “Code Signing Identity”, change “Code Signing Style” to “Manual”, leave “Development Team” empty, and select your provisioning profile in both “Provisioning Profile” and “Provisioning Profile (Deprecated)”

 

Now check the Gerenal tab, and it should not complaint about signing anymore.

プリコネR 1.6 与 cdb、通信加密 与 coneshell.dll

早在版本更新前的一次资源更新的时候,我这边就注意到master db的改动了,新增了一个cdb,编码不明,但应该就是用来新版本的加密版db。当时故障原因是一直以来masterdb manifest只有一行,所以我直接拆逗号,但这一次cdb在unity bundle前面,于是提取失败cron爆炸

当时改完了正规按行读取后就等着新版本了,想着肯定会大改这部分。于是 8/3 的 10002700 更完,一周后1.6就更新了

下完dmm版扔进dnspy,直接看到这么个切换cdb的代码

而当跟随这个OpenCustomVFS之后,发现他调用了一个 coneshell.dll 里面的函数,而这个dll只有一个导出入口,作用是循环输出一个数组里的函数指针

然后就是和dll战了几天,本来想研究透内部逻辑的,然后星月佬一句“你调用不就完了,linux还有wine”,于是…我就扭头去模拟调用了()

不过就算是调用,也要摸好半天各种函数。打开cdb我模拟了半天也没成功,那天我就直接睡了,后来Utaha写了个另一个版本的代码给读出来了,然后调用 sqlite3_backup_init 直接保存出来db了。

就在研究cdb的时候,我又注意到另一个事情:服务器一直在报代理失效,判定原因是返回200但无body内容。而我手动curl的却发现代理没有问题,排查了好久,最后把完整的header和body都带上,果然0长度了。也就是说1.6不仅改了db,还改了通信。那天发现到这里我就去上跑步机了,在跑步时候我就发的“我有种预感,我一会儿还会碰到一个coneshell的调用”。跑完下来继续研究发现果然,unpack里还是一个外部调用。

刚开始本想直接拆一个客户端的响应,但是一直都是unpack出错,最后Utaha给我提说是有一个初始化的函数,输入了udid和随机32B。于是发觉拆解已有响应好像还不如直接自己构造客户端容易

摸了半天之后才算摸清了各个函数的用途与参数

然后经过一通猜测body并对比已有的请求大小,构造出了一堆请求后,才终于看到服务器返回的不是错误的212字节而是492字节了,也就是说构造成功了,接下来就是扔给dll 解包了

但是当我直接扔给了 _g 的时候,他依然给我返回了-1……想了二十分钟整理了下逻辑,意识到如果是游戏正常运行的话,是pack之后等待响应然后紧跟着unpack的,这里会不会有内部状态的改变?于是在unpack之前我又调用了一次pack,这次res正确返回了解包长度,成功了!

于是美滋滋完成编译,rpm源还只有x64 wine,又去找了个一键x86 wine编译在服务器跑了一个小时才跑完。然后就直接扔上去了,于是service back online(

redive/main.php

Coneshell_call/main.cpp


后话:

我挂上了新版本cdb代码,原本猜测的是Hatsune’s Notes现有版本估计就完全死了。但是14号 10002800 更新后发现怎么还有bundle版本的db,虽然有点奇怪cy为什么还不停用传统db,不过他有我就继续用着

这几天其他几位大佬依然在缓慢地彻底研究内部逻辑,我这种不会的咸鱼只能在旁边膜了


8/22 后记2

你西歪太拼了,我这刚完成没几天,现在有了cdb ver.3了,怕是下版本实装


8/28 后记3

cy昨天更了167了,cdb ver3 online

我这种菜渣,拆是不可能拆的,这辈子也看不懂汇编的,您们谁大能收了西歪吧

prcn-ios-1.6.7.7z

等一个最终提交,这破游戏我研究也就到这了,打扰了,告辞

cy,我前天拆cdb的时候,你偷看了吧

b站弹幕重构相关 – 新api+新格式

两周前了吧,b站半废弃了旧版 comment 域名。除了直接访问的xml外都403了,然后接口换到了api下。获取内容是 /x/v1/dm/list.so ,历史弹幕则是 /x/v2/dm/history 底下并且要登录。

昨晚想确认客户端的情况,看到客户端访问的是 /x/v2/dm/list.so ,点开一个一看是个二进制?

因为b ios app的框架魔性加载,clutch没法导出,重新找一个 frida-ios-dump 才成功导出框架。名字很直接,弹幕相关在 BFCDanmaku 里面。用ida打开研究了俩小时,处理函数是 -[BFCDanmakuRemoteParser parseBinaryData: (NSData)data] 。文件格式也是真的暴力。开头一个length,然后读length取一个json,好像是屏蔽用的?这个json可能gz压缩,需要判断开头字节是否1f8b 。然后就是gz压缩的xml。是的还是xml,我还以为用其他格式了,上次那个protobuf本来也挺好,不是很懂。

再观察了一阵,这个和上次pb类似,分段,6min一段。想了想类名大概在线时候用这个动态加载,离线保存还是xml。

bang dream proto相关

本文相关轮子: proto读取导出 | 定时任务本体数据库对比主数据


A python + libil2cpp.so(Android) dumper:

Article: Generating Proto File For Banddream | DNARoma

gist


因为上周的一个想法,写出了redive和cgss的master数据库diff库,还造了一波bundle解压的轮子

redive第三个号被制裁了,平稳科技流也开始查了

土豆的内容星月大佬写离线的时候已经表示过master不可行,都是登录时返回部分master,所以就可以放弃了

然后就是bang了,开搞前我还又去debug了一下,结果看到密钥瞬间才想起power之前给我说过

炸梦通信是protobuf,包括master和manifest也是,所以就必须要提取原始关系才行了。我刚开始还想尝试暴力提取数据,但是内结构和字符串都是wireType 2,没法区分

在之前我已经在Prefare博客上看到过说dump属性什么的,dnspy改了之后也没搞懂怎么看。后来在评论区看到回复才找到

Perfare:邦邦用的是protobuf-net不是Google.Protobuf,不需要.proto文件,你只需要找到带ProtoContractAttrbuit的类并还原出properties上ProtoMemberAttribute的值就可以序列化了

知道入口后就开始观察了,搜索了一波然后看到master数据的类是SuiteMasterGetResponse(基本上各种proto类都叫GetResponse)

观察了下结构之后就开始写proto dumper了,以SuiteMasterGetResponse为入口,循环匹配含有 [ProtoMemberAttribute] 的成员,然后匹配子类递归。匹配中就需要特殊处理,比如xxxx[]就是一个数组,List<xxxx>也是一个数组,Dictionary2<xxx, yyy>就是键值对,观察了下数据分布这里的结构是

即key+value形式

名称和类型之类的导出做完之后,就是tag id了。tag id并不是连续数,所以就需要读取原始数据。每个成员的ProtoMember属性都带一个地址,这个地址是一个函数,每个函数看起来都是这样的:

可以明显看出是个只有5条指令的函数,而id明显就是第3条,那么就只需要读取出立即数就行了

结果这个可以说是整个读取里面最大的坑了。因为某种优化,编译器输出的立即数赋值指令有两种:

movk指令的话,很简单,匹配中间的i位就可以了

但是orr整整卡了我两个小时,在群里大佬stat带领下才逐渐搞明白读取方法

简单讲,从第二字节开始,第一位为0,第二位N表示是否64位,3-8位为immr——旋转数,第三字节1-6为imms——大小数。此处nnnnn恒为11111,表示W31寄存器,即WZR,或读0。立即数结尾imms位设置为1,然后循环右移immr位,即为所读立即数

这里本来imms还表示pattern大小,但其实也没做出来,因为都是32位的pattern。

搞定tag id读取之后就是一路爽了,稍作修改就能输出规范proto。导出代码gist

造完这么个奇怪的轮子之后又得继续造读取轮子。现有的开源实现没找到能快捷转换protobuf到php数组的,估计也是php类型太少会导致格式信息丢失吧。拿出之前读b站弹幕的轮子改了改,换了最近写的FileStream轮子读取内容(Utaha:你要记住自己的本质是一个轮子工(),读完之后再进行字典键值对处理,最后又一个自定义json输出美化的轮子

高潮来了

写完逻辑代码后跑了一遍,但是我在第二遍才加了core.filemode=false,一堆mode change,于是…

一 秒 爽 到

当场恢复了message导出代码,但是主逻辑不见了。今天早上花了一上午grep /dev/sdb1恢复(msys2竟然有这个设备映射),但是p都没找着。于是,又重新造了一遍自己刚造完的轮子(Utaha:你要记住自己的本质是一个轮子工(

这次记录的基本上就这些,还是要感谢各位前辈造好的轮子,我才能这么爽到(x

闲话x2

瞎记录

1、博客的一些更新

  • 服务器

服务器使用水萌大佬的机器也有三个月了,在刚开始的时候因为他们那边也是在不断调不断加东西,所以经常会爆炸,或者重启路由导致ddns ip改变。不过自从过年那次大爆炸之后一来,已经相当稳定运行了半个月了,可喜可贺,可喜可贺。

原始的vultr本来想着会被废置,不过我留下来当作自己的socks代理了(不是ss,纯socks5)不知道为什么好像比别人用的ss还稳,老见到他们说某某又墙了之类的,可能因为只有我一个人用吧(笑

SSL的话,本来我准备换le的野卡,结果还延期公开了。前两天稍微用 acme.sh 测试了一下可以csr同时生成两个域名的证书,爬丝的dnspod api我之前给他搞ddns ip自动更新的时候要过也可以用,到时候再帮他cron上

  • 音乐播放

两周前更改了一下逻辑,之前设置仅在首页播放,因为没有可靠的跨tab通信确保不重复播放的方法。

然后想到了一个方法,用localStorage保存一个值,不存在的时候记录为当前页并自动播放,并设置关闭时删除值;存在且不是当前页的时候不自动播放,不过生成并显示播放器,点击的时候覆盖值并在关闭时删除值

这样就完成了一个简陋的单tab播放的逻辑

  • 侧栏

并不满与现在的顶端固定实现,最理想的是先跟随滚动,到底后固定,继续向下返回时跟随向上,到顶后再固定,这种感觉

写了个跟随scroll的之后发现很难看,去爬丝站上看了看实现发现是动态切换position,虽然美观一些但还是有瑕疵。最后采用了youtube式的侧栏,即独立滚动条

2、CriWare Key Logger

那阵子倒腾redive,虽然说cri的key早都有了,但还是手痒搞了一个这玩意儿

在之前给 @CaiMiao 翻腾PlayerPrefs键名解密的时候看到C# string类的格式的时候对这些对象在内存中的分布又有了一些理解

按照Il2CppDumper导出的类结构,String类是:

然后内存中的结构是这样的:

然后观察了几个其他的结构体后,大概懂了这些对象的组成:存储一个对象存的肯定是个指针,指针指向的地方0-8是所有函数的地址,C风格函数中参数开头会有一个thisPointer,static调用的时候取0,public/private等等调用就传递对象地址。而比如取string.length的时候就是*((int*) (string+0x10) )

而理解了cs的string类的内存表示之后,我就着手写了一个CSStringReader:

而写的时候碰到的坑是我hook了CriWareDecryptionConfig的构造函数,但是永远读不到正确的key string地址。我倒腾了能有两个小时也没搞出来,然后突然想到,会不会是延后设置的?(我在ida中查看构造函数的时候认为已经设置过key的值,所以一直理解是生成的时候已经设置好了)在代码中加了个Timer触发之后果然读取到了正确的stringLength,果然够坑。

在最后为了(未来可能有的)使用简便,把代码固定函数偏移转移到了插件plist中,这样搞其他的就不需要重新编译了,美滋滋

(说起来,我好像不应该用long,key的长度是固定int64,应该用long long的……不管了,都8102了谁还用32位的ios啊(小并感))