diff --git a/chuni/calc_title_server_enc_key.py b/chuni/calc_title_server_enc_key.py new file mode 100644 index 0000000..d0dbca1 --- /dev/null +++ b/chuni/calc_title_server_enc_key.py @@ -0,0 +1,91 @@ +from hashlib import pbkdf2_hmac +import os +import struct +import sys +import re + +from Crypto.Hash import SHA1 +import pefile + +from Crypto.Protocol.KDF import PBKDF2 + +def rva2offset(pe: pefile.PE, rva: int): + for section in pe.sections: + if section.contains_rva(rva): + return section.get_offset_from_rva(rva) + + return -1 + +if len(sys.argv) < 2: + print(f"Usage: python {os.path.basename(__file__)} ") + exit(1) + +exe_path = sys.argv[1] + +KEY_PASSWORD_RE = re.compile(rb"\?AVSystemInterface@projClient@@....(?P....)") +KEY_SALT_RE = re.compile(rb"\x50\x6A\x20\x6A(?P.)\x6A\x10\x2B\xCA\x68(?P....)\x51\x55\xE8....") +SALT_PASSWORD_RE = re.compile(rb"\?AVDeflate@projClient@@\x00\x00\x00\x00....(?P....)(?P....)") +SALT_SALT_RE = re.compile(rb"\x52\x6A\x08\x6A(?P.)\x6A\x10\x68(?P....)\x51\x53\xE8....") +IV_RE_1 = re.compile(rb"\xF3\x0F\x7E\x05(?P....)\x8B\x74\x24\x24\x6A\x01") +IV_RE_2 = re.compile(rb"\xE8....\xF3\x0F\x7E\x05(?P....)\x6A\x01") +ITER_COUNT_RE = re.compile(rb"\xC7\x86....(?P....)\x0F\x8C....\x85\xED\x0F\x84....\x85\xDB\x0F\x84....") + +with open(exe_path, "rb") as f: + exe = f.read() + +pe = pefile.PE(data=exe, fast_load=True) +base_address = pe.OPTIONAL_HEADER.ImageBase + +if (pmatch := KEY_PASSWORD_RE.search(exe)) and (smatch := KEY_SALT_RE.search(exe)): + poffset = rva2offset(pe, struct.unpack(" ") + exit(1) + +with open(sys.argv[1], "rb") as f: + key = blake2b( + f.read(), + digest_size=32, + key=KEY_IV_DIGEST_FIXED, + ).hexdigest() + + print(f"Key: {key}") + +with open(sys.argv[2], "rb") as f: + iv = blake2b( + f.read(), + digest_size=32, + key=KEY_IV_DIGEST_FIXED, + ).hexdigest() + + print(f"IV: {iv}") + +with open(sys.argv[3], "rb") as f: + salt = blake2b( + f.read(), + digest_size=32, + key=KEY_IV_DIGEST_FIXED, + ).hexdigest() + + print(f"Endpoint salt: {salt}")