├── decrypt ├── dynamicDcrypt │ ├── readme │ ├── resource │ │ ├── icon.png │ │ ├── Il2CppDumper │ │ │ ├── Mono.Cecil.dll │ │ │ ├── Il2CppDumper.exe │ │ │ ├── Il2CppDumper.pdb │ │ │ ├── Mono.Cecil.Mdb.dll │ │ │ ├── Mono.Cecil.Pdb.dll │ │ │ ├── Mono.Cecil.Rocks.dll │ │ │ ├── Newtonsoft.Json.dll │ │ │ ├── Il2CppDumper.exe.config │ │ │ ├── config.json │ │ │ ├── ida_py3.py │ │ │ ├── ida.py │ │ │ ├── ghidra.py │ │ │ ├── ida_with_struct_py3.py │ │ │ ├── ida_with_struct.py │ │ │ └── ghidra_with_struct.py │ │ └── inject.js │ └── Decrypt.py └── jsc2js │ └── jsctojs.py └── readme.md /decrypt/dynamicDcrypt/readme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/readme -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/icon.png -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.dll -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Il2CppDumper.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Il2CppDumper.exe -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Il2CppDumper.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Il2CppDumper.pdb -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.Mdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.Mdb.dll -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoooHaaa/cocos-unity-decrypt/HEAD/decrypt/dynamicDcrypt/resource/Il2CppDumper/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/Il2CppDumper.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "DumpMethod": true, 3 | "DumpField": true, 4 | "DumpProperty": true, 5 | "DumpAttribute": true, 6 | "DumpFieldOffset": true, 7 | "DumpMethodOffset": true, 8 | "DumpTypeDefIndex": true, 9 | "GenerateDummyDll": true, 10 | "GenerateStruct": true, 11 | "DummyDllAddToken": true, 12 | "RequireAnyKey": true, 13 | "ForceIl2CppVersion": false, 14 | "ForceVersion": 16 15 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 本项目有两个工具 2 | 3 | 1 cocos2d中 jsc 静态解密为 js 4 | ![企业微信截图_16321920754283](https://user-images.githubusercontent.com/48267341/134103851-0a6cf023-1c36-4d4d-b67f-4fd1f6625f88.png) 5 | 6 | 7 | 2 动态解密,需安装frida 8 | 支持Cocos框架中 libcocos2djs.so 解密js脚本 9 | 支持Cocos框架中 libcocos2dlua.so 解密lua脚本 10 | 支持Unity3d框架中 libil2cpp.so 解密dll、cs文件 11 | 12 | 主界面: 13 | ![企业微信截图_16321921051135](https://user-images.githubusercontent.com/48267341/134103941-2be0727a-af45-49ef-af51-75b4b1d3ff59.png) 14 | 15 | 功能界面 16 | 17 | ![企业微信截图_16321921243568](https://user-images.githubusercontent.com/48267341/134103954-4a9642cf-b257-46a6-a6a1-37cf398ba52d.png) 18 | 19 | 20 | 21 | 22 | ![企业微信截图_16321921391501](https://user-images.githubusercontent.com/48267341/134103959-b66e347d-6723-4325-b038-486ece673174.png) 23 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/ida_py3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | processFields = [ 5 | "ScriptMethod", 6 | "ScriptString", 7 | "ScriptMetadata", 8 | "ScriptMetadataMethod", 9 | "Addresses", 10 | ] 11 | 12 | imageBase = idaapi.get_imagebase() 13 | 14 | def get_addr(addr): 15 | return imageBase + addr 16 | 17 | def set_name(addr, name): 18 | ret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK) 19 | if ret == 0: 20 | new_name = name + '_' + str(addr) 21 | ret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK) 22 | 23 | def make_function(start, end): 24 | next_func = idc.get_next_func(start) 25 | if next_func < end: 26 | end = next_func 27 | if idc.get_func_attr(start, FUNCATTR_START) == start: 28 | ida_funcs.del_func(start) 29 | ida_funcs.add_func(start, end) 30 | 31 | path = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper') 32 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 33 | 34 | if "Addresses" in data and "Addresses" in processFields: 35 | addresses = data["Addresses"] 36 | for index in range(len(addresses) - 1): 37 | start = get_addr(addresses[index]) 38 | end = get_addr(addresses[index + 1]) 39 | make_function(start, end) 40 | 41 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 42 | scriptMethods = data["ScriptMethod"] 43 | for scriptMethod in scriptMethods: 44 | addr = get_addr(scriptMethod["Address"]) 45 | name = scriptMethod["Name"] 46 | set_name(addr, name) 47 | 48 | if "ScriptString" in data and "ScriptString" in processFields: 49 | index = 1 50 | scriptStrings = data["ScriptString"] 51 | for scriptString in scriptStrings: 52 | addr = get_addr(scriptString["Address"]) 53 | value = scriptString["Value"] 54 | name = "StringLiteral_" + str(index) 55 | idc.set_name(addr, name, SN_NOWARN) 56 | idc.set_cmt(addr, value, 1) 57 | index += 1 58 | 59 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 60 | scriptMetadatas = data["ScriptMetadata"] 61 | for scriptMetadata in scriptMetadatas: 62 | addr = get_addr(scriptMetadata["Address"]) 63 | name = scriptMetadata["Name"] 64 | set_name(addr, name) 65 | idc.set_cmt(addr, name, 1) 66 | 67 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 68 | scriptMetadataMethods = data["ScriptMetadataMethod"] 69 | for scriptMetadataMethod in scriptMetadataMethods: 70 | addr = get_addr(scriptMetadataMethod["Address"]) 71 | name = scriptMetadataMethod["Name"] 72 | methodAddr = get_addr(scriptMetadataMethod["MethodAddress"]) 73 | set_name(addr, name) 74 | idc.set_cmt(addr, name, 1) 75 | idc.set_cmt(addr, '{0:X}'.format(methodAddr), 0) 76 | 77 | print('Script finished!') 78 | 79 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/ida.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | processFields = [ 5 | "ScriptMethod", 6 | "ScriptString", 7 | "ScriptMetadata", 8 | "ScriptMetadataMethod", 9 | "Addresses", 10 | ] 11 | 12 | imageBase = idaapi.get_imagebase() 13 | 14 | def get_addr(addr): 15 | return imageBase + addr 16 | 17 | def set_name(addr, name): 18 | ret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK) 19 | if ret == 0: 20 | new_name = name + '_' + str(addr) 21 | ret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK) 22 | 23 | def make_function(start, end): 24 | next_func = idc.get_next_func(start) 25 | if next_func < end: 26 | end = next_func 27 | if idc.get_func_attr(start, FUNCATTR_START) == start: 28 | ida_funcs.del_func(start) 29 | ida_funcs.add_func(start, end) 30 | 31 | path = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper') 32 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 33 | 34 | if "Addresses" in data and "Addresses" in processFields: 35 | addresses = data["Addresses"] 36 | for index in range(len(addresses) - 1): 37 | start = get_addr(addresses[index]) 38 | end = get_addr(addresses[index + 1]) 39 | make_function(start, end) 40 | 41 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 42 | scriptMethods = data["ScriptMethod"] 43 | for scriptMethod in scriptMethods: 44 | addr = get_addr(scriptMethod["Address"]) 45 | name = scriptMethod["Name"].encode("utf-8") 46 | set_name(addr, name) 47 | 48 | if "ScriptString" in data and "ScriptString" in processFields: 49 | index = 1 50 | scriptStrings = data["ScriptString"] 51 | for scriptString in scriptStrings: 52 | addr = get_addr(scriptString["Address"]) 53 | value = scriptString["Value"].encode("utf-8") 54 | name = "StringLiteral_" + str(index) 55 | idc.set_name(addr, name, SN_NOWARN) 56 | idc.set_cmt(addr, value, 1) 57 | index += 1 58 | 59 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 60 | scriptMetadatas = data["ScriptMetadata"] 61 | for scriptMetadata in scriptMetadatas: 62 | addr = get_addr(scriptMetadata["Address"]) 63 | name = scriptMetadata["Name"].encode("utf-8") 64 | set_name(addr, name) 65 | idc.set_cmt(addr, name, 1) 66 | 67 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 68 | scriptMetadataMethods = data["ScriptMetadataMethod"] 69 | for scriptMetadataMethod in scriptMetadataMethods: 70 | addr = get_addr(scriptMetadataMethod["Address"]) 71 | name = scriptMetadataMethod["Name"].encode("utf-8") 72 | methodAddr = get_addr(scriptMetadataMethod["MethodAddress"]) 73 | set_name(addr, name) 74 | idc.set_cmt(addr, name, 1) 75 | idc.set_cmt(addr, '{0:X}'.format(methodAddr), 0) 76 | 77 | print 'Script finished!' 78 | 79 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/ghidra.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | processFields = [ 5 | "ScriptMethod", 6 | "ScriptString", 7 | "ScriptMetadata", 8 | "ScriptMetadataMethod", 9 | "Addresses", 10 | ] 11 | 12 | functionManager = currentProgram.getFunctionManager() 13 | baseAddress = currentProgram.getImageBase() 14 | USER_DEFINED = ghidra.program.model.symbol.SourceType.USER_DEFINED 15 | 16 | def get_addr(addr): 17 | return baseAddress.add(addr) 18 | 19 | def set_name(addr, name): 20 | name = name.replace(' ', '-') 21 | createLabel(addr, name, True, USER_DEFINED) 22 | 23 | def make_function(start): 24 | func = getFunctionAt(start) 25 | if func is None: 26 | createFunction(start, None) 27 | 28 | f = askFile("script.json from Il2cppdumper", "Open") 29 | data = json.loads(open(f.absolutePath, 'rb').read().decode('utf-8')) 30 | 31 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 32 | scriptMethods = data["ScriptMethod"] 33 | monitor.initialize(len(scriptMethods)) 34 | monitor.setMessage("Methods") 35 | for scriptMethod in scriptMethods: 36 | addr = get_addr(scriptMethod["Address"]) 37 | name = scriptMethod["Name"].encode("utf-8") 38 | set_name(addr, name) 39 | monitor.incrementProgress(1) 40 | 41 | if "ScriptString" in data and "ScriptString" in processFields: 42 | index = 1 43 | scriptStrings = data["ScriptString"] 44 | monitor.initialize(len(scriptStrings)) 45 | monitor.setMessage("Strings") 46 | for scriptString in scriptStrings: 47 | addr = get_addr(scriptString["Address"]) 48 | value = scriptString["Value"].encode("utf-8") 49 | name = "StringLiteral_" + str(index) 50 | createLabel(addr, name, True, USER_DEFINED) 51 | setEOLComment(addr, value) 52 | index += 1 53 | monitor.incrementProgress(1) 54 | 55 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 56 | scriptMetadatas = data["ScriptMetadata"] 57 | monitor.initialize(len(scriptMetadatas)) 58 | monitor.setMessage("Metadata") 59 | for scriptMetadata in scriptMetadatas: 60 | addr = get_addr(scriptMetadata["Address"]) 61 | name = scriptMetadata["Name"].encode("utf-8") 62 | set_name(addr, name) 63 | setEOLComment(addr, name) 64 | monitor.incrementProgress(1) 65 | 66 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 67 | scriptMetadataMethods = data["ScriptMetadataMethod"] 68 | monitor.initialize(len(scriptMetadataMethods)) 69 | monitor.setMessage("Metadata Methods") 70 | for scriptMetadataMethod in scriptMetadataMethods: 71 | addr = get_addr(scriptMetadataMethod["Address"]) 72 | name = scriptMetadataMethod["Name"].encode("utf-8") 73 | methodAddr = get_addr(scriptMetadataMethod["MethodAddress"]) 74 | set_name(addr, name) 75 | setEOLComment(addr, name) 76 | monitor.incrementProgress(1) 77 | 78 | if "Addresses" in data and "Addresses" in processFields: 79 | addresses = data["Addresses"] 80 | monitor.initialize(len(addresses)) 81 | monitor.setMessage("Addresses") 82 | for index in range(len(addresses) - 1): 83 | start = get_addr(addresses[index]) 84 | make_function(start) 85 | monitor.incrementProgress(1) 86 | 87 | print 'Script finished!' 88 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/ida_with_struct_py3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | processFields = [ 5 | "ScriptMethod", 6 | "ScriptString", 7 | "ScriptMetadata", 8 | "ScriptMetadataMethod", 9 | "Addresses", 10 | ] 11 | 12 | imageBase = idaapi.get_imagebase() 13 | 14 | def get_addr(addr): 15 | return imageBase + addr 16 | 17 | def set_name(addr, name): 18 | ret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK) 19 | if ret == 0: 20 | new_name = name + '_' + str(addr) 21 | ret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK) 22 | 23 | def make_function(start, end): 24 | next_func = idc.get_next_func(start) 25 | if next_func < end: 26 | end = next_func 27 | if idc.get_func_attr(start, FUNCATTR_START) == start: 28 | ida_funcs.del_func(start) 29 | ida_funcs.add_func(start, end) 30 | 31 | path = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper') 32 | hpath = idaapi.ask_file(False, '*.h', 'il2cpp.h from Il2cppdumper') 33 | parse_decls(open(hpath, 'r').read(), 0) 34 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 35 | 36 | if "Addresses" in data and "Addresses" in processFields: 37 | addresses = data["Addresses"] 38 | for index in range(len(addresses) - 1): 39 | start = get_addr(addresses[index]) 40 | end = get_addr(addresses[index + 1]) 41 | make_function(start, end) 42 | 43 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 44 | scriptMethods = data["ScriptMethod"] 45 | for scriptMethod in scriptMethods: 46 | addr = get_addr(scriptMethod["Address"]) 47 | name = scriptMethod["Name"] 48 | set_name(addr, name) 49 | signature = scriptMethod["Signature"] 50 | if apply_type(addr, parse_decl(signature, 0), 1) == False: 51 | print("apply_type failed:", hex(addr), signature) 52 | 53 | if "ScriptString" in data and "ScriptString" in processFields: 54 | index = 1 55 | scriptStrings = data["ScriptString"] 56 | for scriptString in scriptStrings: 57 | addr = get_addr(scriptString["Address"]) 58 | value = scriptString["Value"] 59 | name = "StringLiteral_" + str(index) 60 | idc.set_name(addr, name, SN_NOWARN) 61 | idc.set_cmt(addr, value, 1) 62 | index += 1 63 | 64 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 65 | scriptMetadatas = data["ScriptMetadata"] 66 | for scriptMetadata in scriptMetadatas: 67 | addr = get_addr(scriptMetadata["Address"]) 68 | name = scriptMetadata["Name"] 69 | set_name(addr, name) 70 | idc.set_cmt(addr, name, 1) 71 | if scriptMetadata["Signature"] is not None: 72 | signature = scriptMetadata["Signature"] 73 | if apply_type(addr, parse_decl(signature, 0), 1) == False: 74 | print("apply_type failed:", hex(addr), signature) 75 | 76 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 77 | scriptMetadataMethods = data["ScriptMetadataMethod"] 78 | for scriptMetadataMethod in scriptMetadataMethods: 79 | addr = get_addr(scriptMetadataMethod["Address"]) 80 | name = scriptMetadataMethod["Name"] 81 | methodAddr = get_addr(scriptMetadataMethod["MethodAddress"]) 82 | set_name(addr, name) 83 | idc.set_cmt(addr, name, 1) 84 | idc.set_cmt(addr, '{0:X}'.format(methodAddr), 0) 85 | 86 | print('Script finished!') 87 | 88 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/ida_with_struct.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | processFields = [ 5 | "ScriptMethod", 6 | "ScriptString", 7 | "ScriptMetadata", 8 | "ScriptMetadataMethod", 9 | "Addresses", 10 | ] 11 | 12 | imageBase = idaapi.get_imagebase() 13 | 14 | def get_addr(addr): 15 | return imageBase + addr 16 | 17 | def set_name(addr, name): 18 | ret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK) 19 | if ret == 0: 20 | new_name = name + '_' + str(addr) 21 | ret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK) 22 | 23 | def make_function(start, end): 24 | next_func = idc.get_next_func(start) 25 | if next_func < end: 26 | end = next_func 27 | if idc.get_func_attr(start, FUNCATTR_START) == start: 28 | ida_funcs.del_func(start) 29 | ida_funcs.add_func(start, end) 30 | 31 | path = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper') 32 | hpath = idaapi.ask_file(False, '*.h', 'il2cpp.h from Il2cppdumper') 33 | parse_decls(open(hpath, 'rb').read(), 0) 34 | data = json.loads(open(path, 'rb').read().decode('utf-8')) 35 | 36 | if "Addresses" in data and "Addresses" in processFields: 37 | addresses = data["Addresses"] 38 | for index in range(len(addresses) - 1): 39 | start = get_addr(addresses[index]) 40 | end = get_addr(addresses[index + 1]) 41 | make_function(start, end) 42 | 43 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 44 | scriptMethods = data["ScriptMethod"] 45 | for scriptMethod in scriptMethods: 46 | addr = get_addr(scriptMethod["Address"]) 47 | name = scriptMethod["Name"].encode("utf-8") 48 | set_name(addr, name) 49 | signature = scriptMethod["Signature"].encode("utf-8") 50 | if apply_type(addr, parse_decl(signature, 0), 1) == False: 51 | print "apply_type failed:", hex(addr), signature 52 | 53 | if "ScriptString" in data and "ScriptString" in processFields: 54 | index = 1 55 | scriptStrings = data["ScriptString"] 56 | for scriptString in scriptStrings: 57 | addr = get_addr(scriptString["Address"]) 58 | value = scriptString["Value"].encode("utf-8") 59 | name = "StringLiteral_" + str(index) 60 | idc.set_name(addr, name, SN_NOWARN) 61 | idc.set_cmt(addr, value, 1) 62 | index += 1 63 | 64 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 65 | scriptMetadatas = data["ScriptMetadata"] 66 | for scriptMetadata in scriptMetadatas: 67 | addr = get_addr(scriptMetadata["Address"]) 68 | name = scriptMetadata["Name"].encode("utf-8") 69 | set_name(addr, name) 70 | idc.set_cmt(addr, name, 1) 71 | if scriptMetadata["Signature"] is not None: 72 | signature = scriptMetadata["Signature"].encode("utf-8") 73 | if apply_type(addr, parse_decl(signature, 0), 1) == False: 74 | print "apply_type failed:", hex(addr), signature 75 | 76 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 77 | scriptMetadataMethods = data["ScriptMetadataMethod"] 78 | for scriptMetadataMethod in scriptMetadataMethods: 79 | addr = get_addr(scriptMetadataMethod["Address"]) 80 | name = scriptMetadataMethod["Name"].encode("utf-8") 81 | methodAddr = get_addr(scriptMetadataMethod["MethodAddress"]) 82 | set_name(addr, name) 83 | idc.set_cmt(addr, name, 1) 84 | idc.set_cmt(addr, '{0:X}'.format(methodAddr), 0) 85 | 86 | print 'Script finished!' 87 | 88 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/inject.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | var filenum = 1; 5 | 6 | function file_createdir(pkgname) { 7 | var mkdirPtr = Module.getExportByName('libc.so', 'mkdir'); 8 | var mkdir = new NativeFunction(mkdirPtr, 'int', ['pointer', 'int']); 9 | mkdir(Memory.allocUtf8String("/data/data/" + pkgname + "/dump"), 0x0FFF) 10 | console.log("[+] 初始化dump目录:/data/data/" + pkgname + "/dump"); 11 | } 12 | 13 | function hook_cocos_js_inflateMemory(funcname, pkgname){ 14 | console.log("[+] hook ", funcname); 15 | var cocosbase = Module.findExportByName("libcocos2djs.so", funcname); 16 | if (cocosbase){ 17 | Interceptor.attach(cocosbase, { 18 | onEnter: function (args) { 19 | this.buff = args[2]; 20 | if (Process.arch == "arm64"){ 21 | this.filename = ptr(args[2]).add(0x3d).readCString() + ".js" 22 | }else{ 23 | this.filename = filenum + '.js'; 24 | filenum = filenum + 1; 25 | } 26 | }, 27 | onLeave:function (retval) { 28 | dump_file_write(this.filename, ptr(Memory.readPointer(this.buff)).readCString(), pkgname); 29 | } 30 | }); 31 | } 32 | } 33 | 34 | function hook_so_js(pkgname) { 35 | var exports = Process.findModuleByName("libcocos2djs.so").enumerateExports(); 36 | for (var m = 0; m < exports.length; m++) { 37 | if (exports[m].name.indexOf("inflateMemory") != -1 && exports[m].name.indexOf("inflateMemoryWithHint") == -1) { 38 | hook_cocos_js_inflateMemory(exports[m].name, pkgname) 39 | break; 40 | } 41 | } 42 | } 43 | 44 | function dump_file_write(file_name, file_str, pkgname) { 45 | var file_path = "/data/data/" + pkgname + "/dump/" + file_name; 46 | var fd = new File(file_path, "a"); 47 | if (fd && fd != null) { 48 | fd.write(file_str + "\r\n"); 49 | fd.flush(); 50 | fd.close(); 51 | console.log("[+] write " + file_path +" done:"); 52 | } 53 | } 54 | 55 | 56 | function hook_so_luac(pkgname){ 57 | var cocosbase = Module.findExportByName("libcocos2dlua.so", "luaL_loadbuffer"); 58 | if (cocosbase){ 59 | Interceptor.attach(cocosbase, { 60 | onEnter: function (args) { 61 | var filename = args[3].readCString(); 62 | if (filename.length < 260){ 63 | var paths = args[3].readCString().split("/"); 64 | filename = paths[0]; 65 | for (var i = 1; i < paths.length; i++){ 66 | filename = filename + "_" + paths[i]; 67 | } 68 | dump_file_write(filename, args[1].readCString(parseInt(args[2])), pkgname); 69 | } 70 | }, 71 | onLeave:function (retval) { 72 | } 73 | }); 74 | } 75 | } 76 | 77 | 78 | function hook_so_sluac(pkgname){ 79 | var cocosbase = Module.findExportByName("libslua.so", "luaL_loadbufferx"); 80 | if (cocosbase){ 81 | Interceptor.attach(cocosbase, { 82 | onEnter: function (args) { 83 | var names = args[3].readCString().split("/"); 84 | var luaname = names[names.length - 1].replace("@", ""); 85 | if (luaname.indexOf("lua") != -1){ 86 | dump_file_write(luaname, args[1].readCString(), pkgname); 87 | } 88 | // dump_file_write(filenum + '.lua', args[1].readCString(), pkgname) 89 | // filenum = filenum + 1; 90 | }, 91 | onLeave:function (retval) { 92 | } 93 | }); 94 | } 95 | } 96 | 97 | 98 | function hook_so(pkgname){ 99 | file_createdir(pkgname); 100 | var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext"); 101 | if(android_dlopen_ext!=null){ 102 | Interceptor.attach(android_dlopen_ext,{ 103 | onEnter: function(args){ 104 | var soName = args[0].readCString(); 105 | if(soName.indexOf("libcocos2djs.so") != -1){ 106 | this.jshook = true; 107 | } 108 | else if(soName.indexOf("libcocos2dlua.so") != -1){ 109 | this.luahook = true; 110 | } 111 | else if(soName.indexOf("libslua.so") != -1){ 112 | this.sluahook = true; 113 | } 114 | }, 115 | onLeave:function(retval){ 116 | if(this.jshook){ 117 | hook_so_js(pkgname); 118 | } 119 | else if(this.luahook){ 120 | hook_so_luac(pkgname); 121 | } 122 | else if(this.sluahook){ 123 | hook_so_sluac(pkgname); 124 | } 125 | } 126 | }); 127 | } 128 | } 129 | 130 | rpc.exports = { 131 | decryptcocos: function decryptcocos(pkgname) { 132 | hook_so(pkgname); 133 | } 134 | }; 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/resource/Il2CppDumper/ghidra_with_struct.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | from ghidra.app.util.cparser.C import CParserUtils 5 | from ghidra.app.cmd.function import ApplyFunctionSignatureCmd 6 | 7 | processFields = [ 8 | "ScriptMethod", 9 | "ScriptString", 10 | "ScriptMetadata", 11 | "ScriptMetadataMethod", 12 | "Addresses", 13 | ] 14 | 15 | functionManager = currentProgram.getFunctionManager() 16 | baseAddress = currentProgram.getImageBase() 17 | USER_DEFINED = ghidra.program.model.symbol.SourceType.USER_DEFINED 18 | 19 | def get_addr(addr): 20 | return baseAddress.add(addr) 21 | 22 | def set_name(addr, name): 23 | name = name.replace(' ', '-') 24 | createLabel(addr, name, True, USER_DEFINED) 25 | 26 | def set_type(addr, type): 27 | # Requires types (il2cpp.h) to be imported first 28 | newType = type.replace("*"," *").replace(" "," ").strip() 29 | dataTypes = getDataTypes(newType) 30 | addrType = None 31 | if len(dataTypes) == 0: 32 | if newType == newType[:-2] + " *": 33 | baseType = newType[:-2] 34 | dataTypes = getDataTypes(baseType) 35 | if len(dataTypes) == 1: 36 | dtm = currentProgram.getDataTypeManager() 37 | pointerType = dtm.getPointer(dataTypes[0]) 38 | addrType = dtm.addDataType(pointerType, None) 39 | elif len(dataTypes) > 1: 40 | print("Conflicting data types found for type " + type + "(parsed as '" + newType + "')") 41 | return 42 | else: 43 | addrType = dataTypes[0] 44 | if addrType is None: 45 | print("Could not identify type " + type + "(parsed as '" + newType + "')") 46 | else: 47 | createData(addr, addrType) 48 | 49 | def make_function(start): 50 | func = getFunctionAt(start) 51 | if func is None: 52 | createFunction(start, None) 53 | 54 | def set_sig(addr, name, sig): 55 | try: 56 | typeSig = CParserUtils.parseSignature(None, currentProgram, sig, False) 57 | except ghidra.app.util.cparser.C.ParseException: 58 | print("Warning: Unable to parse") 59 | print(sig) 60 | print("Attempting to modify...") 61 | # try to fix by renaming the parameters 62 | try: 63 | newSig = sig.replace(", ","ext, ").replace("\)","ext\)") 64 | typeSig = CParserUtils.parseSignature(None, currentProgram, newSig, False) 65 | except: 66 | print("Warning: also unable to parse") 67 | print(newSig) 68 | print("Skipping.") 69 | return 70 | if typeSig is not None: 71 | typeSig.setName(name) 72 | ApplyFunctionSignatureCmd(addr, typeSig, USER_DEFINED, False, True).applyTo(currentProgram) 73 | 74 | f = askFile("script.json from Il2cppdumper", "Open") 75 | data = json.loads(open(f.absolutePath, 'rb').read().decode('utf-8')) 76 | 77 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 78 | scriptMethods = data["ScriptMethod"] 79 | monitor.initialize(len(scriptMethods)) 80 | monitor.setMessage("Methods") 81 | for scriptMethod in scriptMethods: 82 | addr = get_addr(scriptMethod["Address"]) 83 | name = scriptMethod["Name"].encode("utf-8") 84 | set_name(addr, name) 85 | monitor.incrementProgress(1) 86 | 87 | if "ScriptString" in data and "ScriptString" in processFields: 88 | index = 1 89 | scriptStrings = data["ScriptString"] 90 | monitor.initialize(len(scriptStrings)) 91 | monitor.setMessage("Strings") 92 | for scriptString in scriptStrings: 93 | addr = get_addr(scriptString["Address"]) 94 | value = scriptString["Value"].encode("utf-8") 95 | name = "StringLiteral_" + str(index) 96 | createLabel(addr, name, True, USER_DEFINED) 97 | setEOLComment(addr, value) 98 | index += 1 99 | monitor.incrementProgress(1) 100 | 101 | if "ScriptMetadata" in data and "ScriptMetadata" in processFields: 102 | scriptMetadatas = data["ScriptMetadata"] 103 | monitor.initialize(len(scriptMetadatas)) 104 | monitor.setMessage("Metadata") 105 | for scriptMetadata in scriptMetadatas: 106 | addr = get_addr(scriptMetadata["Address"]) 107 | name = scriptMetadata["Name"].encode("utf-8") 108 | set_name(addr, name) 109 | setEOLComment(addr, name) 110 | monitor.incrementProgress(1) 111 | if scriptMetadata["Signature"]: 112 | set_type(addr, scriptMetadata["Signature"].encode("utf-8")) 113 | 114 | if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: 115 | scriptMetadataMethods = data["ScriptMetadataMethod"] 116 | monitor.initialize(len(scriptMetadataMethods)) 117 | monitor.setMessage("Metadata Methods") 118 | for scriptMetadataMethod in scriptMetadataMethods: 119 | addr = get_addr(scriptMetadataMethod["Address"]) 120 | name = scriptMetadataMethod["Name"].encode("utf-8") 121 | methodAddr = get_addr(scriptMetadataMethod["MethodAddress"]) 122 | set_name(addr, name) 123 | setEOLComment(addr, name) 124 | monitor.incrementProgress(1) 125 | 126 | if "Addresses" in data and "Addresses" in processFields: 127 | addresses = data["Addresses"] 128 | monitor.initialize(len(addresses)) 129 | monitor.setMessage("Addresses") 130 | for index in range(len(addresses) - 1): 131 | start = get_addr(addresses[index]) 132 | make_function(start) 133 | monitor.incrementProgress(1) 134 | 135 | if "ScriptMethod" in data and "ScriptMethod" in processFields: 136 | scriptMethods = data["ScriptMethod"] 137 | for scriptMethod in scriptMethods: 138 | addr = get_addr(scriptMethod["Address"]) 139 | sig = scriptMethod["Signature"][:-1].encode("utf-8") 140 | name = scriptMethod["Name"].encode("utf-8") 141 | set_sig(addr, name, sig) 142 | 143 | print 'Script finished!' 144 | -------------------------------------------------------------------------------- /decrypt/jsc2js/jsctojs.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # -*-coding:utf-8 -*- 3 | 4 | """ 5 | # File : AdDiscern.py 6 | # Time :2021/9/18 16:51 7 | # Author :Yooha 8 | """ 9 | 10 | from PyQt5 import QtCore, QtWidgets 11 | from PyQt5.QtWidgets import QFileDialog 12 | import PyQt5 13 | import sys 14 | from PyQt5.QtWidgets import QMessageBox 15 | import os 16 | import sys 17 | from gzip import GzipFile 18 | from io import BytesIO 19 | import struct 20 | 21 | 22 | class Ui_MainWindow(object): 23 | def setupUi(self, MainWindow): 24 | MainWindow.setObjectName("MainWindow") 25 | MainWindow.resize(639, 335) 26 | self.centralwidget = QtWidgets.QWidget(MainWindow) 27 | self.centralwidget.setObjectName("centralwidget") 28 | self.label = QtWidgets.QLabel(self.centralwidget) 29 | self.label.setGeometry(QtCore.QRect(110, 60, 131, 16)) 30 | self.label.setObjectName("label") 31 | self.label_2 = QtWidgets.QLabel(self.centralwidget) 32 | self.label_2.setGeometry(QtCore.QRect(110, 110, 131, 16)) 33 | self.label_2.setObjectName("label_2") 34 | self.label_3 = QtWidgets.QLabel(self.centralwidget) 35 | self.label_3.setGeometry(QtCore.QRect(110, 160, 131, 16)) 36 | self.label_3.setObjectName("label_3") 37 | self.edt_path_so = QtWidgets.QLineEdit(self.centralwidget) 38 | self.edt_path_so.setGeometry(QtCore.QRect(230, 60, 251, 21)) 39 | self.edt_path_so.setObjectName("edt_path_so") 40 | self.btn_path_so = QtWidgets.QPushButton(self.centralwidget) 41 | self.btn_path_so.setGeometry(QtCore.QRect(490, 60, 41, 21)) 42 | self.btn_path_so.setObjectName("btn_path_so") 43 | self.edt_path_jsc = QtWidgets.QLineEdit(self.centralwidget) 44 | self.edt_path_jsc.setGeometry(QtCore.QRect(230, 110, 251, 21)) 45 | self.edt_path_jsc.setObjectName("edt_path_jsc") 46 | self.btn_path_jsc = QtWidgets.QPushButton(self.centralwidget) 47 | self.btn_path_jsc.setGeometry(QtCore.QRect(490, 110, 41, 21)) 48 | self.btn_path_jsc.setObjectName("btn_path_jsc") 49 | self.edt_path_js = QtWidgets.QLineEdit(self.centralwidget) 50 | self.edt_path_js.setGeometry(QtCore.QRect(230, 160, 251, 21)) 51 | self.edt_path_js.setObjectName("edt_path_js") 52 | self.btn_path_js = QtWidgets.QPushButton(self.centralwidget) 53 | self.btn_path_js.setGeometry(QtCore.QRect(490, 160, 41, 21)) 54 | self.btn_path_js.setObjectName("btn_path_js") 55 | self.btn_decrypt = QtWidgets.QPushButton(self.centralwidget) 56 | self.btn_decrypt.setGeometry(QtCore.QRect(220, 220, 161, 23)) 57 | self.btn_decrypt.setObjectName("btn_decrypt") 58 | MainWindow.setCentralWidget(self.centralwidget) 59 | self.menubar = QtWidgets.QMenuBar(MainWindow) 60 | self.menubar.setGeometry(QtCore.QRect(0, 0, 639, 23)) 61 | self.menubar.setObjectName("menubar") 62 | MainWindow.setMenuBar(self.menubar) 63 | self.statusbar = QtWidgets.QStatusBar(MainWindow) 64 | self.statusbar.setObjectName("statusbar") 65 | MainWindow.setStatusBar(self.statusbar) 66 | 67 | self.retranslateUi(MainWindow) 68 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 69 | 70 | def retranslateUi(self, MainWindow): 71 | _translate = QtCore.QCoreApplication.translate 72 | MainWindow.setWindowTitle(_translate("MainWindow", "jsc -> js")) 73 | self.label.setText(_translate("MainWindow", "libcocos2djs.so路径")) 74 | self.label_2.setText(_translate("MainWindow", "jsc文件路径")) 75 | self.label_3.setText(_translate("MainWindow", "解密js文件保存路径")) 76 | self.btn_path_so.setText(_translate("MainWindow", "...")) 77 | self.btn_path_jsc.setText(_translate("MainWindow", "...")) 78 | self.btn_path_js.setText(_translate("MainWindow", "...")) 79 | self.btn_decrypt.setText(_translate("MainWindow", "解密")) 80 | 81 | 82 | class WindowAction(PyQt5.QtWidgets.QMainWindow): 83 | 84 | def __init__(self, obj:object): 85 | super(WindowAction, self).__init__() 86 | self.obj:Worker = obj 87 | 88 | 89 | def click_so(self): 90 | directory = QFileDialog.getOpenFileName(self, "请选择so路径", "./", "*.so") 91 | self.obj.ui.edt_path_so.setText(directory[0]) 92 | 93 | 94 | def click_jsc(self): 95 | directory = QFileDialog.getExistingDirectory(self, "请选择jsc文件目录", "./") 96 | self.obj.ui.edt_path_jsc.setText(directory) 97 | 98 | 99 | def click_js(self): 100 | directory = QFileDialog.getExistingDirectory(self, "请选择js文件保存路径", "./") 101 | self.obj.ui.edt_path_js.setText(directory) 102 | 103 | 104 | def click_decrypt(self): 105 | ret, msg = Decrypt_xxtea(self.obj.ui.edt_path_jsc.text(), Key.parse(self.obj.ui.edt_path_so.text())).run_decrypt(self.obj.ui.edt_path_js.text()) 106 | if ret: 107 | QMessageBox.information(self, "提示", '解密完成', QMessageBox.Ok) 108 | else: 109 | QMessageBox.critical(self, "解密出错", msg, QMessageBox.Ok) 110 | 111 | #*********************************************************************************** 112 | class Key(object): 113 | def __init__(self): 114 | pass 115 | 116 | @classmethod 117 | def parse(cls, path): 118 | with open(path, "rb") as js: 119 | cls.jsbytes = js.read() 120 | index = cls.jsbytes.find(bytes('jsb-adapter', 'utf-8')) 121 | return cls.get_key(index) 122 | 123 | 124 | @classmethod 125 | def get_key(cls, index): 126 | cls.key = bytearray() 127 | key_end = False 128 | num = 1 129 | while True: 130 | if cls.jsbytes[index - num] == 0x0: 131 | if key_end: 132 | cls.key.reverse() 133 | return cls.key.decode() 134 | else: 135 | if key_end == False: 136 | key_end = True 137 | cls.key.append(cls.jsbytes[index - num]) 138 | num += 1 139 | 140 | #*********************************************************************************** 141 | class Decrypt_xxtea(object): 142 | 143 | def __init__(self, path: str, key: str) -> None: 144 | ''' 145 | param: 146 | path : jsc文件所在目录 147 | key : 解密的key 148 | ''' 149 | self.delta = 0x9E3779B9 150 | self.path = path 151 | self.key = key.encode('utf-8') 152 | 153 | 154 | def long2str(self, v, w): 155 | n = (len(v) - 1) << 2 156 | if w: 157 | m = v[-1] 158 | if (m < n - 3) or (m > n): return '' 159 | n = m 160 | s = struct.pack('<%iL' % len(v), *v) 161 | return s[0:n] if w else s 162 | 163 | def str2long(self, s, w): 164 | n = len(s) 165 | m = (4 - (n & 3) & 3) + n 166 | s = s.ljust(m, b"\0") 167 | v = list(struct.unpack('<%iL' % (m >> 2), s)) 168 | if w: v.append(n) 169 | return v 170 | 171 | def decrypt(self, str): 172 | if str == b'': return str 173 | v = self.str2long(str, False) 174 | k = self.str2long(self.key.ljust(16, b"\0"), False) 175 | n = len(v) - 1 176 | z = v[n] 177 | y = v[0] 178 | q = 6 + 52 // (n + 1) 179 | sum = (q * self.delta) & 0xffffffff 180 | while (sum != 0): 181 | e = sum >> 2 & 3 182 | for p in range(n, 0, -1): 183 | z = v[p - 1] 184 | v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff 185 | y = v[p] 186 | z = v[n] 187 | v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff 188 | y = v[0] 189 | sum = (sum - self.delta) & 0xffffffff 190 | return self.long2str(v, True) 191 | 192 | 193 | def find_targets(self, path): 194 | result = [] 195 | if not os.path.exists(path): 196 | return [] 197 | if not os.path.isdir(path): 198 | return [path] 199 | for root, dirs, files in os.walk(path): 200 | for file in files: 201 | if file.endswith(".jsc"): 202 | result.append(os.path.join(root, file)) 203 | return result 204 | 205 | 206 | def run_decrypt(self, savePath): 207 | targets = self.find_targets(self.path) 208 | for target in targets: 209 | out = target[:-1] 210 | out = savePath + '/' + out.split('\\')[-1] 211 | content = open(target, "rb").read() 212 | if self.key: 213 | content = self.decrypt(content) 214 | if content[:2] == b'\037\213': 215 | try: 216 | mock_fp = BytesIO(content) 217 | gz = GzipFile(fileobj=mock_fp) 218 | content = gz.read() 219 | except Exception as e: 220 | return False, str(e) 221 | with open(out, 'wb') as _: 222 | _.write(content) 223 | return True, "" 224 | 225 | 226 | 227 | #*********************************************************************************** 228 | class Worker(object): 229 | def __init__(self): 230 | self.init() 231 | 232 | 233 | @classmethod 234 | def init(cls): 235 | cls.application = PyQt5.QtWidgets.QApplication(sys.argv) 236 | cls.ui = Ui_MainWindow() 237 | cls.window = WindowAction(cls) 238 | cls.window.setWindowIcon(PyQt5.QtGui.QIcon('./icon.png')) 239 | cls.ui.setupUi(cls.window) 240 | cls.setup_action() 241 | cls.window.show() 242 | sys.exit(cls.application.exec_()) 243 | 244 | 245 | @classmethod 246 | def setup_action(cls): 247 | cls.ui.btn_path_so.clicked.connect(cls.window.click_so) 248 | cls.ui.btn_path_jsc.clicked.connect(cls.window.click_jsc) 249 | cls.ui.btn_path_js.clicked.connect(cls.window.click_js) 250 | cls.ui.btn_decrypt.clicked.connect(cls.window.click_decrypt) 251 | #*********************************************************************************** 252 | if __name__ == '__main__': 253 | Worker() -------------------------------------------------------------------------------- /decrypt/dynamicDcrypt/Decrypt.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # -*-coding:utf-8 -*- 3 | 4 | """ 5 | # File : Decrypt.py 6 | # Time :2021/8/20 11:51 7 | # Author :Yooha 8 | """ 9 | 10 | from PyQt5 import QtCore, QtWidgets 11 | import PyQt5 12 | import sys 13 | import os 14 | from PyQt5.QtWidgets import QMessageBox 15 | import frida 16 | import time 17 | import subprocess 18 | 19 | 20 | 21 | #***************************************************************************************** 22 | class Ui_MainWindow(object): 23 | def setupUi(self, MainWindow): 24 | MainWindow.setObjectName("MainWindow") 25 | MainWindow.resize(318, 217) 26 | self.centralwidget = QtWidgets.QWidget(MainWindow) 27 | self.centralwidget.setObjectName("centralwidget") 28 | self.btn_cocos = QtWidgets.QPushButton(self.centralwidget) 29 | self.btn_cocos.setGeometry(QtCore.QRect(40, 30, 231, 31)) 30 | self.btn_cocos.setObjectName("btn_cocos") 31 | self.btn_unity = QtWidgets.QPushButton(self.centralwidget) 32 | self.btn_unity.setGeometry(QtCore.QRect(40, 100, 231, 31)) 33 | self.btn_unity.setObjectName("btn_unity") 34 | MainWindow.setCentralWidget(self.centralwidget) 35 | self.menubar = QtWidgets.QMenuBar(MainWindow) 36 | self.menubar.setGeometry(QtCore.QRect(0, 0, 318, 23)) 37 | self.menubar.setObjectName("menubar") 38 | MainWindow.setMenuBar(self.menubar) 39 | self.statusbar = QtWidgets.QStatusBar(MainWindow) 40 | self.statusbar.setObjectName("statusbar") 41 | MainWindow.setStatusBar(self.statusbar) 42 | 43 | self.retranslateUi(MainWindow) 44 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 45 | 46 | def retranslateUi(self, MainWindow): 47 | _translate = QtCore.QCoreApplication.translate 48 | MainWindow.setWindowTitle(_translate("MainWindow", "UCDecer 1.0")) 49 | self.btn_cocos.setText(_translate("MainWindow", " ")) 50 | self.btn_unity.setText(_translate("MainWindow", "")) 51 | 52 | 53 | class WindowAction(PyQt5.QtWidgets.QMainWindow): 54 | 55 | def __init__(self, decrypt:object): 56 | super(WindowAction, self).__init__() 57 | self.decrypt:DecryptApp = decrypt 58 | 59 | def click_cocos(self): 60 | self.decrypt.dialog_cocos.setupTitle('Cocos2D') 61 | self.decrypt.dialog_cocos.exec() 62 | 63 | def click_unity(self): 64 | self.decrypt.dialog_unity.setupTitle('Unity3D') 65 | self.decrypt.dialog_unity.exec() 66 | #***************************************************************************************** 67 | class Ui_dlg_unity(object): 68 | def setupUi(self, dlg_unity): 69 | dlg_unity.setObjectName("dlg_unity") 70 | dlg_unity.resize(531, 236) 71 | self.label = QtWidgets.QLabel(dlg_unity) 72 | self.label.setGeometry(QtCore.QRect(30, 30, 181, 31)) 73 | self.label.setObjectName("label") 74 | self.unity_dat = QtWidgets.QLineEdit(dlg_unity) 75 | self.unity_dat.setGeometry(QtCore.QRect(200, 29, 301, 31)) 76 | self.unity_dat.setObjectName("unity_dat") 77 | self.label_2 = QtWidgets.QLabel(dlg_unity) 78 | self.label_2.setGeometry(QtCore.QRect(30, 90, 181, 31)) 79 | self.label_2.setObjectName("label_2") 80 | self.unity_so = QtWidgets.QLineEdit(dlg_unity) 81 | self.unity_so.setGeometry(QtCore.QRect(200, 90, 301, 31)) 82 | self.unity_so.setObjectName("unity_so") 83 | self.unity_decrypt = QtWidgets.QPushButton(dlg_unity) 84 | self.unity_decrypt.setGeometry(QtCore.QRect(190, 160, 121, 31)) 85 | self.unity_decrypt.setObjectName("unity_decrypt") 86 | 87 | self.retranslateUi(dlg_unity) 88 | QtCore.QMetaObject.connectSlotsByName(dlg_unity) 89 | 90 | def retranslateUi(self, dlg_unity): 91 | _translate = QtCore.QCoreApplication.translate 92 | dlg_unity.setWindowTitle(_translate("dlg_unity", "Dialog")) 93 | self.label.setText(_translate("dlg_unity", "global-metadata.dat文件路径")) 94 | self.label_2.setText(_translate("dlg_unity", "libil2cpp.so文件路径")) 95 | self.unity_decrypt.setText(_translate("dlg_unity", "Decrypt")) 96 | 97 | 98 | class DialogUnityAction(PyQt5.QtWidgets.QDialog): 99 | 100 | def __init__(self, window): 101 | super(DialogUnityAction, self).__init__(window) 102 | self.ui = Ui_dlg_unity() 103 | self.window:WindowAction = window 104 | self.ui.setupUi(self) 105 | self.setupAction() 106 | 107 | def setupTitle(self, title): 108 | self.setWindowTitle(title) 109 | 110 | def setupAction(self): 111 | self.ui.unity_decrypt.clicked.connect(self.click_decrypt) 112 | 113 | def click_decrypt(self): 114 | try: 115 | current_path = os.path.dirname(os.path.abspath(sys.argv[0])) 116 | text_dat = self.ui.unity_dat.text() 117 | text_so = self.ui.unity_so.text() 118 | command = current_path + "/resource/Il2CppDumper/Il2CppDumper.exe " + text_so + ' ' + text_dat + ' ' + current_path + "/output" 119 | print(command) 120 | out = Shell.excute_cmd(command) 121 | if (str(out).find('Press any key to exit') != -1): 122 | QMessageBox.information(self,"提示", '解密完成!',QMessageBox.Yes | QMessageBox.No) 123 | except Exception as err: 124 | QMessageBox.warning(self,"错误", str(err),QMessageBox.Yes | QMessageBox.No) 125 | exit(2) 126 | #***************************************************************************************** 127 | class Ui_dlg_cocos(object): 128 | def setupUi(self, dlg_cocos): 129 | dlg_cocos.setObjectName("dlg_cocos") 130 | dlg_cocos.resize(374, 207) 131 | self.label = QtWidgets.QLabel(dlg_cocos) 132 | self.label.setGeometry(QtCore.QRect(30, 40, 91, 31)) 133 | self.label.setObjectName("label") 134 | self.cocos_pkg = QtWidgets.QLineEdit(dlg_cocos) 135 | self.cocos_pkg.setGeometry(QtCore.QRect(140, 40, 211, 31)) 136 | self.cocos_pkg.setObjectName("cocos_pkg") 137 | self.cocos_decrypt = QtWidgets.QPushButton(dlg_cocos) 138 | self.cocos_decrypt.setGeometry(QtCore.QRect(60, 90, 91, 31)) 139 | self.cocos_decrypt.setObjectName("cocos_decrypt") 140 | self.cocos_dump = QtWidgets.QPushButton(dlg_cocos) 141 | self.cocos_dump.setGeometry(QtCore.QRect(210, 90, 91, 31)) 142 | self.cocos_dump.setObjectName("cocos_dump") 143 | self.label_2 = QtWidgets.QLabel(dlg_cocos) 144 | self.label_2.setGeometry(QtCore.QRect(40, 130, 311, 51)) 145 | self.label_2.setObjectName("label_2") 146 | 147 | self.retranslateUi(dlg_cocos) 148 | QtCore.QMetaObject.connectSlotsByName(dlg_cocos) 149 | 150 | def retranslateUi(self, dlg_cocos): 151 | _translate = QtCore.QCoreApplication.translate 152 | dlg_cocos.setWindowTitle(_translate("dlg_cocos", "Dialog")) 153 | self.label.setText(_translate("dlg_cocos", "请输入应用包名")) 154 | self.cocos_decrypt.setText(_translate("dlg_cocos", "Decrypt")) 155 | self.cocos_dump.setText(_translate("dlg_cocos", "Dump")) 156 | self.label_2.setText(_translate("dlg_cocos", "提示:请点击手机应用的功能界面,以使脚本解密完全")) 157 | 158 | 159 | class DialogCocosAction(PyQt5.QtWidgets.QDialog): 160 | 161 | def __init__(self, window): 162 | super(DialogCocosAction, self).__init__(window) 163 | self.ui = Ui_dlg_cocos() 164 | self.window:WindowAction = window 165 | self.ui.setupUi(self) 166 | self.setupAction() 167 | self.cocos = None 168 | self.pkgname = None 169 | 170 | 171 | def setupTitle(self, title): 172 | self.setWindowTitle(title) 173 | 174 | def setupAction(self): 175 | self.ui.cocos_decrypt.clicked.connect(self.click_decrypt) 176 | self.ui.cocos_dump.clicked.connect(self.click_dump) 177 | 178 | 179 | def click_decrypt(self): 180 | self.pkgname = self.ui.cocos_pkg.text() 181 | if (self.pkgname == ''): 182 | QMessageBox.warning(self, "警告", "请先输入包名!", QMessageBox.Yes | QMessageBox.No) 183 | return 184 | else: 185 | QMessageBox.information(self,"提示","请先确保打开了frida server!",QMessageBox.Yes | QMessageBox.No) 186 | 187 | try: 188 | self.cocos = Process(self.pkgname) 189 | self.cocos.spawn("./resource/inject.js") 190 | except Exception as err: 191 | QMessageBox.warning(self, "警告", str(err), QMessageBox.Yes | QMessageBox.No) 192 | 193 | def click_dump(self): 194 | if self.cocos: 195 | try: 196 | Shell.excute_adb_multiple(['su\n', 'rm -R /sdcard/Download/dump/*.*\n', 'exit\n']) 197 | Shell.excute_adb_multiple(['su\n', 'chmod 777 /data/data/' + self.pkgname + '/dump\n', 'exit\n']) 198 | Shell.excute_adb_multiple(['su\n', 'mv /data/data/' + self.pkgname + '/dump /sdcard/Download\n', 'exit\n']) 199 | Shell.excute_adb_simple('adb pull /sdcard/Download/dump ./output/dump\n') 200 | except Exception as err: 201 | QMessageBox.warning(self,"错误",str(err),QMessageBox.Yes | QMessageBox.No) 202 | exit(2) 203 | #***************************************************************************************** 204 | class Process(object): 205 | 206 | def __init__(self, pkgname): 207 | self.pid = None 208 | self.pkgname = pkgname 209 | self.session = None 210 | self.script = None 211 | self.device = frida.get_usb_device(timeout=15) 212 | pass 213 | 214 | 215 | def spawn(self, hook): 216 | self.pid = self.device.spawn(self.pkgname) 217 | self.device.resume(self.pid) 218 | 219 | while True: # 每0.5秒获取一次session 直至成功 220 | try: 221 | time.sleep(0.5) 222 | self.session = self.device.attach(self.pid) 223 | except: 224 | continue 225 | break 226 | 227 | with open(hook, "r", encoding='utf-8') as f: 228 | self.script = self.session.create_script(f.read()) 229 | 230 | self.script.load() 231 | self.script.exports.decryptcocos(self.pkgname) 232 | return True 233 | 234 | #***************************************************************************************** 235 | class Shell(object): 236 | def __init__(self): 237 | pass 238 | 239 | @classmethod 240 | def excute_cmd(cls, cmd:str) -> list: 241 | obj = subprocess.Popen(cmd, shell = True, stdin=subprocess.PIPE, stdout=subprocess.PIPE ,stderr=subprocess.PIPE) 242 | info,err = obj.communicate() 243 | return (str(info.decode('gbk'))).split('\n') 244 | 245 | 246 | @classmethod 247 | def excute_adb_simple(cls, cmd:str) -> list: 248 | obj = subprocess.Popen(cmd, shell = True, stdin=subprocess.PIPE, stdout=subprocess.PIPE ,stderr=subprocess.PIPE) 249 | return obj.stdout.readlines() 250 | 251 | @classmethod 252 | def excute_adb_multiple(cls, cmd:list) -> list: 253 | info = None 254 | obj = subprocess.Popen(['adb', 'shell'], shell = True, stdin=subprocess.PIPE, stdout=subprocess.PIPE ,stderr=subprocess.PIPE) 255 | for line in cmd: 256 | obj.stdin.write(line.encode('utf-8')) 257 | info,err = obj.communicate() 258 | return (str(info.decode('gbk'))).split('\n') 259 | 260 | #***************************************************************************************** 261 | class DecryptApp(object): 262 | 263 | def __init__(self): 264 | self.application = PyQt5.QtWidgets.QApplication(sys.argv) 265 | self.ui = Ui_MainWindow() 266 | self.window = WindowAction(self) 267 | self.window.setWindowIcon(PyQt5.QtGui.QIcon('./resource/icon.png')) 268 | self.ui.setupUi(self.window) 269 | self.setup_action() 270 | self.dialog_cocos = DialogCocosAction(self.window) 271 | self.dialog_unity = DialogUnityAction(self.window) 272 | self.window.show() 273 | sys.exit(self.application.exec_()) 274 | 275 | def setup_action(self): 276 | self.ui.btn_cocos.clicked.connect(self.window.click_cocos) 277 | self.ui.btn_unity.clicked.connect(self.window.click_unity) 278 | 279 | 280 | 281 | if __name__ == '__main__': 282 | DecryptApp() 283 | 284 | 285 | 286 | --------------------------------------------------------------------------------