Cocos Creator 2.X(Cocos2d-js)游戏资源目录分析&逆向还原
js注入版筹划中,不咕的话下周可以更新?
拿到了某变态服游戏,打开lib看到了libcocos2djs.so,判断版本为2.4。游戏把资源文件下载到了/data下,因此需要root。目录结构如下:
g4-start/
├── config.json
├── import
│ ├── 1e
│ │ └── 1ea6e4bcd.json
│ └── e7
│ └── e76cb2d2-fa48-4916-8c8c-d7f64ee0c948.json
└── native
└── 1e
└── 1ea6e4bcd.png
可以看到,文件名全部被改为了UUID,不利于处理。打开config.json,uuid项里竟然是Base64(但不是)!在cocos2d/core/utils/decode-uuid看到了对应的源码,成功还原uuid,再通过paths项还原目录结构。
话不多说,上完整代码(在资源目录下运行)
#!/usr/bin/python3
# cocos2d-js资源还原
# Date: 2024/2/14
import os
import json
import shutil
# static sheets
# src: cocos2d/core/utils/decode-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]
a = ["", "", "", "", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "", "", "", "", "", "", "", ""]
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]
def decode_uuid(t):
if len(t) != 22:
return t
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)
def replace_uuids(json_str):
data = json.loads(json_str)
uuids = data.get('uuids', [])
decoded_uuids = [decode_uuid(uuid) for uuid in uuids]
data['uuids'] = decoded_uuids
return json.dumps(data)
if not os.path.exists('config_patch.json'):
json_str = open("config.json").read()
json_str = replace_uuids(json_str)
file = open("config_patch.json", "w")
file.write(json_str)
file.close() #Windows需要close
config = json.load(open('config_patch.json'))
# 遍历paths
for key, value in config["paths"].items():
path = value[0]
uuid_index = int(key)
uuid = config["uuids"][uuid_index]
output_dir = f"output/{path}"
os.makedirs(output_dir, exist_ok=True)
# 在import和native两个目录下判断{对应uuid前两位}/{对应uuid}.*
for root, dirs, files in os.walk("import"):
for file in files:
if uuid[:2] in root and uuid in file:
src_file = os.path.join(root, file)
dst_file = os.path.join(output_dir, file)
# 如果output目录已存在同名文件,重命名
if os.path.exists(dst_file):
index = 1
while True:
new_dst_file = os.path.join(output_dir, f"{file}.{index}")
if not os.path.exists(new_dst_file):
dst_file = new_dst_file
break
index += 1
shutil.copy(src_file, dst_file)
for root, dirs, files in os.walk("native"):
for file in files:
if uuid[:2] in root and uuid in file:
src_file = os.path.join(root, file)
dst_file = os.path.join(output_dir, file)
if os.path.exists(dst_file):
index = 1
while True:
new_dst_file = os.path.join(output_dir, f"{file}.{index}")
if not os.path.exists(new_dst_file):
dst_file = new_dst_file
break
index += 1
shutil.copy(src_file, dst_file)
#对单文件目录的处理
files = os.listdir(output_dir)
if len(files) == 1 and os.path.isfile(os.path.join(output_dir, files[0])):
file_to_move = os.path.join(output_dir, files[0])
new_path = os.path.join(os.path.dirname(output_dir), os.path.basename(output_dir) + os.path.splitext(files[0])[1])
if os.path.exists(new_path):
index = 1
while True:
new_paths = str(index) + "_" + new_path
if not os.path.exists(new_paths):
new_path = new_paths
break
index += 1
try:
os.rename(file_to_move, new_path)
except:
print(f"诶, {new_path} 无法访问")
os.rmdir(output_dir)
print("文件复制完成")
补:对于spine JSON文件的提取:
import os
import json
import shutil
import sys
# static sheets
# src: cocos2d/core/utils/decode-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]
a = ["", "", "", "", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "-", "", "", "", "", "", "", "", "", "", "", "", ""]
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]
def decode_uuid(t):
if len(t) != 22:
return t
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)
def parse_json_files(directory):
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith('.json'):
json_file = os.path.join(root, file)
with open(json_file, 'r') as f:
json_data = json.load(f)
try:
if json_data[3][0][0] != 'sp.SkeletonData':
continue
except:
# Wrong format, skip
continue
spine_data = json_data[5][0]
spine_name = os.path.basename(os.path.dirname(json_file))
if isinstance(spine_data[4], dict):
with open(os.path.join(root, f'{spine_name}.skel.json'), 'w') as f:
json.dump(spine_data[4], f)
with open(os.path.join(root, f'{spine_name}.atlas'), 'w') as f:
f.write(spine_data[2])
png_files = [f for f in os.listdir(root) if f.endswith('.png')]
if len(png_files) > 1:
print(f'error: 出现多个.png,目录: {root}')
elif len(png_files) == 1:
shutil.copyfile(os.path.join(root, png_files[0]), os.path.join(root, f'{spine_name}.png'))
else:
with open(os.path.join(root, f'{spine_name}.atlas'), 'w') as f:
f.write(spine_data[3])
bin_files = [f for f in os.listdir(root) if f.endswith('.bin')]
if len(bin_files) > 1:
print(f'error: 出现多个.bin,目录: {root}')
elif len(bin_files) == 1:
shutil.copyfile(os.path.join(root, bin_files[0]), os.path.join(root, f'{spine_name}.skel.json'))
png_files = [f for f in os.listdir(root) if f.endswith('.png')]
if len(png_files) > 1:
print(f'error: 出现多个.png,目录: {root}')
elif len(png_files) == 1:
shutil.copyfile(os.path.join(root, png_files[0]), os.path.join(root, f'{spine_name}.png'))
parse_json_files('.')
--------------
你已经看完这篇博文了!
本文来自博客园,作者:星如雨yu,转载请注明原文链接:https://www.cnblogs.com/tianpanyu/p/18015389
另,建议转载手动看一眼,把代码块转过去呗(超小声嘀咕)