#!/usr/bin/env python
#~/Library/Application Support/MobileSync/Backup
import sys
import os
import hashlib
import shutil
mbdx = {}
dict = {}
def getint(data, offset, intsize):
"""Retrieve an integer (big-endian) and new offset from the current offset"""
value = 0
while intsize > 0:
value = (value<<8) + ord(data[offset])
offset = offset + 1
intsize = intsize - 1
return value, offset
def getstring(data, offset):
"""Retrieve a string and new offset from the current offset into the data"""
if data[offset] == chr(0xFF) and data[offset+1] == chr(0xFF):
return '', offset+2 # Blank string
length, offset = getint(data, offset, 2) # 2-byte length
value = data[offset:offset+length]
return value, (offset + length)
def process_mbdb_file(filename):
mbdb = {} # Map offset of info in this file => file info
data = open(filename).read()
if data[0:4] != "mbdb": raise Exception("This does not look like an MBDB file")
offset = 4
offset = offset + 2 # value x05 x00, not sure what this is
while offset < len(data):
fileinfo = {}
fileinfo['start_offset'] = offset
fileinfo['domain'], offset = getstring(data, offset)
fileinfo['filename'], offset = getstring(data, offset)
fileinfo['linktarget'], offset = getstring(data, offset)
fileinfo['datahash'], offset = getstring(data, offset)
fileinfo['unknown1'], offset = getstring(data, offset)
fileinfo['mode'], offset = getint(data, offset, 2)
fileinfo['unknown2'], offset = getint(data, offset, 4)
fileinfo['unknown3'], offset = getint(data, offset, 4)
fileinfo['userid'], offset = getint(data, offset, 4)
fileinfo['groupid'], offset = getint(data, offset, 4)
fileinfo['mtime'], offset = getint(data, offset, 4)
fileinfo['atime'], offset = getint(data, offset, 4)
fileinfo['ctime'], offset = getint(data, offset, 4)
fileinfo['filelen'], offset = getint(data, offset, 8)
fileinfo['flag'], offset = getint(data, offset, 1)
fileinfo['numprops'], offset = getint(data, offset, 1)
fileinfo['properties'] = {}
for ii in range(fileinfo['numprops']):
propname, offset = getstring(data, offset)
propval, offset = getstring(data, offset)
fileinfo['properties'][propname] = propval
mbdb[fileinfo['start_offset']] = fileinfo
fullpath = fileinfo['domain'] + '-' + fileinfo['filename']
id = hashlib.sha1(fullpath)
mbdx[fileinfo['start_offset']] = id.hexdigest()
return mbdb
def modestr(val):
def mode(val):
if (val & 0x4): r = 'r'
else: r = '-'
if (val & 0x2): w = 'w'
else: w = '-'
if (val & 0x1): x = 'x'
else: x = '-'
return r+w+x
return mode(val>>6) + mode((val>>3)) + mode(val)
def fileinfo_str(f, verbose=False):
# if not verbose: return "(%s)%s::%s" % (f['fileID'], f['domain'], f['filename'])
dict[f['fileID']] = f['filename']
if not verbose: return "%s => %s (%s)" % (f['fileID'], f['filename'], f['domain'])
if (f['mode'] & 0xE000) == 0xA000: type = 'l' # symlink
elif (f['mode'] & 0xE000) == 0x8000: type = '-' # file
elif (f['mode'] & 0xE000) == 0x4000: type = 'd' # dir
else:
print >> sys.stderr, "Unknown file type %04x for %s" % (f['mode'], fileinfo_str(f, False))
type = '?' # unknown
info = ("%s%s %08x %08x %7d %10d %10d %10d (%s)%s::%s" %
(type, modestr(f['mode']&0x0FFF) , f['userid'], f['groupid'], f['filelen'],
f['mtime'], f['atime'], f['ctime'], f['fileID'], f['domain'], f['filename']))
if type == 'l': info = info + ' -> ' + f['linktarget'] # symlink destination
for name, value in f['properties'].items(): # extra properties
info = info + ' ' + name + '=' + repr(value)
return info
verbose = True
if __name__ == '__main__':
if len(sys.argv)!=3:
print "\nUsage: Python iOS-Corrupted-Backup-Reader.py [Full path to backup directory] [Full path to output directory]\n"
print "Example: Python iOS-Corrupted-Backup-Reader.py c:\backup c:\output"
sys.exit(0)
backuppath=sys.argv[1]
outputpath=sys.argv[2]
if os.path.exists(backuppath)==0:
print "Backup directory not found."
sys.exit(0)
if os.path.exists(outputpath)==0:
print "Output directory not found. Create the directory before running the script."
sys.exit(0)
if backuppath[:-1]!='/':
backuppath=backuppath+'/'
if outputpath[:-1]!='/':
outputpath=outputpath+'/'
mbdb = process_mbdb_file(backuppath+"Manifest.mbdb")
for offset, fileinfo in mbdb.items():
if offset in mbdx:
fileinfo['fileID'] = mbdx[offset]
else:
fileinfo['fileID'] = ""
print >> sys.stderr, "No fileID found for %s" % fileinfo_str(fileinfo)
print fileinfo_str(fileinfo)
folder=os.listdir(backuppath)
for fname in folder:
ffullname=backuppath+fname
if fname in dict:
tmp=dict[fname]
odir,oname=tmp[:tmp.rfind('/')],tmp[tmp.rfind('/')+1:]
if os.path.exists(outputpath+odir)==0:
os.makedirs(outputpath+odir)
print ">>makedirs "+outputpath+odir
try:
shutil.copy(ffullname,outputpath+odir+'/'+oname)
print ">>copy from "+ffullname+" to "+outputpath+odir+'/'+oname
except:
pass
folder=os.listdir(backuppath)
for fname in folder:
ffullname=backuppath+fname
print "handler "+ffullname
f=open(ffullname,'rb')
ftype=f.read(15)
f.close()
try:
if os.path.exists(outputpath+'other-data')==0:
os.makedirs(outputpath+'other-data')
if ftype.find('bplist')!=-1 or ftype.find(')!=-1:
mtype='.plist'
if ftype.find('SQLite')!=-1:
mtype='.sqlitedb'
if ftype.find('JFIF')!=-1 or ftype.find('Exif')!=-1:
mtype='.jpeg'
if ftype.find('PNG')!=-1:
mtype='.png'
if ftype.find('cook')!=-1:
mtype='.binarycookies'
if ftype.find('ftypqt')!=-1:
mtype='.mov'
if ftype.find('ID3')!=-1:
mtype='.mp3'
file_path=outputpath+'other-data'+'/'+fname+mtype
if(os.path.exists(file_path)==False):
shutil.copy(ffullname,file_path)
print ">>copy from "+ffullname+" to "+file_path
else:
outfilename=outputpath+'other-data'+'/'+fname+str(randrange(0,1000))+mtype
shutil.copy(ffullname,outfilename)
print ">>copy from "+ffullname+" to "+outfilename
except:
pass
print "Files successfully moved to"+outputpath
手机备份的文件所在路径:
~/Library/Application Support/MobileSync/Backup
执行样例:
Python ReadiPhoneBackupData.py/Library/Application Support/MobileSync/Backup/xxx /Users/xxx/Desktop/xxx