def get_imei(): candidates = [] class Parcel(object): # https://gist.github.com/ktnr74/60ac7bcc2cd17b43f2cb def __init__(self, text): if text.startswith(b'Result: Parcel(') and text.endswith(b'\')'): self.data = b''.join([struct.pack('<L', int(x, 16)) for x in re.findall(b'([0-9a-f]{8}) ', text)]) self.resultcode = self.get_int(0) else: raise Exception('Unexpected input!') def get_int(self, offset=4): return int(struct.unpack('<L', self.data[offset:offset+4])[0]) def get_utf16(self, offset=4): return (self.data[offset + 4: offset+4+self.get_int(offset) * 2]).decode('utf-16') out = subproc_succ("adb shell service call iphonesubinfo 1") imei = Parcel(out.strip()).get_utf16() logger.info(f"found imei={imei} from iphonesubinfo") candidates.append(imei) out = subproc_succ(f"adb shell su -c \"cat {MM_DIR}/MicroMsg/CompatibleInfo.cfg\"") try: # https://gist.github.com/ChiChou/36556fd412a9e3216abecf06e084e4d9 jobj = javaobj.loads(out) imei = jobj[258] except: logger.warning("imei not found in CompatibleInfo.cfg") else: candidates.append(imei) logger.info(f"found imei={imei} in CompatibleInfo.cfg") logger.info(f"Possible imei: {candidates}") return list(set(candidates))
def get_uin(): candidates = [] try: uin = None out = subproc_succ(f"adb shell cat {MM_DIR}/shared_prefs/system_config_prefs.xml") for line in out.decode('utf-8').split("\n"): if "default_uin" in line: line = PyQuery(line) uin = line.attr["value"] break uin = int(uin) except Exception: logger.warning("uin not found in system_config_prefs.xml") else: candidates.append(uin) logger.info(f"found uin={uin} in system_config_prefs.xml") try: uin = None out = subproc_succ(f"adb shell cat {MM_DIR}/shared_prefs/com.tencent.mm_preferences.xml") for line in out.decode('utf-8').split("\n"): if "last_login_uin" in line: line = PyQuery(line) uin = line.text() break uin = int(uin) except Exception: logger.warning("uin not found in com.tencent.mm_preferences.xml") else: candidates.append(uin) logger.info(f"found uin={uin} in com.tencent.mm_preferences.xml") try: uin = None out = subproc_succ(f"adb shell cat {MM_DIR}/shared_prefs/auth_info_key_prefs.xml") for line in out.decode('utf-8').split("\n"): if "auth_uin" in line: line = PyQuery(line) uin = line.attr["value"] break uin = int(uin) except Exception: logger.warning("uin not found in auth_info_key_prefs.xml") else: candidates.append(uin) logger.info(f"found uin={uin} in auth_info_key_prefs.xml") try: out = subproc_succ(f"adb shell cat {MM_DIR}/MicroMsg/systemInfo.cfg") uin = javaobj.loads(out).get(1, 0) except: logger.warning("default uin not found in systemInfo.cfg") else: candidates.append(uin) logger.info(f"found uin={uin} in systemInfo.cfg") candidates = list({x for x in candidates if x != 0}) logger.info(f"Possible uin: {candidates}") return candidates
raise logger.info(f"Decryption succeeded! Writing database to {output} ...") c.execute("SELECT sqlcipher_export('db');") c.execute("DETACH DATABASE db;") c.close() if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('task', choices=['uin', 'imei', 'decrypt']) parser.add_argument('--imei', help='overwrite imei') parser.add_argument('--uin', help='overwrite uin') parser.add_argument('--input', help='encrypted EnMicroMsg.db') args = parser.parse_args() subproc_succ("adb root") if args.task == 'uin': uin = get_uin() elif args.task == 'imei': imei = get_imei() elif args.task == 'decrypt': uins = [args.uin] if args.uin else get_uin() imeis = [args.imei] if args.imei else get_imei() output_file = args.input + ".decrypted" assert not os.path.isfile(output_file), f"Output {output_file} exists!" for uin in uins: uin = str(uin).encode('ascii') for imei in imeis: key = get_key(imei, uin) logger.info(f"Trying key {key} ...")