#!/usr/bin/env python # This software is Copyright (c) 2018, Dhiru Kholia and it # is hereby released to the general public under the following terms: # # Redistribution and use in source and binary forms, with or without # modification, are permitted. # # All credit goes to "Android backup extractor" project by Nikolay Elenkov for # making this work possible. # # Tested with Android 4.4.4, Android 6.0 and Android 8.0 running on Genymotion. # # Android backups can be created with the following command, # # adb backup -f freeotp-backup.ab -apk org.fedorahosted.freeotp # valid for freeotp app import os import sys PY3 = sys.version_info[0] == 3 if not PY3: reload(sys) sys.setdefaultencoding('utf8') # https://github.com/nelenkov/android-backup-extractor BACKUP_MANIFEST_VERSION = 1 BACKUP_FILE_HEADER_MAGIC = b"ANDROID BACKUP\n" BACKUP_FILE_V1 = 1 BACKUP_FILE_V2 = 2 BACKUP_FILE_V3 = 3 BACKUP_FILE_V4 = 4 BACKUP_FILE_V5 = 5 ENCRYPTION_MECHANISM = b"AES/CBC/PKCS5Padding" PBKDF2_HASH_ROUNDS = 10000 PBKDF2_KEY_SIZE = 256 # bits MASTER_KEY_SIZE = 256 # bits PBKDF2_SALT_SIZE = 512 # bits ENCRYPTION_ALGORITHM_NAME = b"AES-256" def process_file(filename): """ Parser for Android Backup .ab files """ with open(filename, "rb") as f: magic = f.readline() # Untested hack for "Xiaomi-MIUI backup" while magic != BACKUP_FILE_HEADER_MAGIC and magic: magic = f.readline() if magic != BACKUP_FILE_HEADER_MAGIC: sys.stderr.write("[!] Magic missing from file, is this an Android Backup?\n") return try: version = int(f.readline()) except ValueError: return if version < BACKUP_FILE_V1 or version > BACKUP_FILE_V5: sys.stderr.write("[!] Unsupported backup version, is this an Android Backup?\n") return try: is_compressed = int(f.readline()) except ValueError: sys.stderr.write("[!] Error reading compression flag, is this an Android Backup?\n") return encryption_algorithm = f.readline().strip() if encryption_algorithm != ENCRYPTION_ALGORITHM_NAME: sys.stderr.write( "[!] Unsupported encryption algorithm (%s) found, is this an Android Backup?\n" % encryption_algorithm) return user_salt = f.readline().strip().lower() ck_salt = f.readline().strip().lower() try: rounds = int(f.readline()) except ValueError: sys.stderr.write("[!] Error reading rounds value, is this an Android Backup?\n") return user_iv = f.readline().strip().lower() masterkey_blob = f.readline().strip().lower() if PY3: user_salt = str(user_salt, 'ascii') ck_salt = str(ck_salt, 'ascii') user_iv = str(user_iv, 'ascii') masterkey_blob = str(masterkey_blob, 'ascii') cipher = 0 # AES-256 sys.stdout.write("%s:$ab$%d*%d*%d*%s*%s*%s*%s\n" % (os.path.basename(filename), version, cipher, rounds, user_salt, ck_salt, user_iv, masterkey_blob)) if __name__ == "__main__": if len(sys.argv) < 2: sys.stderr.write("Usage: %s [Android Backup .ab file(s)]\n" % sys.argv[0]) sys.exit(-1) for i in range(1, len(sys.argv)): process_file(sys.argv[i])