标签归档:protobuf

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)

继续阅读bang dream proto相关

关于b站新弹幕格式.pb

格式为google protocol buffer (protobuf)

地址格式为{cid}-{part}.pb,每part包含3分钟的弹幕内容,即边播放边加载模式,如-3.pb包含第6-9分弹幕

在bilibiliPlayer.min.js中有大部分field id的定义,但文件中出现了id12-14

pb格式弹幕 Field常量
1  row (Row)
2  chat_server (string)
3  chat_id (varint32)
4  mission (varint32)
5  max_limit (varint32)
6  source (string)
7  ds (varint32)
8  de (varint32)
9  max_count (varint32)
10 realname (varint32)
11 sectionlen (varint32)(一般为180)
//猜测id
12 duration (float)
13 total_count (varint32)
14 pb_version (varint32)(目前常量1)

pb格式弹幕row Field常量
1  playtime (float)
2  mode (varint32)
3  fontsize (varint32)
4  color (varint32)
5  times (varint32)
6  poolid (varint32)
7  hash (string)
8  dmid (varint32)
9  msg (string)
10 uid (varint32)(暂未出现)
11 uname (string)(暂未出现)

其中varint32为变长度int32格式,具体为每字节只有后7位存储数据,第1位为指示位,为1时继续读取下一字节

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}

文件读取代码样本

<?php
/*
 BiliBili pb danmaku reader
 @author esterTion(esterTionCN@gmail.com)
*/
$pb=fopen('http://comment.bilibili.com/14328539-1.pb','r');

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}
function readString($fp){
	$strLength=readVarInt32($fp);
	return fread($fp,$strLength);
}
$types=array(
	'VARINT'=>0,
	'FIXED64'=>1,
	'DELIMITED'=>2,
	'START_GROUP'=>3,
	'END_GROUP'=>4,
	'FIXED32'=>5
);
$rowCount=0;
while(true){
	$id=fread($pb,1);
	if($id==='')
		break;
	$id=unpack('C',$id)[1];
	$type = $id & 7;
	$id = $id >> 3;
	switch($id){
		case 1:
			$rowLength=readVarInt32($pb);
			echo 'row length:'.$rowLength.' ';
			$end=ftell($pb)+$rowLength;
			$row=array();
			while(ftell($pb) < $end){
				$id=unpack('C',fread($pb,1))[1];
				$id = $id >> 3;
				switch($id){
					case 1:
						$row['playtime']=unpack('f',fread($pb,4))[1];
					break;
					case 2:
						$row['mode']=readVarInt32($pb);
					break;
					case 3:
						$row['fontsize']=readVarInt32($pb);
					break;
					case 4:
						$row['color']=substr(pack('N', readVarInt32($pb) ),2);
					break;
					case 5:
						$row['timestamp']=readVarInt32($pb);
					break;
					case 6:
						$row['poolid']=readVarInt32($pb);
					break;
					case 7:
						$row['hash']=readString($pb);
					break;
					case 8:
						$row['dmid']=readVarInt32($pb);
					break;
					case 9:
						$row['msg']=readString($pb);
					break;
					case 10:
						$row['uid']=readVarInt32($pb);
					break;
					case 11:
						$row['uname']=readString($pb);
					break;
				}
			}
			print_r($row);
			$rowCount++;
		break;
		case 2:
			echo '[chat_server] => '.readString($pb)."\n";
		break;
		case 3:
			echo '[chat_id] => '.readVarInt32($pb)."\n";
		break;
		case 4:
			echo '[mission] => '.readVarInt32($pb)."\n";
		break;
		case 5:
			echo '[max_limit] => '.readVarInt32($pb)."\n";
		break;
		case 6:
			echo '[source] => '.readString($pb)."\n";
		break;
		case 7:
			echo '[ds] => '.readVarInt32($pb)."\n";
		break;
		case 8:
			echo '[de] => '.readVarInt32($pb)."\n";
		break;
		case 9:
			echo '[max_count] => '.readVarInt32($pb)."\n";
		break;
		case 10:
			echo '[realname] => '.readVarInt32($pb)."\n";
		break;
		case 11:
			echo '[sectionlen] => '.readVarInt32($pb)."\n";
		break;
		default:
			switch($type){
				case 0:
					echo '--Unknown ID '.$id.' with varint32 value '.readVarInt32($pb)."\n";
				break;
				case 1:
					echo '--Unknown ID '.$id.' with fixed 64bit data hex '.bin2hex(fread($pb,8))."\n";
				break;
				case 5:
					echo '--Unknown ID '.$id.' with fixed 32bit data hex '.bin2hex(fread($pb,4))."\n";
				break;
				default:
					echo '--Unknown ID '.$id.' with type '.$type."\n";
			}
	}
}
echo $rowCount.' rows in file'."\n";