Skip to content

Instantly share code, notes, and snippets.

@geekman
Created March 3, 2017 17:58
Show Gist options
  • Save geekman/0aaa9e4659977a98fc9f36d6887fef37 to your computer and use it in GitHub Desktop.
Save geekman/0aaa9e4659977a98fc9f36d6887fef37 to your computer and use it in GitHub Desktop.

Revisions

  1. geekman created this gist Mar 3, 2017.
    99 changes: 99 additions & 0 deletions parse_keybag.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    #!/usr/bin/env python
    #
    # extracts and parse BackupKeyBag
    #
    # 2017.02.04 darell tan
    #

    from plist import *
    import struct
    import sys
    from binascii import hexlify
    from collections import OrderedDict

    try:
    from cStringIO import StringIO
    except:
    from StringIO import StringIO


    def getKeybagFile(manifest_file):
    """
    Retrieves the BackupKeyBag embedded within the Manifest.plist.
    """
    with open(manifest_file, 'rb') as f:
    data = f.read()
    pl = Structure.from_bin(data) if data.startswith('bplist') \
    else Structure.from_xml(data)

    assert 'Version' in pl

    return StringIO(pl['BackupKeyBag'].get_value())


    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(4+4)
    if hdr == '':
    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 == 'UUID':
    if 'UUID' in currKey:
    keys.append(currKey)
    else:
    self.hdr = currKey
    currKey = OrderedDict()

    currKey[typ] = data

    if currKey:
    keys.append(currKey)

    self.keys = keys

    def dump(self):
    for k, v in self.hdr.iteritems():
    print k, v

    print '-' * 10

    def decode(typ, val):
    if typ == 'UUID':
    v = hexlify(val)
    return '%s...%s' % (v[:6], v[-4:])
    elif not isinstance(val, (int, long)):
    return hexlify(val)
    else:
    return repr(val)

    for key in self.keys:
    print ', '.join('%s: %s' % (k, decode(k, v)) \
    for k, v in key.iteritems())

    def __repr__(self):
    return repr(self.keys)

    def main():
    stream = getKeybagFile(sys.argv[1])

    k = Keybag(stream)
    k.dump()

    if __name__ == '__main__':
    main()