因为上周的一个想法,写出了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>也是一个数组,Dictionary
2<xxx, yyy>就是键值对,观察了下数据分布这里的结构是
1 2 3 4 |
message entries { type1 key = 1; type2 value = 2; } |
即key+value形式
名称和类型之类的导出做完之后,就是tag id了。tag id并不是连续数,所以就需要读取原始数据。每个成员的ProtoMember属性都带一个地址,这个地址是一个函数,每个函数看起来都是这样的:
1 2 3 4 5 6 7 |
__text:0000000101320B5C sub_101320B5C ; DATA XREF: __const:000000010256B948↓o __text:0000000101320B5C LDR X8, [X0,#8] __text:0000000101320B60 LDR X0, [X8] __text:0000000101320B64 MOV W1, #1 __text:0000000101320B68 MOV X2, #0 __text:0000000101320B6C B ProtoMemberAttribute$$.ctor __text:0000000101320B6C ; End of function sub_101320B5C |
可以明显看出是个只有5条指令的函数,而id明显就是第3条,那么就只需要读取出立即数就行了
结果这个可以说是整个读取里面最大的坑了。因为某种优化,编译器输出的立即数赋值指令有两种:
1 2 3 4 5 |
movk Rd HALF xx1x 0010 1xxi iiii iiii iiii iiid dddd orr Rd_SP Rn LIMM x01x 0010 0Nii iiii iiii iinn nnnd dddd |
movk指令的话,很简单,匹配中间的i位就可以了
但是orr整整卡了我两个小时,在群里大佬stat带领下才逐渐搞明白读取方法
简单讲,从第二字节开始,第一位为0,第二位N表示是否64位,3-8位为immr——旋转数,第三字节1-6为imms——大小数。此处nnnnn恒为11111,表示W31寄存器,即WZR,或读0。立即数结尾imms位设置为1,然后循环右移immr位,即为所读立即数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
function readInst($inst) { $chk = $inst & 0x6f800000; if ($chk == 0x42800000) { $imme = ($inst & 0x1fffe0) >> 5; $dest = $inst & 0x1f; //echo "\tmov \tW${dest}, #${imme}\n"; return $imme; } else if ($chk == 0x22000000) { $N =($inst & 0x400000) != 0; $immr =($inst & 0x3f0000) >>16; $imms =($inst & 0xfc00) >>10; $dest = $inst & 0x1f; if ($N) { $size = 64; } else { $size = 32; $mask = 0x20; while($size > 1) { if (($imms & $mask) == 0) break; $size /= 2; $mask /= 2; } } $S = $imms+1; $pattern = bindec( str_repeat(str_pad(str_repeat('1', $S), $size, '0', STR_PAD_LEFT), 32 / $size)); $imme = rotate($pattern, $immr); //echo "\torr \tW${dest}, W31, #${imme}\n"; return $imme; } else { echo decbin($inst)."\n"; throw new Exception('unknown'); } } |
这里本来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