CocosCreator 通过uuid逆向还原资源

通过uuid逆向还原资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/python3
# cocos2d-js资源还原 + 整理输出(忽略 .json 文件,递归 assets)
import os
import json
import shutil
import re

# ---------- UUID 解码表 ----------
i = [64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51]
n = '0123456789abcdef'
s = [0,1,2,3,4,5,6,7,9,10,11,12,14,15,16,17,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35]
a_template = ["", "", "", "", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "", "", "", "", "", "", "", ""]

def decode_uuid(t):
if len(t) != 22:
return t
a = a_template.copy()
a[0] = t[0]
a[1] = t[1]
r = 2
for e in range(2, 22, 2):
o = i[ord(t[e])]
l = i[ord(t[e + 1])]
a[s[r]] = n[o >> 2]
a[s[r + 1]] = n[(3 & o) << 2 | l >> 4]
a[s[r + 2]] = n[15 & l]
r += 3
return ''.join(a)

# ---------- 匹配完整 UUID 格式 ----------
uuid_regex = re.compile(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', re.IGNORECASE)

# ---------- 遍历 assets 下所有 cc.config*.json 文件 ----------
assets_root = "assets"
config_files = []
for root, dirs, files in os.walk(assets_root):
for file in files:
if file.startswith("cc.config") and file.endswith(".json"):
config_files.append(os.path.join(root, file))

print(f"找到 {len(config_files)} 个 cc.config.json 文件")

# ---------- 解析 UUID ----------
uuid_map = {} # {uuid: resource_path}
for cfg_file in config_files:
cfg = json.load(open(cfg_file, "r", encoding="utf-8"))
uuids = cfg.get("uuids", [])
paths = cfg.get("paths", {})
# 解码 uuids
decoded_uuids = [decode_uuid(u) for u in uuids]
for k, v in paths.items():
uuid_index = int(k)
uuid = decoded_uuids[uuid_index]
# 只保留完整 UUID
if uuid_regex.match(uuid):
resource_path = v[0] # 资源对应的路径名
uuid_map[uuid] = resource_path

print(f"解析出 {len(uuid_map)} 个有效 UUID")

# ---------- 遍历 assets 目录找到对应资源 ----------
found_count = 0
for root, dirs, files in os.walk(assets_root):
for file in files:
for uuid, resource_path in uuid_map.items():
uuid_compact = uuid.replace("-", "")
if uuid_compact in file.replace("-", ""):
# 忽略 .json 文件
if file.lower().endswith(".json"):
continue
src_file = os.path.join(root, file)
final_ext = "".join(os.path.splitext(src_file)[1:]) # 支持多点扩展名
final_dir = os.path.join("output", os.path.dirname(resource_path))
os.makedirs(final_dir, exist_ok=True)
final_path = os.path.join(final_dir, os.path.basename(resource_path) + final_ext)

# 重名文件加索引
if os.path.exists(final_path):
index = 1
while True:
new_final = os.path.join(final_dir, f"{os.path.basename(resource_path)}_{index}{final_ext}")
if not os.path.exists(new_final):
final_path = new_final
break
index += 1

shutil.copy(src_file, final_path)
print(f"{resource_path:40} | {uuid} | {final_path}")
found_count += 1
break # 一个文件对应一个 UUID

print(f"整理完成,共还原 {found_count} 个资源文件(忽略 .json 文件,无空目录)")