├── 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 | 
5 |
6 |
7 | 2 动态解密,需安装frida
8 | 支持Cocos框架中 libcocos2djs.so 解密js脚本
9 | 支持Cocos框架中 libcocos2dlua.so 解密lua脚本
10 | 支持Unity3d框架中 libil2cpp.so 解密dll、cs文件
11 |
12 | 主界面:
13 | 
14 |
15 | 功能界面
16 |
17 | 
18 |
19 |
20 |
21 |
22 | 
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 |
--------------------------------------------------------------------------------