Skip to content

Instantly share code, notes, and snippets.

@esterTion
Last active April 28, 2025 19:06
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);
@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