Skip to content

Instantly share code, notes, and snippets.

@andreacanes
Forked from esterTion/0_generateMessage
Created February 16, 2025 20:49
Show Gist options
  • Save andreacanes/1a8e57a2818ade8b93b0f3c599c5b86c to your computer and use it in GitHub Desktop.
Save andreacanes/1a8e57a2818ade8b93b0f3c599c5b86c 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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment