Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save azliabdullah/5bf3d645b7d3fd4a9fc6632c51521d33 to your computer and use it in GitHub Desktop.

Select an option

Save azliabdullah/5bf3d645b7d3fd4a9fc6632c51521d33 to your computer and use it in GitHub Desktop.

Revisions

  1. @dnaroma dnaroma revised this gist Apr 30, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Gen Proto BanG Dream.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@
    This is the code rewritten in Python 3 from the original code of esterTion's [PHP version](https://gist.github.com/esterTion/768c646a83a089af9e5fbb83b77a59fc)
    This is the code rewritten in Python 3 from the original code of esterTion's [PHP version](https://gist.github.com/esterTion/768c646a83a089af9e5fbb83b77a59fc). **Only works with blobs from Android apk!!!**

    `genProto.py` for old versions, `genProto.py` for new versions with arm64 blobs.
  2. @dnaroma dnaroma revised this gist Apr 30, 2020. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion Gen Proto BanG Dream.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,3 @@
    This is the code rewritten in Python 3 from the original code of esterTion's [PHP version](https://gist.github.com/esterTion/768c646a83a089af9e5fbb83b77a59fc)
    This is the code rewritten in Python 3 from the original code of esterTion's [PHP version](https://gist.github.com/esterTion/768c646a83a089af9e5fbb83b77a59fc)

    `genProto.py` for old versions, `genProto.py` for new versions with arm64 blobs.
  3. @dnaroma dnaroma renamed this gist Apr 30, 2020. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. @dnaroma dnaroma revised this gist Mar 16, 2020. 1 changed file with 137 additions and 0 deletions.
    137 changes: 137 additions & 0 deletions genProto_arm64.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,137 @@
    from struct import unpack
    import re
    import sys

    dumpcs = open('dump.cs', encoding="utf8").read()
    prog = open('libil2cpp.so', 'rb')

    definedClass = []
    targetClass = sys.argv[1] #'SuiteMasterGetResponse' # change to get different classes
    outputPath = './{}.proto'.format(targetClass)
    outputFile = open(outputPath, 'w')
    # write first line
    outputFile.write('syntax = "proto2";\n')
    # outputFile.write('package bang;\n')

    typeMap = {
    'uint': 'uint32',
    'string': 'string',
    'ulong': 'uint32',
    'float': 'float',
    'int': 'int32',
    'double': 'double',
    'bool': 'bool',
    'long': 'int32'
    }

    def getTag(address):
    offset = address & 0xFFFFFFFF

    prog.seek(offset)
    inst = prog.read(4)
    inst = int.from_bytes(inst, byteorder='little', signed=False)
    if inst == 0xf9400408:
    prog.seek(offset + 4)
    inst = int.from_bytes(prog.read(4), 'little', signed=False)
    elif inst == 0xf81e0ff3:
    prog.seek(offset + 16)
    inst = int.from_bytes(prog.read(4), 'little', signed=False)
    else:
    print(hex(inst), hex(address))
    return None
    if inst >> 24 == 0x52:
    return (inst >> 5) & 0xFFFF
    elif inst >> 24 == 0x32:
    retnum = (inst >> 8) & 0xFFFF
    immr = (retnum >> 8) & 0x3F
    imms = (retnum >> 2) & 0x3F
    clz = lambda x: "{:032b}".format(x).index("1")
    _len = 31 - clz((0 << 6) | (~imms & 0x3F))
    _size = 1 << _len
    R = immr & (_size - 1)
    S = imms & (_size - 1)
    ret = (1 << (S+1)) - 1
    for i in range(immr):
    ret = rotr(ret, 32)
    return ret


    def rotr(num, bits):
    num &= (2**bits-1)
    bit = num & 1
    num >>= 1
    if(bit):
    num |= (1 << (bits-1))

    return num

    def writeMessage(target, message):
    outputFile.write('message {} {{\n'.format(target))
    for item, info in message.items():
    typ = info[0]
    if type(info[1]).__name__ == 'str':
    tag = getTag(int(info[1], 16))
    else:
    tag = info[1]
    hint = info[2]
    comment = info[3]
    if hint == 'map':
    outputFile.write(' {}{} {} = {};\n'.format(hint, typ, item, tag))
    else:
    outputFile.write(' {} {} {} = {};\n'.format(hint, typ, item, tag))
    outputFile.write('}\n')

    def readClass(level, target):
    try:
    definedClass.index(target)
    shownClass = True
    except ValueError:
    definedClass.append(target)
    shownClass = False

    message = {}
    classDef = re.search('\[ProtoContractAttribute\].*?\n.*?class ' + target + ' [^\{\}]*?\{((.*\n)*?)?\s+(//\s+Properties(.*\n)*?)?\s+(//\s+Methods(.*\n)*?)?\}\s*?', dumpcs)
    if not classDef:
    print('{} not found'.format(target))
    else:
    propList = re.findall('(\[ProtoMemberAttribute\] //.*Offset: 0x([0-9A-F]+).+?\n \w+ ([^\ \<]+(\<(.*?)\>)?) ([^\ ;]+))', classDef[0])
    for prop in propList:
    typ = jumpTyp(level, prop[2], prop[5])
    message[typ[0]] = [typ[1], prop[1], typ[2], typ[3]]
    if not shownClass:
    # print('{} \n'.format(target))
    writeMessage(target, message)

    def jumpTyp(level, typ, name):
    if typ[-2:] == '[]':
    sub = jumpTyp(level + 2, typ[0:-2], 'entry')
    return [name, sub[1], 'repeated', 'array']
    elif typ[0:10] == 'Dictionary':
    subType = re.search('<(\w+), (\w+)>', typ)
    readClass(level + 1, subType[2])
    return [name, '<{}, {}>'.format(typeMap.get(subType[1], subType[1]), typeMap.get(subType[2], subType[2])), 'map', 'dictionary']
    elif typ[0:4] == 'List':
    subType = re.search('<(\w+)>', typ)
    sub = jumpTyp(level + 1, subType[1], 'entry')
    return [name, sub[1], 'repeated', 'list']
    elif typ[0:8] == 'Nullable':
    subType = re.search('<(\w+)>', typ)
    sub = jumpTyp(level, subType[1], name)
    sub[3] = 'nullable'
    return sub
    else:
    expectTyp = ['uint','string','ulong','float','int','double', 'bool','long']
    try:
    expectTyp.index(typ)
    isType = True
    except ValueError:
    expectTyp.append(typ)
    isType = False

    if isType:
    return [name, typeMap[typ], 'optional', 'normal type']
    else:
    readClass(level + 1, typ)
    return [name, typ, 'optional', 'sub class']

    readClass(0, targetClass)
  5. DNARoma revised this gist Apr 5, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions genProto.py
    Original file line number Diff line number Diff line change
    @@ -15,12 +15,12 @@
    typeMap = {
    'uint': 'uint32',
    'string': 'string',
    'ulong': 'uint32',
    'ulong': 'uint64',
    'float': 'float',
    'int': 'int32',
    'double': 'double',
    'bool': 'bool',
    'long': 'int32'
    'long': 'int64'
    }

    def getTag(address):
  6. DNARoma revised this gist Mar 15, 2019. 1 changed file with 22 additions and 48 deletions.
    70 changes: 22 additions & 48 deletions genProto.py
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@

    definedClass = []
    targetClass = sys.argv[1] #'SuiteMasterGetResponse' # change to get different classes
    outputPath = './jp/{}.proto'.format(targetClass)
    outputPath = './{}.proto'.format(targetClass)
    outputFile = open(outputPath, 'w')
    # write first line
    outputFile.write('syntax = "proto2";\n')
    @@ -31,71 +31,45 @@ def getTag(address):
    inst = int.from_bytes(inst, byteorder='little', signed=False)
    if inst == 0xe5900004: #0x080440f9:
    prog.seek(offset + 4)
    return int.from_bytes(prog.read(2), 'little', signed=False) & 0xfff
    retnum = int.from_bytes(prog.read(2), 'little', signed=False)
    rotate_flag = int.from_bytes(prog.read(1), 'little', signed=False)
    if rotate_flag == 0xA0:
    # rotate tag number
    rotate_num = (retnum >> 8) & 0xF
    tag = retnum & 0xFF
    for i in range(rotate_num * 2):
    tag = rotr(tag, 32)
    return tag
    return retnum & 0xfff
    elif inst == 0xe92d4c10:
    prog.seek(offset + 12)
    return int.from_bytes(prog.read(2), 'little', signed=False) & 0xfff
    else:
    print(hex(inst), hex(address))

    return readInst(inst)

    def readInst(inst):
    chk = inst & 0x6f800000
    if chk == 0x42800000:
    imme = (inst & 0x1fffe0) >> 5
    dest = inst & 0x1f
    return imme
    elif 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 = int((('1' * S).ljust(size, '0')) * (32 / size))
    imme = rotate(pattern, immr)
    return imme
    else:
    print('Not found inst=' + inst)
    def rotr(num, bits):
    num &= (2**bits-1)
    bit = num & 1
    num >>= 1
    if(bit):
    num |= (1 << (bits-1))

    def rotate(pattern, rotate):
    result = pattern
    while rotate > 0:
    low = result & 1
    result >>= 1
    rotate -= 1
    if low == 1:
    result |= 0x80000000
    return result
    return num

    def writeMessage(target, message):
    outputFile.write('message {} {{\n'.format(target))
    for item, info in message.items():
    typ = info[0]
    if type(info[1]).__name__ == 'str':
    tag = getTag(int(info[1], 16))
    if tag == 0xf4b:
    tag = 0x12c
    else:
    tag = info[1]
    hint = info[2]
    comment = info[3]
    if hint == 'map':
    outputFile.write(' {}{} {} = {}; // {}\n'.format(hint, typ, item, tag, comment))
    outputFile.write(' {}{} {} = {};\n'.format(hint, typ, item, tag))
    else:
    outputFile.write(' {} {} {} = {}; // {}\n'.format(hint, typ, item, tag, comment))
    outputFile.write(' {} {} {} = {};\n'.format(hint, typ, item, tag))
    outputFile.write('}\n')

    def readClass(level, target):
    @@ -111,12 +85,12 @@ def readClass(level, target):
    if not classDef:
    print('{} not found'.format(target))
    else:
    propList = re.findall('(\[ProtoMemberAttribute\] // 0x([0-9A-F]+)\n \w+ ([^\ \<]+(\<(.*?)\>)?) ([^\ ;]+))', classDef[0])
    propList = re.findall('(\[ProtoMemberAttribute\] //.*Offset: 0x([0-9A-F]+)\n \w+ ([^\ \<]+(\<(.*?)\>)?) ([^\ ;]+))', classDef[0])
    for prop in propList:
    typ = jumpTyp(level, prop[2], prop[5])
    message[typ[0]] = [typ[1], prop[1], typ[2], typ[3]]
    if not shownClass:
    print('{} \n'.format(target))
    # print('{} \n'.format(target))
    writeMessage(target, message)

    def jumpTyp(level, typ, name):
  7. DNARoma revised this gist Oct 11, 2018. 1 changed file with 5 additions and 6 deletions.
    11 changes: 5 additions & 6 deletions genProto.py
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,13 @@
    from struct import unpack
    import re
    import sys

    dumpcs = open('dump.cs').read()
    prog = open('libil2cpp.so', 'rb')

    definedClass = []
    targetClass = 'SuiteMasterGetResponse' # change to get different classes
    outputPath = './{}_gen.proto'.format(targetClass)
    targetClass = sys.argv[1] #'SuiteMasterGetResponse' # change to get different classes
    outputPath = './jp/{}.proto'.format(targetClass)
    outputFile = open(outputPath, 'w')
    # write first line
    outputFile.write('syntax = "proto2";\n')
    @@ -28,7 +29,7 @@ def getTag(address):
    prog.seek(offset)
    inst = prog.read(4)
    inst = int.from_bytes(inst, byteorder='little', signed=False)
    if inst == 0xe5900004:
    if inst == 0xe5900004: #0x080440f9:
    prog.seek(offset + 4)
    return int.from_bytes(prog.read(2), 'little', signed=False) & 0xfff
    elif inst == 0xe92d4c10:
    @@ -98,7 +99,6 @@ def writeMessage(target, message):
    outputFile.write('}\n')

    def readClass(level, target):
    print(target)
    try:
    definedClass.index(target)
    shownClass = True
    @@ -107,13 +107,12 @@ def readClass(level, target):
    shownClass = False

    message = {}
    classDef = re.search('class ' + target + ' [^\{\}]*?\{((.*\n)*?)?\s+(//\s+Properties(.*\n)*?)?\s+(//\s+Methods(.*\n)*?)?\}\s*?', dumpcs)
    classDef = re.search('\[ProtoContractAttribute\].*?\n.*?class ' + target + ' [^\{\}]*?\{((.*\n)*?)?\s+(//\s+Properties(.*\n)*?)?\s+(//\s+Methods(.*\n)*?)?\}\s*?', dumpcs)
    if not classDef:
    print('{} not found'.format(target))
    else:
    propList = re.findall('(\[ProtoMemberAttribute\] // 0x([0-9A-F]+)\n \w+ ([^\ \<]+(\<(.*?)\>)?) ([^\ ;]+))', classDef[0])
    for prop in propList:
    print(prop)
    typ = jumpTyp(level, prop[2], prop[5])
    message[typ[0]] = [typ[1], prop[1], typ[2], typ[3]]
    if not shownClass:
  8. @dnaroma dnaroma created this gist Sep 15, 2018.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    This is the code rewritten in Python 3 from the original code of esterTion's [PHP version](https://gist.github.com/esterTion/768c646a83a089af9e5fbb83b77a59fc)
    170 changes: 170 additions & 0 deletions genProto.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,170 @@
    from struct import unpack
    import re

    dumpcs = open('dump.cs').read()
    prog = open('libil2cpp.so', 'rb')

    definedClass = []
    targetClass = 'SuiteMasterGetResponse' # change to get different classes
    outputPath = './{}_gen.proto'.format(targetClass)
    outputFile = open(outputPath, 'w')
    # write first line
    outputFile.write('syntax = "proto2";\n')

    typeMap = {
    'uint': 'uint32',
    'string': 'string',
    'ulong': 'uint32',
    'float': 'float',
    'int': 'int32',
    'double': 'double',
    'bool': 'bool',
    'long': 'int32'
    }

    def getTag(address):
    offset = address & 0xFFFFFFFF

    prog.seek(offset)
    inst = prog.read(4)
    inst = int.from_bytes(inst, byteorder='little', signed=False)
    if inst == 0xe5900004:
    prog.seek(offset + 4)
    return int.from_bytes(prog.read(2), 'little', signed=False) & 0xfff
    elif inst == 0xe92d4c10:
    prog.seek(offset + 12)
    return int.from_bytes(prog.read(2), 'little', signed=False) & 0xfff
    else:
    print(hex(inst), hex(address))

    return readInst(inst)

    def readInst(inst):
    chk = inst & 0x6f800000
    if chk == 0x42800000:
    imme = (inst & 0x1fffe0) >> 5
    dest = inst & 0x1f
    return imme
    elif 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 = int((('1' * S).ljust(size, '0')) * (32 / size))
    imme = rotate(pattern, immr)
    return imme
    else:
    print('Not found inst=' + inst)

    def rotate(pattern, rotate):
    result = pattern
    while rotate > 0:
    low = result & 1
    result >>= 1
    rotate -= 1
    if low == 1:
    result |= 0x80000000
    return result

    def writeMessage(target, message):
    outputFile.write('message {} {{\n'.format(target))
    for item, info in message.items():
    typ = info[0]
    if type(info[1]).__name__ == 'str':
    tag = getTag(int(info[1], 16))
    if tag == 0xf4b:
    tag = 0x12c
    else:
    tag = info[1]
    hint = info[2]
    comment = info[3]
    if hint == 'map':
    outputFile.write(' {}{} {} = {}; // {}\n'.format(hint, typ, item, tag, comment))
    else:
    outputFile.write(' {} {} {} = {}; // {}\n'.format(hint, typ, item, tag, comment))
    outputFile.write('}\n')

    def readClass(level, target):
    print(target)
    try:
    definedClass.index(target)
    shownClass = True
    except ValueError:
    definedClass.append(target)
    shownClass = False

    message = {}
    classDef = re.search('class ' + target + ' [^\{\}]*?\{((.*\n)*?)?\s+(//\s+Properties(.*\n)*?)?\s+(//\s+Methods(.*\n)*?)?\}\s*?', dumpcs)
    if not classDef:
    print('{} not found'.format(target))
    else:
    propList = re.findall('(\[ProtoMemberAttribute\] // 0x([0-9A-F]+)\n \w+ ([^\ \<]+(\<(.*?)\>)?) ([^\ ;]+))', classDef[0])
    for prop in propList:
    print(prop)
    typ = jumpTyp(level, prop[2], prop[5])
    message[typ[0]] = [typ[1], prop[1], typ[2], typ[3]]
    if not shownClass:
    print('{} \n'.format(target))
    writeMessage(target, message)

    def jumpTyp(level, typ, name):
    if typ[-2:] == '[]':
    sub = jumpTyp(level + 2, typ[0:-2], 'entry')
    return [name, sub[1], 'repeated', 'array']
    elif typ[0:11] == 'Dictionary`':
    subType = re.search('<(\w+), (\w+)>', typ)
    readClass(level + 1, subType[2])
    # prefix = '{}_{}'.format(subType[1], subType[2])

    # try:
    # definedClass.index(prefix)
    # shownClass = True
    # except ValueError:
    # definedClass.append(prefix)
    # shownClass = False
    # message = {}
    # sub = jumpTyp(level + 1, subType[1], '{}_key'.format(prefix))
    # message[sub[0]] = [sub[1], 1, sub[2], sub[3]]
    # sub = jumpTyp(level + 1, subType[2], '{}_value'.format(prefix))
    # message[sub[0]] = [sub[1], 2, sub[2], sub[3]]
    # if not shownClass:
    # writeMessage(prefix, message)
    return [name, '<{}, {}>'.format(typeMap.get(subType[1], subType[1]), typeMap.get(subType[2], subType[2])), 'map', 'dictionary']
    elif typ[0:5] == 'List`':
    subType = re.search('<(\w+)>', typ)
    sub = jumpTyp(level + 1, subType[1], 'entry')
    return [name, sub[1], 'repeated', 'list']
    elif typ[0:9] == 'Nullable`':
    subType = re.search('<(\w+)>', typ)
    sub = jumpTyp(level, subType[1], name)
    sub[3] = 'nullable'
    return sub
    else:
    expectTyp = ['uint','string','ulong','float','int','double', 'bool','long']
    try:
    expectTyp.index(typ)
    isType = True
    except ValueError:
    expectTyp.append(typ)
    isType = False

    if isType:
    return [name, typeMap[typ], 'optional', 'normal type']
    else:
    readClass(level + 1, typ)
    return [name, typ, 'optional', 'sub class']

    readClass(0, targetClass)