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>也是一个数组,Dictionary`2<xxx, yyy>就是键值对,观察了下数据分布这里的结构是

message entries {
  type1 key = 1;
  type2 value = 2;
}

即key+value形式

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

__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条,那么就只需要读取出立即数就行了

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

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位,即为所读立即数

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

2 thoughts on “bang dream proto相关”

  1. 不明覺厲,最近再研究sdorica逆向,搜遍有關global-metadata解密的信息都很少,搜尋引擎剛好顯示這篇有關bang dream也來觀摩觀摩下

回复 D 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax