├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── image-1.png ├── image.png ├── img.png └── plugin.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## il2cpp_bn 3 | 4 | 将il2cppdumper的符号信息导入binaryninja中,就像使用其自带的脚本导入ida中一样 5 | 6 | 实现了 7 | 8 | 更改函数名称及声明 并将声明自动注释 9 | ![Alt text](image.png) 10 | 11 | 导入string并注释 12 | 13 | ![Alt text](image-1.png) 14 | 15 | ## 使用方法 16 | 17 | 建议open with option打开 18 | 19 | 选择 ![img.png](img.png) 20 | 21 | 可以避免过长的反编译所有函数的等待时间 22 | 23 | 24 | 先使用il2cpp dump获取script.json和il2cpp.h 25 | 26 | 在il2cpp.h的头部增加 27 | 28 | (64位) 29 | ``` 30 | #define intptr_t int64_t 31 | #define uintptr_t uint64_t 32 | ``` 33 | 34 | 然后使用bn的内置功能 ctrl+p 搜索 'Import Header File' 35 | 36 | 导入il2cpp.h 37 | 38 | 然后使用插件,选择对应的功能 39 | 40 | 根据提示选中script.json 等待即可 41 | 42 | ## 不足 43 | 44 | 没有找到自动导入头文件的api函数 只能手动导入 45 | 46 | ## 感谢 47 | 48 | 感谢 @mFallW1nd 提供的优化思路,通过手动parser,获取type的方式避免了使用bv.parse_types_from_string的性能问题 49 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from binaryninja import * 2 | 3 | bv: BinaryView 4 | 5 | 6 | class MyType(): 7 | def __init__(self, bv: BinaryView, signature, isFunc=True): 8 | self.bv = bv 9 | self.initialize_typing_dict() 10 | if isFunc: 11 | self.preprocess_signature(signature) 12 | self.parse_signature_tokens() 13 | self.compile_funcType() 14 | 15 | def initialize_typing_dict(self): 16 | self.dict1 = {"void": Type.void(), 17 | "int8_t": Type.int(1), "int": Type.int(4), 18 | "int16_t": Type.int(2), "int32_t": Type.int(4), "int64_t": Type.int(8), 19 | "uint8_t": Type.int(1, False), "uint16_t": Type.int(2, False), 20 | "uint32_t": Type.int(4, False), "uint64_t": Type.int(8, False), 21 | "float": Type.float(4), "double": Type.float(8), 22 | "long": Type.int(8), "bool": Type.bool(), "char": Type.char()} 23 | if self.bv.arch.address_size in (4, 8): 24 | self.dict1["intptr_t"] = Type.int(self.bv.arch.address_size) 25 | self.dict1["uintptr_t"] = Type.int(self.bv.arch.address_size, False) 26 | 27 | def preprocess_signature(self, signature): 28 | signature = signature.replace("intptr_t method,", "").replace("const ", "") 29 | self.tokens = signature.split() 30 | self.signature = signature 31 | 32 | def parse_signature_tokens(self): 33 | self.retType = self.string2type(self.tokens[0]) 34 | self.name = self.tokens[1] 35 | self.args = [arg.replace("(", "").replace(");", "") for arg in self.tokens[2:]] 36 | self.args = " ".join(self.args) 37 | self.args = [arg.split() if len(arg.split()) > 1 else arg.split() + ['tem'] for arg in self.args.split(",")] 38 | self.args = [[arg[-1], " ".join(arg[:-1])] for arg in self.args] 39 | self.args = [(arg[0], self.string2type(arg[1])) for arg in self.args] 40 | 41 | def compile_funcType(self): 42 | self.funcType = Type.function(self.retType, self.args) 43 | 44 | def string2type(self, strIn): 45 | ptrNum = strIn.count("*") 46 | strIn = strIn.replace("*", "") 47 | strIn = strIn.strip() 48 | if " " in strIn: 49 | print("bug! space in strIn", self.signature) 50 | return self.dict1["uint64_t"] 51 | isPtr = "*" in strIn 52 | if strIn in self.dict1: 53 | ret = self.dict1[strIn] 54 | else: 55 | try: 56 | ret = Type.named_type_from_registered_type(self.bv, strIn) 57 | except: 58 | self.print_error(strIn) 59 | ret = self.dict1["uint64_t"] 60 | for i in range(ptrNum): 61 | ret = Type.pointer(self.bv.arch, ret) 62 | return ret 63 | 64 | def print_error(self, strIn): 65 | print("error type: ", strIn) 66 | print(self.signature) 67 | print(self.retType) 68 | print(self.name) 69 | print(self.args) 70 | 71 | 72 | def get_addr(bv=None, addr=0): 73 | return bv.start + addr 74 | 75 | 76 | def get_pointer(bv: BinaryView): 77 | return f"uint64_t" 78 | bv.arch.address_size 79 | 80 | 81 | def set_name(bv, addr, name, isFunc=True): 82 | # 设置变量的名称 83 | if not isFunc: 84 | funcs = bv.get_functions_containing(addr) 85 | if funcs is not None: 86 | [bv.remove_user_function(x) for x in funcs] 87 | if bv.get_data_var_at(addr): 88 | bv.get_data_var_at(addr).name = name 89 | else: 90 | # 设置为char* 91 | bv.define_user_data_var(addr, Type.pointer(bv.arch, Type.char()), name) 92 | bv.set_comment_at(addr, name) 93 | else: 94 | # 设置函数的名称 95 | try: 96 | bv.get_functions_containing(addr)[0].name = name 97 | except: 98 | if addr != 0: 99 | print("set error", hex(addr), name) 100 | 101 | 102 | def make_function(bv, start, end): 103 | # print(start) 104 | pos = start - 1 105 | funcset = set() 106 | 107 | while pos < end: 108 | try: 109 | pos = bv.get_next_function_start_after(pos) 110 | funcset.add(bv.get_functions_containing(pos)[0]) 111 | except: 112 | pos += 1 113 | try: 114 | func = bv.get_functions_containing(pos)[0] 115 | if not func.name.startswith("sub_"): 116 | return 117 | funcset.add(func) 118 | except: 119 | pass 120 | if len(funcset) != 1: 121 | for x in funcset: 122 | bv.remove_user_function(x) 123 | bv.create_user_function(start) 124 | 125 | 126 | def apply_func_type(bv, addr, funcType: str): 127 | function_list = bv.get_functions_containing(addr) 128 | if not function_list: 129 | print("no function", hex(addr), funcType) 130 | return 131 | func = function_list[0] 132 | try: 133 | func.type = MyType(bv, funcType).funcType 134 | except Exception as e: 135 | funcType = funcType.replace("intptr_t method,", "") 136 | parserTmp = bv.parse_type_string(funcType)[0] 137 | func.type = parserTmp 138 | print("error type,use auto parser", funcType) 139 | print(e) 140 | 141 | 142 | def apply_data_type(bv, addr, dataType: str): 143 | try: 144 | bv.get_data_var_at(addr).type = MyType(bv, dataType, False).string2type(dataType) 145 | except: 146 | print(f"error::{hex(addr)} {dataType}") 147 | 148 | 149 | def make_ScriptString(bv: BinaryView, data=None): 150 | if data is None: 151 | import json 152 | path = get_open_filename_input("script.json") 153 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 154 | processFields = [ 155 | "ScriptMethod", 156 | "ScriptString", 157 | "ScriptMetadata", 158 | "ScriptMetadataMethod", 159 | "Addresses", 160 | ] 161 | if "ScriptString" in data and "ScriptString" in processFields: 162 | index = 1 163 | scriptStrings = data["ScriptString"] 164 | for scriptString in scriptStrings: 165 | addr = get_addr(bv, addr=scriptString["Address"]) 166 | value = scriptString["Value"] 167 | name = "StringLiteral_" + str(index) 168 | set_name(bv, addr, name, False) 169 | bv.set_comment_at(addr, value) 170 | index += 1 171 | print("ScriptString finished!") 172 | 173 | 174 | def make_ScriptMetadataMethod(bv: BinaryView, data=None): 175 | # 实际上是储存了method的地址的变量 176 | if data is None: 177 | import json 178 | path = get_open_filename_input("script.json") 179 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 180 | processFields = [ 181 | "ScriptMethod", 182 | "ScriptString", 183 | "ScriptMetadata", 184 | "ScriptMetadataMethod", 185 | "Addresses", 186 | ] 187 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 188 | scriptMetadataMethods: object = data["ScriptMetadataMethod"] 189 | for scriptMetadataMethod in scriptMetadataMethods: 190 | addr = get_addr(bv, addr=scriptMetadataMethod["Address"]) # 是变量的addr 191 | name = scriptMetadataMethod["Name"] 192 | methodAddr = get_addr(bv, addr=scriptMetadataMethod["MethodAddress"]) 193 | set_name(bv, methodAddr, name, True) 194 | set_name(bv, addr, name, False) 195 | bv.set_comment_at(addr, f'{name} {hex(methodAddr)}') 196 | print("ScriptMetadataMethod finished!") 197 | 198 | 199 | def make_ScriptMetadata_name(bv: BinaryView, data=None): 200 | if data is None: 201 | import json 202 | path = get_open_filename_input("script.json") 203 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 204 | processFields = [ 205 | "ScriptMethod", 206 | "ScriptString", 207 | "ScriptMetadata", 208 | "ScriptMetadataMethod", 209 | "Addresses", 210 | ] 211 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 212 | scriptMetadatas = data["ScriptMetadata"] 213 | for scriptMetadata in scriptMetadatas: 214 | addr = get_addr(bv, addr=scriptMetadata["Address"]) 215 | name = scriptMetadata["Name"] 216 | set_name(bv, addr, name, False) 217 | if scriptMetadata["Signature"] is not None: 218 | signature = scriptMetadata["Signature"] 219 | bv.set_comment_at(addr, str(signature)) 220 | print("ScriptMetadata-name finished!") 221 | 222 | 223 | def make_ScriptMethod_name(bv: BinaryView, data=None): 224 | if data is None: 225 | import json 226 | path = get_open_filename_input("script.json") 227 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 228 | processFields = [ 229 | "ScriptMethod", 230 | "ScriptString", 231 | "ScriptMetadata", 232 | "ScriptMetadataMethod", 233 | "Addresses", 234 | ] 235 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 236 | scriptMethods = data["ScriptMethod"] 237 | for scriptMethod in scriptMethods: 238 | addr = get_addr(bv, addr=scriptMethod["Address"]) 239 | name = scriptMethod["Name"] 240 | set_name(bv, addr, name, True) 241 | if scriptMethod["Signature"] is not None: 242 | signature = scriptMethod["Signature"] 243 | bv.set_comment_at(addr, str(signature)) 244 | print("ScriptMethod-name finished!") 245 | 246 | 247 | def make_ScriptMethod_type(bv: BinaryView, data=None): 248 | if data is None: 249 | import json 250 | path = get_open_filename_input("script.json") 251 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 252 | processFields = [ 253 | "ScriptMethod", 254 | "ScriptString", 255 | "ScriptMetadata", 256 | "ScriptMetadataMethod", 257 | "Addresses", 258 | ] 259 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 260 | scriptMethods = data["ScriptMethod"] 261 | for scriptMethod in scriptMethods: 262 | addr = get_addr(bv, addr=scriptMethod["Address"]) 263 | if scriptMethod["Signature"] is not None: 264 | signature = scriptMethod["Signature"] 265 | apply_func_type(bv, addr, signature) 266 | print("ScriptMethod-type finished!") 267 | 268 | 269 | def make_ScriptMetadata_type(bv: BinaryView, data=None): 270 | if data is None: 271 | import json 272 | path = get_open_filename_input("script.json") 273 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 274 | processFields = [ 275 | "ScriptMethod", 276 | "ScriptString", 277 | "ScriptMetadata", 278 | "ScriptMetadataMethod", 279 | "Addresses", 280 | ] 281 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 282 | scriptMetadatas = data["ScriptMetadata"] 283 | for scriptMetadata in scriptMetadatas: 284 | addr = get_addr(bv, addr=scriptMetadata["Address"]) 285 | if scriptMetadata["Signature"] is not None: 286 | signature = scriptMetadata["Signature"] 287 | apply_data_type(bv, addr, signature) 288 | print("ScriptMetadata-type finished!") 289 | 290 | 291 | def make_func(bv: BinaryView, data=None): 292 | if data is None: 293 | import json 294 | path = get_open_filename_input("script.json") 295 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 296 | processFields = [ 297 | "ScriptMethod", 298 | "ScriptString", 299 | "ScriptMetadata", 300 | "ScriptMetadataMethod", 301 | "Addresses", 302 | ] 303 | if "Addresses" in data and "Addresses" in processFields: 304 | addresses = data["Addresses"] 305 | for index in range(len(addresses) - 1): 306 | start = get_addr(bv, addr=addresses[index]) 307 | end = get_addr(bv, addr=addresses[index + 1]) 308 | make_function(bv, start, end) 309 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 310 | scriptMethods = data["ScriptMethod"] 311 | for scriptMethod in scriptMethods: 312 | addr = get_addr(bv, addr=scriptMethod["Address"]) 313 | make_function(bv, addr, addr + 0x1) 314 | # if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 315 | # scriptMetadataMethods: object = data["ScriptMetadataMethod"] 316 | # for scriptMetadataMethod in scriptMetadataMethods: 317 | # addr = get_addr(bv, addr=scriptMetadataMethod["Address"]) 318 | # methodAddr = get_addr(bv, addr=scriptMetadataMethod["MethodAddress"]) 319 | # if bv.get_data_var_at(methodAddr) is None: 320 | # make_function(bv, methodAddr, methodAddr + 0x1) 321 | # if bv.get_data_var_at(addr) is None: 322 | # make_function(bv, addr, addr + 0x1) 323 | print("make function finished!") 324 | 325 | 326 | def import_info(bv): 327 | import json 328 | path = get_open_filename_input("script.json") 329 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 330 | make_ScriptString(bv, data) 331 | make_ScriptMetadataMethod(bv, data) 332 | make_ScriptMetadata_name(bv, data) 333 | make_ScriptMethod_name(bv, data) 334 | make_ScriptMethod_type(bv, data) 335 | make_ScriptMetadata_type(bv, data) 336 | print("all recover finished!") 337 | 338 | 339 | PluginCommand.register("il2cpp_bn\\1.make_func", "", make_func) 340 | # PluginCommand.register("il2cpp_bn\\2.ScriptString", "", make_ScriptString) 341 | # PluginCommand.register("il2cpp_bn\\3.ScriptMetadataMethod", "", make_ScriptMetadataMethod) 342 | # PluginCommand.register("il2cpp_bn\\4.ScriptMetadata_name", "", make_ScriptMetadata_name) 343 | # PluginCommand.register("il2cpp_bn\\5.ScriptMethod_name", "", make_ScriptMethod_name) 344 | # PluginCommand.register("il2cpp_bn\\6.ScriptMethod_type", "", make_ScriptMethod_type) 345 | # PluginCommand.register("il2cpp_bn\\7.ScriptMetadata_type", "", make_ScriptMetadata_type) 346 | PluginCommand.register("il2cpp_bn\\2.recover Info", "", import_info) 347 | -------------------------------------------------------------------------------- /image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VNRev/il2cpp_bn/91a65b80cb61530164bd61830cbcd74cd2845105/image-1.png -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VNRev/il2cpp_bn/91a65b80cb61530164bd61830cbcd74cd2845105/image.png -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VNRev/il2cpp_bn/91a65b80cb61530164bd61830cbcd74cd2845105/img.png -------------------------------------------------------------------------------- /plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginmetadataversion": 2, 3 | "name": "il2cpp_bn", 4 | "type": [ 5 | "helper" 6 | ], 7 | "api": [ 8 | "python3" 9 | ], 10 | "description": "il2cpp info 2 bn", 11 | "longdescription": "", 12 | "license": { 13 | "name": "MIT", 14 | "text": "Copyright (c) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." 15 | }, 16 | "platforms": [ 17 | "Darwin", 18 | "Linux", 19 | "Windows" 20 | ], 21 | "dependencies": { 22 | }, 23 | "version": "1.0.2", 24 | "author": "ltlly", 25 | "minimumbinaryninjaversion": 3164 26 | } --------------------------------------------------------------------------------