-
-
Save ceramicwhite/11da2e0b2b8b11341eb67d19d7a84ace to your computer and use it in GitHub Desktop.
extract & parse the BackupKeyBag from an iTunes Backup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| # | |
| # extracts and parse BackupKeyBag | |
| # | |
| # 2017.02.04 darell tan | |
| # | |
| # Update 2024.06.11 Jasper | |
| import plistlib | |
| import struct | |
| import sys | |
| from binascii import hexlify | |
| from collections import OrderedDict | |
| from io import BytesIO | |
| def getKeybagFile(manifest_file): | |
| """ | |
| Retrieves the BackupKeyBag embedded within the Manifest.plist. | |
| """ | |
| with open(manifest_file, 'rb') as f: | |
| data = f.read() | |
| if data.startswith(b'bplist'): | |
| pl = plistlib.loads(data) | |
| else: | |
| pl = plistlib.loads(data) | |
| assert 'Version' in pl | |
| return BytesIO(pl['BackupKeyBag']) | |
| class Keybag: | |
| def __init__(self, f): | |
| self.hdr = OrderedDict() | |
| self.keys = [] | |
| self.f = f if hasattr(f, 'read') else open(f, 'rb') | |
| self._parse() | |
| def _parse(self): | |
| keys = [] | |
| currKey = OrderedDict() | |
| while True: | |
| hdr = self.f.read(8) | |
| if hdr == b'': | |
| break | |
| typ, sz = struct.unpack('>4sI', hdr) | |
| data = self.f.read(sz) | |
| if sz == 4: | |
| data, = struct.unpack('>I', data) | |
| # UUID usually first item of each entry | |
| if typ == b'UUID': | |
| if 'UUID' in currKey: | |
| keys.append(currKey) | |
| else: | |
| self.hdr = currKey | |
| currKey = OrderedDict() | |
| currKey[typ.decode('utf-8')] = data | |
| if currKey: | |
| keys.append(currKey) | |
| self.keys = keys | |
| def dump(self): | |
| for k, v in self.hdr.items(): | |
| print(k, v) | |
| print('-' * 10) | |
| def decode(typ, val): | |
| if typ == 'UUID': | |
| v = hexlify(val).decode('utf-8') | |
| return '%s...%s' % (v[:6], v[-4:]) | |
| elif not isinstance(val, int): | |
| return hexlify(val).decode('utf-8') | |
| else: | |
| return repr(val) | |
| for key in self.keys: | |
| print(', '.join('%s: %s' % (k, decode(k, v)) for k, v in key.items())) | |
| def __repr__(self): | |
| return repr(self.keys) | |
| def main(): | |
| stream = getKeybagFile(sys.argv[1]) | |
| k = Keybag(stream) | |
| k.dump() | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment