造梦西游3再续天庭 存档修改
2026-06-27
《再续天庭1.1》的存档解密逻辑主要经历了四个步骤:
第一步,程序读取指定的加密存档文件,并去除其中的换行和空格,然后使用自定义的 Base64 字符表“zYxWvUtSrQpOnMlKjIhGfEdCbAaBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890+/=”对文本进行变体 Base64 解码,将其还原为原始的字节数组;
第二步,程序对该字节数组中的每一个字节进行异或(XOR)运算,固定的异或密钥为十进制的 90(即十六进制的 0x5A),这一步利用了异或运算的自反性来逆转混淆;
第三步,程序进入一个最多执行 10 次的循环,尝试使用 Zlib 库进行多层解压缩,期间会兼顾处理包含或不包含标准标头的压缩流数据,直到无法继续解压、触发异常时自动跳出循环;
第四步,程序进行 AMF3 协议的数据反序列化解析,首先校验第一个字节是否为数字 6(代表字符串对象),验证通过后通过特定的位移运算读取紧随其后的 AMF3 变长整数(U29)以确定 XML 字符串的实际长度,将其右移 1 位得到真正的长度值,并根据该长度截取并使用 UTF-8 编码解码出 XML 明文,最终利用 minidom 库对 XML 进行美化排版并保存为以 .xml 结尾的文本文件。
附上python代码
import os
import zlib
import xml.dom.minidom
# 完美对齐解密出来的自定义 Base64 字符表
CUSTOM_ALPHABET = "zYxWvUtSrQpOnMlKjIhGfEdCbAaBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890+/="
XOR_KEY = 90 # 0x5A
def custom_b64decode(s: str) -> bytearray:
"""变体 Base64 解码逻辑 (函数 o)"""
s = s.strip().replace("\r", "").replace("\n", "").replace(" ", "")
data = bytearray()
for i in range(0, len(s), 4):
chunk = s[i:i+4]
c = [CUSTOM_ALPHABET.index(char) if char in CUSTOM_ALPHABET else 64 for char in chunk]
while len(c) < 4:
c.append(64)
b = (c[0] << 2) | ((c[1] & 48) >> 4)
d = ((c[1] & 15) << 4) | ((c[2] & 60) >> 2)
g = ((c[2] & 3) << 6) | c[3]
data.append(b)
if c[2] != 64: data.append(d)
if c[3] != 64: data.append(g)
return data
def custom_b64encode(g: bytearray) -> str:
"""变体 Base64 编码逻辑 (函数 p)"""
a = ""
for b in range(0, len(g), 3):
c = min(3, len(g) - b)
d = g[b]
e = g[b + 1] if c > 1 else 0
f = g[b + 2] if c > 2 else 0
h = (d & 252) >> 2
i = (d & 3) << 4 | (e & 240) >> 4
j = (e & 15) << 2 | (f & 192) >> 6
k = f & 63
a += CUSTOM_ALPHABET[h] + CUSTOM_ALPHABET[i]
a += CUSTOM_ALPHABET[j] if c > 1 else CUSTOM_ALPHABET[64]
a += CUSTOM_ALPHABET[k] if c > 2 else CUSTOM_ALPHABET[64]
return a
def read_amf3_integer(data: bytearray, pos: int):
"""AMF3 变长整数 (U29) 读取逻辑 (函数 m)"""
result = 0
for i in range(4):
b = data[pos]
pos += 1
if i < 3:
result = (result << 7) | (b & 127)
if (b & 128) == 0: break
else:
result = (result << 8) | b
return result, pos
def write_amf3_integer(c: int) -> bytearray:
"""AMF3 变长整数 (U29) 写入逻辑 (函数 n)"""
a = []
if c < 128:
a.push(c) if hasattr(a, 'push') else a.append(c)
elif c < 16384:
a.append(c >> 7 & 127 | 128)
a.append(c & 127)
elif c < 2097152:
a.append(c >> 14 & 127 | 128)
a.append(c >> 7 & 127 | 128)
a.append(c & 127)
else:
a.append(c >> 22 & 127 | 128)
a.append(c >> 15 & 127 | 128)
a.append(c >> 8 & 127 | 128)
a.append(c & 255)
return bytearray(a)
def format_xml(xml_str: str) -> str:
"""对 XML 进行美化排版"""
try:
dom = xml.dom.minidom.parseString(xml_str)
return dom.toprettyxml(indent=" ")
except:
return xml_str
def compress_xml(xml_str: str) -> str:
"""去除 XML 格式化引入的换行和缩进,还原紧凑字符串"""
lines = [line.strip() for line in xml_str.splitlines() if line.strip()]
return "".join(lines)
def cmd_decrypt():
path = input("\n请输入要解密的存档路径 (如 2.sav): ").strip().strip('"')
if not os.path.exists(path):
print("[-] 错误:找不到指定文件。")
return
try:
with open(path, "r", encoding="utf-8") as f:
raw_content = f.read()
# 1. Base64 还原
bytes_data = custom_b64decode(raw_content)
# 2. XOR 90 解密
for i in range(len(bytes_data)): bytes_data[i] ^= XOR_KEY
# 3. 多层 Zlib 解压
for _ in range(10):
try:
try: bytes_data = zlib.decompress(bytes_data, -zlib.MAX_WBITS)
except zlib.error: bytes_data = zlib.decompress(bytes_data)
except zlib.error: break
# 4. AMF3 解析
if bytes_data[0] != 6:
print("[-] 校验失败:该文件不是合法的 AMF3 存档数据。")
return
amf3_value, next_pos = read_amf3_integer(bytes_data, 1)
str_len = amf3_value >> 1
xml_bytes = bytes_data[next_pos : next_pos + str_len]
xml_text = xml_bytes.decode('utf-8')
# 美化排版并保存
pretty_xml = format_xml(xml_text)
out_path = path + ".xml"
with open(out_path, "w", encoding="utf-8") as out_f:
out_f.write(pretty_xml)
print(f"[+] 解密成功!明文已格式化保存至: {out_path}")
print(" 你可以直接用记事本打开修改它。")
except Exception as e:
print(f"[-] 解密过程中发生异常: {e}")
def cmd_encrypt():
path = input("\n请输入修改后的 XML 明文路径 (如 2.sav.xml): ").strip().strip('"')
if not os.path.exists(path):
print("[-] 错误:找不到指定文件。")
return
try:
with open(path, "r", encoding="utf-8") as f:
xml_content = f.read()
# 压缩掉美化排版的空格和换行
clean_xml = compress_xml(xml_content)
xml_bytes = clean_xml.encode('utf-8')
# 1. AMF3 序列化打包 (函数 l)
amf3_len_code = (len(xml_bytes) << 1) | 1
amf3_len_bytes = write_amf3_integer(amf3_len_code)
amf3_packet = bytearray([6]) + amf3_len_bytes + xml_bytes
# 2. Zlib 压缩
compressed = zlib.compress(amf3_packet)
compressed_bytes = bytearray(compressed)
# 3. XOR 90 加密
for i in range(len(compressed_bytes)): compressed_bytes[i] ^= XOR_KEY
# 4. 变体 Base64 编码
final_string = custom_b64encode(compressed_bytes)
# 保存为新存档
out_path = path.replace(".xml", "") if path.endswith(".xml") else path + ".sav"
if out_path == path: out_path += ".new"
with open(out_path, "w", encoding="utf-8") as out_f:
out_f.write(final_string)
print(f"[+] 加密成功!新存档已打包输出至: {out_path}")
print(" 你可以将此文件改回游戏要求的名字放回存档目录。")
except Exception as e:
print(f"[-] 加密过程中发生异常: {e}")
def main():
print("=" * 45)
print(" 《再续天庭1.1》存档算法逆向破解工具")
print("=" * 45)
while True:
print("\n[可用指令] 1: 加密打包存档 2: 解密分析存档 0: 退出")
choice = input("请输入指令数字: ").strip()
if choice == "1":
cmd_encrypt()
elif choice == "2":
cmd_decrypt()
elif choice == "0":
print("退出程序。")
break
else:
print("[-] 无效指令,请重新输入。")
if __name__ == "__main__":
main()
发表评论: