游戏是图片应该XXTEA加密,资源的文件名混淆,找不到匹配的spine三件套对应名称
这是我整理的一部分内容Omniheroes部分
大佬有空说一下自己弄的话,解决的思路和方向吗
这是我最新的进度,按大佬的提示和看视频,我尝试搜索图片的统一头部标识QDREAM
但搜索QDREAM,找到的这里好像只是一个文本,不知道怎么进行下一步了。也没找到大佬图片里的那部分
下面放一个觉得好看的立绘看能不能吸引到有兴趣的大佬吧。
提示:
这游戏spine文件应该只有待机立绘和战斗小人
看起来像异或
挖坟+接着求助(国庆又试了一下,太菜了我)
用豆包扒了两天 计算前14位异或可以和QIAN-MERCURY匹配,但是用xor软件解了之后还是打不开图片,豆包写的py也不行。
今天又额外扒到点东西,我更想不明白哪里出问题了
int sub_ABCD30()
{
byte_22DCFA0[0] = 24;
strcpy((char *)&qword_22DCFA1, “QIAN-MERCURY”);
byte_22DCFB8 = 18;
strcpy((char *)&qword_22DCFB9, “KUN-VENUS”);
byte_22DCFD0 = 20;
strcpy((char *)&qword_22DCFD1, “ZHEN-EARTH”);
byte_22DCFE8 = 16;
strcpy((char *)&qword_22DCFE9, “XUN-MARS”);
byte_22DD000 = 22;
strcpy((char *)&qword_22DD001, “KAN-JUPITER”);
byte_22DD018 = 18;
strcpy((char *)&qword_22DD019, “LI-SATURN”);
byte_22DD030 = 20;
strcpy((char *)&qword_22DD031, “GEN-URANUS”);
byte_22DD048 = 22;
strcpy((char *)&qword_22DD049, “DUI-NEPTUNE”);
return __cxa_atexit(sub_ABCC20, 0, &off_21FA0C0);
}
s大佬发的我尝试去找了,没找到…..hook我也试了,然后弄成了切换角色的时候读取哪些文件(菜)。豆包说读取明文内存,可是我adb死活操作不了开启软件和移动文件的权限,也就没法生成,frida的指令也是用的吾爱的指令成功连接的。
有好心的大佬帮忙的解答的话万分感谢,祝大家节日快乐
dump出来是八卦啊,有意思的
77c8e53978 18 51 49 41 4e 2d 4d 45 52 43 55 52 59 00 00 00 .QIAN-MERCURY...
77c8e53988 00 00 00 00 00 00 00 00 12 4b 55 4e 2d 56 45 4e .........KUN-VEN
77c8e53998 55 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00 US..............
77c8e539a8 14 5a 48 45 4e 2d 45 41 52 54 48 00 00 00 00 00 .ZHEN-EARTH.....
77c8e539b8 00 00 00 00 00 00 00 00 10 58 55 4e 2d 4d 41 52 .........XUN-MAR
77c8e539c8 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 S...............
77c8e539d8 16 4b 41 4e 2d 4a 55 50 49 54 45 52 00 00 00 00 .KAN-JUPITER....
77c8e539e8 00 00 00 00 00 00 00 00 12 4c 49 2d 53 41 54 55 .........LI-SATU
77c8e539f8 52 4e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 RN..............
77c8e53a08 14 47 45 4e 2d 55 52 41 4e 55 53 00 00 00 00 00 .GEN-URANUS.....
77c8e53a18 00 00 00 00 00 00 00 00 16 44 55 49 2d 4e 45 50 .........DUI-NEP
77c8e53a28 54 55 4e 45 00 00 00 00 00 00 00 00 00 00 00 00 TUNE............
77c8e53a38 20 6c 75 cd 77 00 00 b4 00 00 00 00 00 00 00 00
我去,只顾着找还真没注意是拼音八卦
代码如下,试了下解出来四标准astc的魔数
import struct
import hashlib
def cal_index(t):
t &= 0xFFFFFFFFFFFFFFFF
x8 = (t + 0x1B77400) & 0xFFFFFFFFFFFFFFFF
x10 = x8 >> 10
# 取高64位
x9_umulh = ((x10 * 0x31B5D43AFE99EF) >> 64) & 0xFFFFFFFFFFFFFFFF
x9_lsr = x9_umulh >> 6
x8_mod = (x8 - (x9_lsr * 0x5265C00)) & 0xFFFFFFFFFFFFFFFF
x8_mul = (x8_mod * 0x31B5D43B) & 0xFFFFFFFFFFFFFFFF
index = x8_mul >> 0x35
return index
def dec(i):
data = bytearray(i)
t = struct.unpack('<Q', data[6:14])[0]
KEY_TABLE = [
"QIAN-MERCURY", "KUN-VENUS", "ZHEN-EARTH", "XUN-MARS",
"KAN-JUPITER", "LI-SATURN", "GEN-URANUS", "DUI-NEPTUNE"
]
salt = KEY_TABLE[cal_index(t)]
pld = data[14:]
# nibbles
ex = []
for b in hashlib.sha256(f"{salt}{t}".encode()).digest():
ex.append((b >> 4) & 0xF)
ex.append(b & 0xF)
for i in range(min(100, len(pld))):
idx = [(1, 2), (4, 5), (31, 32)][i % 3]
if idx[1] < len(ex):
key = (ex[idx[0]] + ex[idx[1]]) & 0xFF
if key != 0:
pld[i] ^= key
return bytes(pld)
if __name__ == "__main__":
with open('0d3e1bc1-ce94-40a9-86a3-3e3d7ab20e06.astc', 'rb') as f:
enc = f.read()
with open('dec.astc', 'wb') as f:
f.write(dec(enc))
密钥表,挺有意思
0:"QIAN-MERCURY" (乾 - 水星)
1: "KUN-VENUS" (坤 - 金星)
2: "ZHEN-EARTH" (震 - 地球)
3: "XUN-MARS" (巽 - 火星)
4: "KAN-JUPITER" (坎 - 木星)
5: "LI-SATURN" (离 - 土星)
6: "GEN-URANUS" (艮 - 天王星)
7: "DUI-NEPTUNE" (兑 - 海王星)
感谢大佬
他密钥索引那一块有点问题,我在看看。
临时加了个暴搜,勉强能用,但是长度那部分还得再看看。
import struct
import hashlib
import texture2ddecoder
from pathlib import Path
from PIL import Image
def to_int32(n):
return (n & 0xFFFFFFFF) if n < 0x80000000 else (n & 0xFFFFFFFF) - 0x10000000000
def to_uint32(n):
return n & 0xFFFFFFFF
def cal_index(t):
t &= 0xFFFFFFFFFFFFFFFF
x8 = (t + 0x1B77400) & 0xFFFFFFFFFFFFFFFF
x10 = x8 >> 10
x9_umulh = ((x10 * 0x31B5D43AFE99EF) >> 64) & 0xFFFFFFFFFFFFFFFF
x9_lsr = x9_umulh >> 6
x8_mod = (x8 - (x9_lsr * 0x5265C00)) & 0xFFFFFFFFFFFFFFFF
x8_mul = (x8_mod * 0x31B5D43B) & 0xFFFFFFFFFFFFFFFF
index = x8_mul >> 0x35
return index
def calculate_decrypt_len(sha256_hash):
s = []
v82 = struct.unpack('<8I', sha256_hash)
for val in v82:
for j in range(4):
byte = (val >> (j * 8)) & 0xFF
s.append(byte >> 4)
s.append(byte & 0x0F)
v_stack = [to_int32(x) for x in s]
v1_vec = [v_stack[i] + v_stack[i+4] + v_stack[i+8] + v_stack[i+12] for i in range(4)]
v2_vec = [v_stack[i+16] + v_stack[i+20] + v_stack[i+24] + v_stack[i+28] for i in range(4)]
v3_vec = [v_stack[i+32] + v_stack[i+36] + v_stack[i+40] + v_stack[i+44] for i in range(4)]
v4_vec = [v_stack[i+48] + v_stack[i+52] + v_stack[i+56] + v_stack[i+60] for i in range(4)]
v40_vec = [
to_int32(v1_vec[0] + v2_vec[0] + v3_vec[0] + v4_vec[0]),
to_int32(v1_vec[1] + v2_vec[1] + v3_vec[1] + v4_vec[1]),
to_int32(v1_vec[2] + v2_vec[2] + v3_vec[2] + v4_vec[2]),
to_int32(v1_vec[3] + v2_vec[3] + v3_vec[3] + v4_vec[3])
]
v41 = sum(v40_vec)
v42_base = []
m = 0xCCCCCCCD
for val in v40_vec:
val_s32 = to_int32(val)
mul_res_64 = val_s32 * m
shifted = (mul_res_64 >> 32) >> 3
v42_base.append(to_int32(val_s32 - shifted * 10))
for i in range(len(v42_base)):
if v42_base[i] == 0: v42_base[i] = 1
v18 = to_uint32(v41)
v44 = (v18 % 10) or 1
v43 = ((v41 >> 32) % 10) or 1
v45_part1 = to_int32(v42_base[0] * v42_base[2])
v45_part2 = to_int32(v42_base[1] * v42_base[3])
decrypt_len = to_uint32(v43 * v44 * v45_part1 * v45_part2)
if decrypt_len <= 100: decrypt_len = 100
return decrypt_len
def brute(enc, ex, b=8):
ASTC_MAGIC = 0x5CA1AB13
test_data = bytearray(enc[:b])
max_idx = len(ex) - 1
for idx0 in range(max_idx):
for idx1 in range(max_idx):
for idx2 in range(max_idx):
pattern = [(idx0, idx0+1), (idx1, idx1+1), (idx2, idx2+1)]
test = bytearray(test_data)
for i in range(b):
idx_pair = pattern[i % 3]
xor_key = (ex[idx_pair[0]] + ex[idx_pair[1]]) & 0xFF
test[i] ^= xor_key
if len(test) >= 4 and struct.unpack('<I', test[:4])[0] == ASTC_MAGIC:
return pattern
return None
def dec(input):
data = bytearray(input)
t = struct.unpack('<Q', data[6:14])[0]
KEY_TABLE = ["QIAN-MERCURY", "KUN-VENUS", "ZHEN-EARTH", "XUN-MARS", "KAN-JUPITER", "LI-SATURN", "GEN-URANUS", "DUI-NEPTUNE"]
index = cal_index(t)
salt = KEY_TABLE[index]
key_string = f"{salt}{t}"
print(f"时间戳: {t}")
print(f"密钥盐: {salt}")
sha256_hash = hashlib.sha256(key_string.encode()).digest()
payload = data[14:]
decrypt_len = calculate_decrypt_len(sha256_hash)
aligned_len = (decrypt_len + 16 - 1) // 16 * 16
expanded_for_brute = []
for byte in sha256_hash:
expanded_for_brute.append((byte >> 4) & 0xF)
expanded_for_brute.append(byte & 0xF)
key_pattern = brute(payload, expanded_for_brute)
print(key_pattern)
for i in range( min(aligned_len, len(payload))):
idx_pair = key_pattern[i % 3]
xor_key = (expanded_for_brute[idx_pair[0]] + expanded_for_brute[idx_pair[1]]) & 0xFF
payload[i] ^= xor_key
return bytes(payload)
def conv(data, path):
header = data[:16]
magic = struct.unpack('<I', header[:4])[0]
block_x, block_y = header[4], header[5]
xsize = int.from_bytes(header[7:10], 'little')
ysize = int.from_bytes(header[10:13], 'little')
print(f"{xsize}x{ysize},块{block_x}x{block_y}")
decoded = texture2ddecoder.decode_astc(data, xsize, ysize, block_x, block_y)
image = Image.frombytes('RGBA', (xsize, ysize), decoded)
image.save(path, 'PNG')
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='QDREAM ASTC解密')
parser.add_argument('i', help='加密ASTC文件')
args = parser.parse_args()
with open(args.i, 'rb') as f:
enc = f.read()
conv(dec(enc), (Path(args.i).stem + '.png'))
辛苦了