Skip to content

Instantly share code, notes, and snippets.

@esterTion
Last active July 4, 2025 20:37
Show Gist options
  • Save esterTion/768c646a83a089af9e5fbb83b77a59fc to your computer and use it in GitHub Desktop.
Save esterTion/768c646a83a089af9e5fbb83b77a59fc to your computer and use it in GitHub Desktop.
Bang Dream proto dumper
gist title place holder

Used to dump proto defination from BangDream, meant to dump ios binary

First, modify Il2Cpp (like using dnspy) to dump Properties. (Config.dumpProperty = true)
Then dump the game as usual
Modify generateMessage.php to match your binary and dump.cs file
And run php generateMessage.php <messageClass>

Example proto output attached

Notice: Dictionary is outputed as two elements message, 1 for key, and 2 for value


用于导出BangDream proto定义文件,可用在ios程序上
首先修改Il2Cpp(比如用dnspy)使之导出属性(Config.dumpProperty = true)
然后导出程序内容
修改 generateMessage.php内的程序与 dump.cs 文件位置
然后运行 php generateMessage.php <messageClass>

后附样例proto输出

注意:Dictionary 键值对输出为两元素结构,1为键,2为值

<?php
/**
* https://gist.github.com/esterTion/768c646a83a089af9e5fbb83b77a59fc
* Updated for il2cpp-dumper v6.1.2
* https://github.com/Perfare/Il2CppDumper/releases
*/
$dumpcs = file_get_contents('D:\\ida_workplace\\bang\\dump.cs');
$prog = fopen('D:\\ida_workplace\\bang\\UnityFramework','rb');
$definedClass=[];
$class = $argv[1];
$outputProtoFile = fopen(__DIR__.'/'.$class.'_gen.proto', 'w');
fwrite($outputProtoFile, "syntax = \"proto2\";\n");
function stripClass($s) {
$idx = strrpos($s, '.');
if ($idx === false) return $s;
return substr($s, $idx + 1);
}
function writeMessage($class, $message) {
global $outputProtoFile;
$class = stripClass($class);
fwrite($outputProtoFile, "message ${class} {\n");
foreach ($message as $item=>$info) {
$type = stripClass($info[0]);
$tag = $info[1];
$hint = $info[2];
$comment = $info[3];
fwrite($outputProtoFile, " ${hint} ${type} ${item} = ${tag}; // ${comment}\n");
}
fwrite($outputProtoFile, "}\n");
}
function readClass($level, $class) {
global $dumpcs;
global $definedClass;
if (($shownClass = array_search($class, $definedClass)) === false) {
$definedClass[] = $class;
}
$message = [];
//echo str_repeat(" ", $level).$class."\n";
if (preg_match("(\[ProtoContract\].*\n\w+ class ".$class." [^{}]*?(\{((?>[^{}]+)|(?-2))*\}))", $dumpcs, $classDef) !== 0) {
$classDef=$classDef[0];
preg_match_all('(\[ProtoMember\((\d+)\)\].*\n \w+ ([^\ \<]+(\<((?>[^\<\>]+)|(?-2))*\>)?) ([^\ ;]+))', $classDef, $propList);
for($i=0;$i<count($propList[0]); $i++) {
$type = jumpType(
$level,
$propList[2][$i],
$propList[5][$i]
);
$message[$type[0]] = [$type[1], $propList[1][$i], $type[2], $type[3]];
}
if ($class == 'MasterActionSet') {
$message['areaName'] = [
'string',
6,
'optional',
'manual add'
];
}
if (!$shownClass) {
echo $class."\n";
//print_r($message);
writeMessage($class, $message);
}
unset($message);
} else {
echo $class.' not found';
exit;
}
}
// 1012ECB5C 1
// 1012ECB70 2
function jumpType ($level, $type, $name) {
if (substr($type, -2, 2) == '[]') {
// array entry
//echo str_repeat(" ", $level+1).$type."\n";
$sub = jumpType($level+2, substr($type, 0, -2), 'entry');
return [$name, $sub[1], 'repeated', 'array'];
} else if (substr($type, 0, 11) == 'Dictionary<') {
// dictionary
preg_match('(<(\w+), (\w+)>)', $type, $subType);
//echo str_repeat(" ", $level+1).'dictarr_'.$name."[]\n";
$prefix = $subType[1].'_'.$subType[2];
global $definedClass;
if (($shownClass = array_search($prefix, $definedClass)) === false) {
$definedClass[] = $prefix;
}
$message = [];
$sub = jumpType($level+1, $subType[1], $prefix.'_key');
$message[$sub[0]] = [$sub[1], 1, $sub[2], $sub[3]];
$sub = jumpType($level+1, $subType[2], $prefix.'_value');
$message[$sub[0]] = [$sub[1], 2, $sub[2], $sub[3]];
if (!$shownClass) {
writeMessage($prefix, $message);
}
return [$name,$prefix, 'repeated', 'dictionary'];
} else if (substr($type, 0, 5) == 'List<') {
// array entry
preg_match('(<(\w+)>)', $type, $subType);
//echo str_repeat(" ", $level+1).'arr_'.$name."[]\n";
$sub = jumpType($level+1, $subType[1], 'entry');
return [$name,$sub[1], 'repeated', 'list'];
} else if (array_search($type,
['uint','string','ulong','float','int','double', 'bool','long']
) !== false){
// normal type
//echo str_repeat(" ", $level+1).'<'.$type .'> '. $name."\n";
return [$name,array('uint'=>'uint32','string'=>'string','ulong'=>'uint64','float'=>'float','int'=>'int32','double'=>'double', 'bool'=>'bool','long'=>'int64')[$type], 'optional', 'normal type'];
} else if (substr($type, 0, 9) == 'Nullable<') {
// array entry
//echo str_repeat(" ", $level+1).'<'.$type .'> '. $name."\n";
//return [$name,$type, 'optional', 'nullable type'];
preg_match('(<(\w+)>)', $type, $subType);
$return = jumpType($level, $subType[1], $name);
$return[3] = 'nullable';
return $return;
} else {
// sub message
readClass($level+1, $type);
return [$name,$type, 'optional', 'sub class'];
}
}
readClass(0, $class);
@esterTion
Copy link
Author

@dlbuhtig4096
一般来说,grpc同时涉及dns拦截和证书绑定,而且不认系统库。
也就是,只使用proxy(包括socks)、及mitm关闭pinning,是没有用的。
以dankagu时候的例子,需要手动修改dns,将player-api-production.danmakujp-server.com指向局域网内的电脑,同时还需要修改绑定的证书。dankagu的证书公钥是存放在resources.assets里面的sc TextAsset内加密存储的(ServerConfig)
图片
图片
这个如果不是当时要关服了,我也不会去搞这个抓包存自己的玩家数据。
如果同样是 Takasho 库的话,可能有个类似的加密服务器配置项目,需要自己修改后重新打包进assets内

@dlbuhtig4096
Copy link

dlbuhtig4096 commented Jan 27, 2025

@esterTion 原來如此,怪不得都抓不到
我還奇怪為什麼代理設定看起來都沒有作用
ServerConfig 這個 class 我再研究看看,謝謝

我好像有在 /1cc/ 看過你和其他人的討論
如果你對這遊戲有興趣的話,我之後可以分享 proto dumper 和加解密的 code

@0xS4D
Copy link

0xS4D commented Jan 31, 2025

@esterTion 原來如此,怪不得都抓不到 我還奇怪為什麼代理設定看起來都沒有作用 ServerConfig 這個 class 我再研究看看,謝謝

我好像有在 /1cc/ 看過你和其他人的討論 如果你對這遊戲有興趣的話,我之後可以分享 proto dumper 和加解密的 code

I’ve been working hard trying to capture the messages from Pokémon TCG Pocket. I tried everything—Charles, MITM, Burp. I got the global-metadata and managed to extract the DLLs (both iOS and Android), but I couldn’t create a Frida script that hooks the functions correctly without crashing, nor could I extract data from the sent/received packets.

With IDA, I found the certificates, but I couldn’t make any further progress.

If you managed to read the packets, could you give me a hand?

My Discord is 0xs4d.

@dlbuhtig4096
Copy link

dlbuhtig4096 commented Jan 31, 2025

@esterTion 原來如此,怪不得都抓不到 我還奇怪為什麼代理設定看起來都沒有作用 ServerConfig 這個 class 我再研究看看,謝謝
我好像有在 /1cc/ 看過你和其他人的討論 如果你對這遊戲有興趣的話,我之後可以分享 proto dumper 和加解密的 code

I’ve been working hard trying to capture the messages from Pokémon TCG Pocket. I tried everything—Charles, MITM, Burp. I got the global-metadata and managed to extract the DLLs (both iOS and Android), but I couldn’t create a Frida script that hooks the functions correctly without crashing, nor could I extract data from the sent/received packets.

With IDA, I found the certificates, but I couldn’t make any further progress.

If you managed to read the packets, could you give me a hand?

My Discord is 0xs4d.

@0xS4D I haven't get packets capture working yet.
Was working on dumping proto from the game.
And I am almost there, dumped protos are publicly available in this repo.

Actually I have tried Frida few days ago and it crashed as well.
I will probably give frida-il2cpp-bridge a try few days later.
Have send you friend request on discord.

@esterTion 就像上面說的,我開了一個 public repo
現在只有 proto,順利的話之後會做個 python client 然後開源在上面
不過我通常只逆向單機遊戲,不太碰網遊
所以別說 grpc 了,我連一般的 rpc 都沒怎麼碰過,只知道個大概
其他人也都是第一次碰 grpc

如果有個熟悉通訊的人在,相信這個 project 容易很多
有興趣一起研究的話,請再通知我們一聲

@andreacanes
Copy link

andreacanes commented Feb 16, 2025

Hey guys very interested in your work, I was wondering if you'd like to connect and talk about this, I know a few weeks went by but I would to discuss this with someone like you, I have gotten pretty far, and I managed to decompile the apk and dump dlls and classes and methods with il2cpp-bridge.
If you want to use frida I have been able to only successfully set it up on 1 emulator, everything else seem to not work or if it does it still won't let you access the emulated realm for il2cpp-bridge.
@dlbuhtig4096 Would it be possible to access the dumped proto you mentioned? I'm about to dive into that and it would save me some time. I would also love to work with you on the replicating request part as that is where I have lots of previous experience.
@0xS4D I also sent you a friend request if you'd be interesting in working on this

My expertise is more on the side of rebuilding and replicating requests but I had lots of fun getting my hands on something new.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment