def main(): app = QtGui.QApplication(sys.argv) init_path = "{0:s}/Apple Computer/MobileSync/Backup".format( os.getenv('APPDATA')) dirname = QtGui.QFileDialog.getExistingDirectory( None, "Select iTunes backup directory", init_path) kb = getBackupKeyBag(dirname, 'pouet') #XXX: hardcoded password for demo if not kb: warn("Backup keybag unlock fail : wrong passcode?") return db = MBDB(dirname) keychain_filename, keychain_record = db.get_file_by_name( 'keychain-backup.plist') f = file(dirname + '/' + keychain_filename, 'rb') keychain_data = f.read() f.close() if keychain_record.encryption_key is not None: # file is encrypted if kb.classKeys.has_key(keychain_record.protection_class): kek = kb.classKeys[keychain_record.protection_class]['KEY'] k = AESUnwrap(kek, keychain_record.encryption_key[4:]) if k is not None: c = AES.new(k, AES.MODE_CBC) keychain_data = c.decrypt(keychain_data) padding = keychain_data[keychain_record.size:] if len(padding) > AES.block_size or padding != chr( len(padding)) * len(padding): warn("Incorrect padding for file %s" % keychain_record.path) keychain_data = keychain_data[:keychain_record.size] else: warn("Cannot unwrap key") else: warn("Cannot load encryption key for file %s" % f) f = file('keychain.tmp', 'wb') f.write(keychain_data) f.close() # kc = KeychainBackup4('keychain-backup.plist', kb) kc = KeychainBackup4('keychain.tmp', kb) pwds = kc.get_passwords() inet_pwds = kc.get_inet_passwords() print inet_pwds qb = KeychainWindow() qb.setGenericPasswords(pwds) qb.setInternetPasswords(inet_pwds) qb.show() sys.exit(app.exec_()) pass
def main(): app = QtGui.QApplication(sys.argv) init_path = "{0:s}/Apple Computer/MobileSync/Backup".format( os.getenv('APPDATA')) dirname = QtGui.QFileDialog.getExistingDirectory( None, "Select iTunes backup directory", init_path) kb = getBackupKeyBag(dirname, 'pouet') #XXX: hardcoded password for demo if not kb: warn("Backup keybag unlock fail : wrong passcode?") return db = MBDB(dirname) db.keybag = kb filename, record = db.get_file_by_name("keychain-backup.plist") keychain_data = db.read_file(filename, record) f = file('keychain.tmp', 'wb') f.write(keychain_data) f.close() kc = Keychain4('keychain.tmp', kb) pwds = kc.get_passwords() inet_pwds = kc.get_inet_passwords() qb = KeychainWindow() qb.setGenericPasswords(pwds) qb.setInternetPasswords(inet_pwds) qb.show() sys.exit(app.exec_()) pass
def main(): app = QtGui.QApplication(sys.argv) init_path = "{0:s}/Apple Computer/MobileSync/Backup".format(os.getenv('APPDATA')) dirname = QtGui.QFileDialog.getExistingDirectory(None, "Select iTunes backup directory", init_path) kb = getBackupKeyBag(dirname, 'pouet') #XXX: hardcoded password for demo if not kb: warn("Backup keybag unlock fail : wrong passcode?") return db = MBDB(dirname) db.keybag = kb filename, record = db.get_file_by_name("keychain-backup.plist") keychain_data = db.read_file(filename, record) f = file('keychain.tmp', 'wb') f.write(keychain_data) f.close() kc = Keychain4('keychain.tmp', kb) pwds = kc.get_passwords() inet_pwds = kc.get_inet_passwords() qb = KeychainWindow() qb.setGenericPasswords(pwds) qb.setInternetPasswords(inet_pwds) qb.show() sys.exit(app.exec_()) pass
def extract_backup(backup_path, output_path, password=""): if not os.path.exists(backup_path + "/Manifest.plist"): print "Manifest.plist not found" return manifest = readPlist(backup_path + "/Manifest.plist") info = readPlist( backup_path + "/Info.plist") for i in showinfo: print i + " : " + unicode(info.get(i, "missing")) if manifest["IsEncrypted"] and password == "": password = getpass('Enter backup password : ') if not manifest.has_key("BackupKeyBag"): print "oops this is not encrypted" exit(1) else: mbdb = MBDB(backup_path) kb = Keybag.createWithBackupManifest(manifest, password) if not kb: return manifest["password"] = password mbdb.keybag = kb extract_sms_db(mbdb, output_path)
def main(): app = QtGui.QApplication(sys.argv) init_path = "{0:s}/Apple Computer/MobileSync/Backup".format(os.getenv("APPDATA")) dirname = QtGui.QFileDialog.getExistingDirectory(None, "Select iTunes backup directory", init_path) kb = getBackupKeyBag(dirname, "pouet") # XXX: hardcoded password for demo if not kb: warn("Backup keybag unlock fail : wrong passcode?") return db = MBDB(dirname) keychain_filename, keychain_record = db.get_file_by_name("keychain-backup.plist") f = file(dirname + "/" + keychain_filename, "rb") keychain_data = f.read() f.close() if keychain_record.encryption_key is not None: # file is encrypted if kb.classKeys.has_key(keychain_record.protection_class): kek = kb.classKeys[keychain_record.protection_class]["KEY"] k = AESUnwrap(kek, keychain_record.encryption_key[4:]) if k is not None: c = AES.new(k, AES.MODE_CBC) keychain_data = c.decrypt(keychain_data) padding = keychain_data[keychain_record.size :] if len(padding) > AES.block_size or padding != chr(len(padding)) * len(padding): warn("Incorrect padding for file %s" % keychain_record.path) keychain_data = keychain_data[: keychain_record.size] else: warn("Cannot unwrap key") else: warn("Cannot load encryption key for file %s" % f) f = file("keychain.tmp", "wb") f.write(keychain_data) f.close() # kc = KeychainBackup4('keychain-backup.plist', kb) kc = KeychainBackup4("keychain.tmp", kb) pwds = kc.get_passwords() inet_pwds = kc.get_inet_passwords() print inet_pwds qb = KeychainWindow() qb.setGenericPasswords(pwds) qb.setInternetPasswords(inet_pwds) qb.show() sys.exit(app.exec_()) pass
def extract_backup(backup_path, output_path, password=""): if not os.path.exists(backup_path + "/Manifest.plist"): print "Manifest.plist not found" return manifest = readPlist(backup_path + "/Manifest.plist") info = readPlist( backup_path + "/Info.plist") for i in showinfo: print i + " : " + unicode(info.get(i, "missing")) #jsc # print "Extract backup to %s ? (y/n)" % output_path # if raw_input() == "n": # return print "Backup is %sencrypted" % (int(not manifest["IsEncrypted"]) * "not ") #jsc # if manifest["IsEncrypted"] and password == "": # print "Enter backup password : "******"BackupKeyBag"): print "No BackupKeyBag in manifest, assuming iOS 3.x backup" decrypt_backup3(backup_path, output_path, password) else: mbdb = MBDB(backup_path) kb = Keybag.createWithBackupManifest(manifest, password) if not kb: return #jsc password = kb.bfPassword manifest["password"] = password makedirs(output_path) plistlib.writePlist(manifest, output_path + "/Manifest.plist") mbdb.keybag = kb mbdb.extract_backup(output_path) #jsc print "Bruteforce successful, backup password : %s" % password print "You can decrypt the keychain using the following command : " print "python keychain_tool.py -d \"%s\" \"%s\"" % (output_path + "/KeychainDomain/keychain-backup.plist", output_path + "/Manifest.plist")
def extract_backup(backup_path, output_path, password=""): if not os.path.exists(backup_path + "/Manifest.plist"): print "Manifest.plist not found" return manifest = readPlist(backup_path + "/Manifest.plist") info = readPlist(backup_path + "/Info.plist") for i in showinfo: print i + " : " + unicode(info.get(i, "missing")) print "Extract backup to %s ? (y/n)" % output_path if raw_input() == "n": return print "Backup is %sencrypted" % (int(not manifest["IsEncrypted"]) * "not ") if manifest["IsEncrypted"] and password == "": print "Enter backup password : "******"BackupKeyBag"): print "No BackupKeyBag in manifest, assuming iOS 3.x backup" decrypt_backup3(backup_path, output_path, password) else: mbdb = MBDB(backup_path) kb = Keybag.createWithBackupManifest(manifest, password) if not kb: return manifest["password"] = password makedirs(output_path) plistlib.writePlist(manifest, output_path + "/Manifest.plist") mbdb.keybag = kb mbdb.extract_backup(output_path) print "You can decrypt the keychain using the following command : " print "python keychain_tool.py -d %s %s" % ( output_path + "/keychain-backup.plist", output_path + "/Manifest.plist")
def extract_backup(backup_path, output_path, password="", app=None): ''' if not os.path.exists(backup_path + "/Manifest.plist"): print "Manifest.plist not found" return manifest = readPlist(backup_path + "/Manifest.plist") ''' manifest = readManifest(backup_path) if manifest is None: print("Manifest.plist not found") return # dict = manifest['Applications'] # for apps in dict.iteritems(): # print "App Name: " + apps[0] # for key, value in apps[1].iteritems(): # print key + " : " + value # print "####################################" showinfo = readInfo(backup_path) if showinfo is None: print("Info.plist not found") return for i in showinfo: value = unicode(showinfo.get(i, "missing")) if i == "Product Type": value = value + " (" + getIDeviceProductName(value) + ")" print(i + " : " + value + "...") # print "Extract backup to %s ? (y/n)" % output_path # if raw_input() == "n": # return print("Backup is %sencrypted" % (int(not manifest["IsEncrypted"]) * "not ")) if manifest["IsEncrypted"] and password == "": print ("Enter backup password : "******"BackupKeyBag"): print ("No BackupKeyBag in manifest, assuming iOS 3.x backup") decrypt_backup3(backup_path, output_path, password) else: mbdb = MBDB(backup_path) kb = Keybag.createWithBackupManifest(manifest, password) if not kb: return manifest["password"] = password makedirs(output_path) plistlib.writePlist(manifest, output_path + "/Manifest.plist") mbdb.keybag = kb database, cursor = iOSBackupDB() store2db(cursor, mbdb) database.commit() print_domains(cursor) cursor.execute("Select * from indice where mbapp_name= ?", (app,)) records = cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) mbdb.extract_backup_from_db(dbrecord, output_path)
def extract_backup(backup_path, output_path, password=""): if not os.path.exists(backup_path + "/Manifest.plist"): print "Manifest.plist not found" return manifest = readPlist(backup_path + "/Manifest.plist") info = readPlist(backup_path + "/Info.plist") for i in showinfo: print i + " : " + unicode(info.get(i, "missing")) print "Extract backup to %s ? (y/n)" % output_path if raw_input() == "n": return print "Backup is %sencrypted" % (int(not manifest["IsEncrypted"]) * "not ") if manifest["IsEncrypted"] and password == "": print "Enter backup password : "******"BackupKeyBag"): print "No BackupKeyBag in manifest, assuming iOS 3.x backup" decrypt_backup3(backup_path, output_path, password) elif os.path.exists(backup_path + "/Manifest.mbdb"): mbdb = MBDB(backup_path) kb = Keybag.createWithBackupManifest(manifest, password) if not kb: return manifest["password"] = password makedirs(output_path) plistlib.writePlist(manifest, output_path + "/Manifest.plist") mbdb.keybag = kb mbdb.extract_backup(output_path) print "You can decrypt the keychain using the following command : " print "python keychain_tool.py -d \"%s\" \"%s\"" % ( output_path + "/KeychainDomain/keychain-backup.plist", output_path + "/Manifest.plist") elif os.path.exists(backup_path + "/Manifest.db"): if 'ManifestKey' in manifest: kb = Keybag.createWithBackupManifest(manifest, password, ios102=True) else: kb = Keybag.createWithBackupManifest(manifest, password) if not kb: return manifest["password"] = password makedirs(output_path) plistlib.writePlist(manifest, output_path + "/Manifest.plist") manifest_key = None if 'ManifestKey' in manifest: clas = struct.unpack('<L', manifest['ManifestKey'].data[:4])[0] wkey = manifest['ManifestKey'].data[4:] manifest_key = kb.unwrapKeyForClass(clas, wkey) manifset_db = ManifestDB(backup_path, key=manifest_key) manifset_db.keybag = kb manifset_db.extract_backup(output_path) print "You can decrypt the keychain using the following command: " print "python keychain_tool.py -d \"%s\" \"%s\"" % ( output_path + "/KeychainDomain/keychain-backup.plist", output_path + "/Manifest.plist") else: print "No Manifest database found, Is it a complete backup?"
class iOSBE(QtGui.QMainWindow): def __init__(self): super(iOSBE, self).__init__(None) self.backuppath = None self.database = None self.cursor = None self.manifest = None self.infoplist = None self.iOSVersion = 0 self.passwd = None self.work_dir = None self.extractpath = None self.is_active = False self.mbdb = None self.mru_list = list() self.threemaUI = None self.contactsUI = None self.sqlbrowserUI = None self.smsUI = None self.callhistoryUI = None self.whatsappUI = None if "linux" in sys.platform: self.mousewait = Qt.WaitCursor else: self.mousewait = QCursor(Qt.WaitCursor) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.ui.treeViewDomains.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.treeViewDomains.customContextMenuRequested.connect(self.ctxMenu) self.ui.treeViewDomains.setHeaderLabel("") self.ui.treeViewDomains.setColumnWidth(0, 200) self.ui.treeViewDomains.setColumnWidth(2, 16) self.ui.treeViewDomains.setColumnHidden(1, True) self.ui.treeViewDomains.setColumnHidden(3, True) self.ui.treeViewDomains.setColumnHidden(4, True) self.ui.treeViewDomains.setColumnHidden(5, True) # action handlers QtCore.QObject.connect(self.ui.action_OpenBackup, QtCore.SIGNAL("triggered(bool)"), self.openBackupGUI) QtCore.QObject.connect(self.ui.action_About, QtCore.SIGNAL("triggered(bool)"), self.displayAbout) QtCore.QObject.connect(self.ui.action_CloseBackup, QtCore.SIGNAL("triggered(bool)"), self.closeBackup) QtCore.QObject.connect(self.ui.action_ExtractApp, QtCore.SIGNAL("triggered(bool)"), self.extractApp) QtCore.QObject.connect(self.ui.action_ExtractAll, QtCore.SIGNAL("triggered(bool)"), self.extractAll) QtCore.QObject.connect(self.ui.action_Contacts, QtCore.SIGNAL("triggered(bool)"), self.showContacts) QtCore.QObject.connect(self.ui.action_CallHistory, QtCore.SIGNAL("triggered(bool)"), self.showCallHistory) QtCore.QObject.connect(self.ui.action_Messages, QtCore.SIGNAL("triggered(bool)"), self.showMessages) QtCore.QObject.connect(self.ui.action_Threema, QtCore.SIGNAL("triggered(bool)"), self.showThreema) QtCore.QObject.connect(self.ui.action_WhatsApp, QtCore.SIGNAL("triggered(bool)"), self.showWhatsapp) self.work_dir = makeTmpDir() if sys.platform != "darwin": self.ui.separatorMRUList.setSeparator(True) self.mruLoadList() self.mruUpdateFileMenu() def closeEvent(self, event): #clean up and remove temporary files... rmTmpDir(self.work_dir) def ctxMenu(self, pos): # managing "standard" files selectedItem = self.ui.treeViewDomains.currentItem() if (selectedItem): pass else: return file = selectedItem.text(0).split(".") ftype = "" if file.__len__() != 2: return fext = file[1].encode('ascii','ignore').upper() for ext in PICEXTENSIONLIST: if fext == ext: ftype = "image" break if ftype == "": for ext in SQLITEEXTENSIONLIST: if fext == ext: ftype = "sqlite" break showMenu = False menu = QtGui.QMenu() # if image if (ftype == "image"): action1 = QtGui.QAction("Open with Image Viewer", self) action1.triggered.connect(self.openSelectedImage) menu.addAction(action1) showMenu = True # if sqlite if (ftype == "sqlite"): action1 = QtGui.QAction("Open with SQLite Browser", self) action1.triggered.connect(self.openSelectedSqlite) menu.addAction(action1) showMenu = True if (showMenu): menu.exec_(self.ui.treeViewDomains.mapToGlobal(pos)) def isSubWindowOpen(self, win): # check if plugin already open found = False def isWindowOpen(self, win): #check if pid file of win is existing pass def showContacts(self): if self.isSubWindowOpen("contactsGUI") == True: return mbdomain_type = "HomeDomain" mbapp_name = "Library/AddressBook" if self.extractpath == None: dir = self.work_dir else: dir = self.extractpath self.cursor.execute("Select * from indice where mbdomain_type=? and mbfile_path= ?", (mbdomain_type,mbapp_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) abook = dir + "/HomeDomain/Library/AddressBook/AddressBook.sqlitedb" abimg = dir + "/HomeDomain/Library/AddressBook/AddressBookImages.sqlitedb" self.contactsUI = contactsGUI(abook, abimg, self.work_dir) self.contactsUI.show() def showMessages(self): if self.isSubWindowOpen("smsGUI") == True: return if self.extractpath == None: dir = self.work_dir else: dir = self.extractpath mbdomain_type = "HomeDomain" mbapp_name = "Library/AddressBook" self.cursor.execute("Select * from indice where mbdomain_type=? and mbfile_path= ?", (mbdomain_type,mbapp_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) mbdomain_type = "HomeDomain" mbapp_name = "Library/SMS" self.cursor.execute("Select * from indice where mbdomain_type=? and mbfile_path= ?", (mbdomain_type,mbapp_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) abook = dir + "/HomeDomain/Library/AddressBook/AddressBook.sqlitedb" abimg = dir + "/HomeDomain/Library/AddressBook/AddressBookImages.sqlitedb" sms = dir + "/HomeDomain/Library/SMS/sms.db" self.smsUI = smsGUI(sms, abook, abimg) self.smsUI.show() def showCallHistory(self): if self.extractpath == None: dir = self.work_dir else: dir = self.extractpath if self.iOSVersion == IPHONE_UNSUPPORTED: QtGui.QMessageBox.information(self, "Information", "Unsupported iOS version...") return if self.iOSVersion == IPHONE_VERSION6 or self.iOSVersion == IPHONE_VERSION7: mbdomain_type = "WirelessDomain" mbfile_name = "call_history.db" elif self.iOSVersion == IPHONE_VERSION8: mbdomain_type = "HomeDomain" mbfile_name = "CallHistory.storedata" self.cursor.execute("Select * from indice where mbdomain_type=? and mbfile_name= ?", (mbdomain_type,mbfile_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) callhistorydb = dir + "/" + dbrecord.mbdomain_type + "/" + str(dbrecord.mbfile_path) + "/" + dbrecord.mbfile_name mbdomain_type = "HomeDomain" mbapp_name = "Library/AddressBook" self.cursor.execute("Select * from indice where mbdomain_type=? and mbfile_path= ?", (mbdomain_type,mbapp_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) abook = dir + "/HomeDomain/Library/AddressBook/AddressBook.sqlitedb" abimg = dir + "/HomeDomain/Library/AddressBook/AddressBookImages.sqlitedb" self.callhistoryUI = callhistoryGUI(callhistorydb, abook) self.callhistoryUI.show() return def showThreema(self): if self.isSubWindowOpen("threemaGUI") == True: return mbdomain_type = "AppDomain" mbapp_name = "ch.threema.iapp" if self.extractpath == None: dir = self.work_dir else: dir = self.extractpath self.cursor.execute("Select * from indice where mbdomain_type=? and mbapp_name= ?", (mbdomain_type,mbapp_name)) records = self.cursor.fetchall() if len(records) == 0: QtGui.QMessageBox.information(self, "Information", "Threema not found...") return for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) threemaDB = dir + "/" + mbdomain_type + "/" + mbapp_name + "/Documents/ThreemaData.sqlite" self.threemaUI = threemaGUI(threemaDB, dir) self.threemaUI.show() def showWhatsapp(self): if self.iOSVersion == IPHONE_UNSUPPORTED: QtGui.QMessageBox.information(self, "Information", "Unsupported iOS version...") return if self.extractpath == None: dir = self.work_dir else: dir = self.extractpath self.cursor.execute("select * from indice where mbapp_name Like '%Whatsapp%' order by domain") records = self.cursor.fetchall() if len(records) == 0: QtGui.QMessageBox.information(self, "Information", "Whatsapp not found...") return for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) path2appdomain = "AppDomain/net.whatsapp.WhatsApp" if self.iOSVersion == IPHONE_VERSION8: path2groupdomain = "AppDomainGroup/group.net.whatsapp.WhatsApp.shared" else: path2groupdomain = None self.whatsappUI = whatsappGUI(path2appdomain, path2groupdomain, self.work_dir) self.whatsappUI.show() return def onTreeClick(self): selectedItem = self.ui.treeViewDomains.currentItem() file = selectedItem.text(0).split(".") if file.__len__() == 2: for ext in PICEXTENSIONLIST: fext = file[1].encode('ascii','ignore') if fext.upper() == ext: self.showPicture(selectedItem.text(4), selectedItem.text(0), ext) break def openSelectedSqlite(self): selectedItem = self.ui.treeViewDomains.currentItem() self.showSQLite(selectedItem.text(4), selectedItem.text(0)) def openSelectedImage(self): selectedItem = self.ui.treeViewDomains.currentItem() self.showPicture(selectedItem.text(4), selectedItem.text(0)) def showSQLite(self, mbd, mbf): mbdomain_type = mbd mbfile_name = mbf if self.extractpath == None: dir = self.work_dir else: dir = self.extractpath self.cursor.execute("Select * from indice where mbdomain_type=? and mbfile_name= ?", (mbdomain_type,mbfile_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, dir) sqlitedb = dir + "/" + dbrecord.mbdomain_type + "/" + str(dbrecord.mbfile_path) + "/" + dbrecord.mbfile_name self.sqlbrowserUI = sqlBrowserGUI(sqlitedb, dir, dbrecord.mbfile_name) self.sqlbrowserUI.show() def showPicture(self, mbd, mbf): mbdomain_type = mbd mbfile_name = mbf self.cursor.execute("Select * from indice where mbdomain_type = ? and mbfile_name like ?", (mbdomain_type,mbfile_name)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) image_data = self.mbdb.readBackupFile(dbrecord) qimg = QtGui.QImage.fromData(image_data) qimg = qimg.scaled(800,600).scaled(400,300, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.SmoothTransformation) pixmap = QtGui.QPixmap.fromImage(qimg) self.w = ImageViewer(pixmap, self.ui.treeViewDomains) self.w.setWindowTitle(mbf) self.w.show() def informationMessage(self, message): QtGui.QMessageBox.information(self, "Information", message) def passwordDialog(self): passwd = None ok = False passwd, ok = QtGui.QInputDialog.getText(self, 'Backup seems to be encrypted. Password required...', 'Password:'******'Password', 'Enter password:'******'t find Info.plist in directory %s. Not a valid backup directory?" % self.backuppath) self.ui.statusbar.showMessage("Stop...") return False else: # refresh gridLayoutInfo self.gridLayoutInfo_refresh(self.infoplist) if not self.manifest.has_key("BackupKeyBag"): self.informationMessage("Only iOSBackup >= Version 5 Supported") if self.manifest["IsEncrypted"]: self.passwd = self.passwordDialog() if self.passwd is None: self.informationMessage("Password not given! Will not be able to extract information...") progressBar = QtGui.QProgressBar() self.ui.statusbar.addWidget(progressBar) self.mbdb = MBDB(self.backuppath) if self.passwd is not None: kb = Keybag.createWithBackupManifest(self.manifest, self.passwd) if not kb: self.informationMessage( "Can not extract backup key.\nYou can only browse through the domains and apps...") # return False self.manifest["password"] = self.passwd self.mbdb.keybag = kb progressBar.setMaximum(self.mbdb.numoffiles) if TestMode is True: self.database, self.cursor = iOSBackupDB(TestDatabase) else: self.database, self.cursor = iOSBackupDB() store2db(self.cursor, self.mbdb) self.database.commit() self.ui.treeViewDomains.setHeaderLabel("Files/Domains/Apps") standardFiles = QtGui.QTreeWidgetItem(None) standardFiles.setText(0, "Standard files") self.ui.treeViewDomains.addTopLevelItem(standardFiles) for elementName in ['Manifest.plist', 'Info.plist', 'Status.plist']: newItem = QtGui.QTreeWidgetItem(standardFiles) newItem.setText(0, elementName) newItem.setText(1, "X") self.ui.treeViewDomains.addTopLevelItem(newItem) self.cursor.execute("SELECT DISTINCT(mbdomain_type) FROM indice") domain_types = self.cursor.fetchall() for domain_type_u in domain_types: domain_type = str(domain_type_u[0]) newDomainFamily = QtGui.QTreeWidgetItem(None) newDomainFamily.setText(0, domain_type) self.ui.treeViewDomains.addTopLevelItem(newDomainFamily) # show new domain family in main view QtGui.QApplication.processEvents() query = "SELECT DISTINCT(mbapp_name) FROM indice WHERE mbdomain_type = ? ORDER BY mbdomain_type" self.cursor.execute(query, (domain_type,)) domain_names = self.cursor.fetchall() for domain_name_u in domain_names: domain_name = str(domain_name_u[0]) if (len(domain_names) > 1): newDomain = QtGui.QTreeWidgetItem(newDomainFamily) newDomain.setText(0, domain_name) self.ui.treeViewDomains.addTopLevelItem(newDomain) rootNode = newDomain else: rootNode = newDomainFamily # query = "SELECT path, mbfile_path, mbfile_name, size, fileid, mbfile_type FROM indice WHERE mbdomain_type = ? AND mbapp_name = ? ORDER BY mbfile_path, mbfile_name" query = "SELECT mbfile_path, mbfile_name, size, id, mbfile_type FROM indice WHERE mbdomain_type = ? AND mbapp_name = ? ORDER BY mbfile_path, mbfile_name" self.cursor.execute(query, (domain_type, domain_name)) nodes = self.cursor.fetchall() pathToNode = {'': rootNode} for nodeData in nodes: path = str(nodeData[0]) # finding parent directory lookup = path missing = collections.deque() dirNode = None while dirNode is None: dirNode = pathToNode.get(lookup, None) if dirNode is None: lookup, sep, component = lookup.rpartition('/') missing.appendleft(component) # creating parent directory if neccesary for component in missing: newPath = QtGui.QTreeWidgetItem(dirNode) newPath.setText(0, component) newPath.setToolTip(0, component) self.ui.treeViewDomains.addTopLevelItem(newPath) dirNode = newPath #lookup = posixpath.join(lookup, component) lookup = path pathToNode[lookup] = newPath try: file_name = str(nodeData[1].encode("utf-8")) except: file_name = nodeData[1] if (nodeData[2]) < 1024: file_dim = str(nodeData[2]) + " b" else: file_dim = str(nodeData[2] / 1024) + " kb" file_id = int(nodeData[3]) file_type = str(nodeData[4]) if file_type == 'd': newFile = dirNode else: newFile = QtGui.QTreeWidgetItem(newPath) self.ui.treeViewDomains.addTopLevelItem(newFile) newFile.setText(0, file_name) newFile.setToolTip(0, file_name) newFile.setText(2, str(file_dim)) newFile.setText(1, file_type) newFile.setText(3, str(file_id)) newFile.setText(4, domain_type) newFile.setText(5, domain_name) rawFiles = QtGui.QTreeWidgetItem(None) rawFiles.setText(0, "Raw files") self.ui.treeViewDomains.addTopLevelItem(rawFiles) # query = "SELECT mbfile_path, mbfile_name, size, id, mbfile_type FROM indice ORDER BY mbfile_path, mbfile_name" query = "SELECT domain, path, size, id, mbfile_type FROM indice ORDER BY domain, path" self.cursor.execute(query) nodes = self.cursor.fetchall() for nodeData in nodes: domain_name = str(nodeData[0]).replace("-", "/", 1) + "/" + str(nodeData[1]) newFile = QtGui.QTreeWidgetItem(rawFiles) self.ui.treeViewDomains.addTopLevelItem(newFile) if (nodeData[2]) < 1024: file_dim = str(nodeData[2]) + " b" else: file_dim = str(nodeData[2] / 1024) + " kb" file_id = int(nodeData[3]) file_type = str(nodeData[4]) newFile.setText(0, domain_name) newFile.setToolTip(0, domain_name) newFile.setText(2, str(file_dim)) newFile.setText(1, file_type) newFile.setText(3, str(file_id)) self.ui.statusbar.removeWidget(progressBar) self.activateMenu(True) return True def closeBackup(self): self.ui.statusbar.showMessage("Close Backup %s..." %self.backuppath) self.activateMenu(False) self.gridLayoutInfo_refresh() self.gridLayoutManifest_refresh() self.ui.treeViewDomains.clear() self.backuppath = None self.database = None self.cursor = None self.manifest = None self.infoplist = None self.passwd = None self.extractpath = None self.ui.statusbar.showMessage("Done...") def extractApp(self): if self.is_active == False: return selectedItem = self.ui.treeViewDomains.currentItem() if self.backuppath is None: msg = "No iOS Backup open..." self.informationMessage(msg) return if (self.extractpath == None) or (len(self.extractpath) == 0): self.extractpath = self.getFilepathDialog(self.backuppath) if (self.extractpath == None) or (len(self.extractpath) == 0): return None if selectedItem.text(4) == "AppDomain": search = '%' + selectedItem.text(0) + '%' self.cursor.execute("Select * from indice where mbapp_name like ?", (search,)) else: search = '%' + selectedItem.text(0) + '%' self.cursor.execute("Select * from indice where mbdomain_type = ? and mbfile_path like ?", (selectedItem.text(4),search)) records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, self.extractpath) def extractAll(self): if self.is_active == False: return if self.backuppath is None: msg = "No iOS Backup open..." self.informationMessage(msg) return if (self.extractpath == None) or (len(self.extractpath) == 0): self.extractpath = self.getFilepathDialog(self.backuppath) if (self.extractpath == None) or (len(self.extractpath) == 0): return None # msg = "Will extract App %s to path %s" % (selectedItem.text(0), self.extractpath) # self.informationMessage(msg) self.cursor.execute("Select * from indice") records = self.cursor.fetchall() for record in records: dbrecord = MBFileRecordFromDB(record) self.mbdb.extract_backup_from_db(dbrecord, self.extractpath) def gridLayoutInfo_refresh(self, showinfo=None): mydict = {"Build Version": self.ui.lblBuildVersion, "Device Name": self.ui.lblDeviceName, "Display Name": self.ui.lblDisplayName, "GUID": self.ui.lblGUID, "ICCID": self.ui.lblICCID, "IMEI": self.ui.lblIMEI, "MEID": self.ui.lblMEID, "Phone Number": self.ui.lblPhoneNumber, "Product Name": self.ui.lblProductName, "Product Type": self.ui.lblProductType, "Product Version": self.ui.lblProductVersion, "Serial Number": self.ui.lblSerialNumber, "Target Identifier": self.ui.lblTargetIdentifier, "Target Type": self.ui.lblTargetType, "Unique Identifier": self.ui.lblUniqueIdentifier, "iTunes Version": self.ui.lbliTunesVersion } for i in mydict: if showinfo is not None: value = unicode(showinfo.get(i, "missing")) if i == 'Product Version': self.iOSVersion = self.getIOSVersion(value) else: value = '' try: mydict[i].setText(value) except: pass def getIOSVersion(self, version): try: return int(version.split('.')[0]) except: return 0 def gridLayoutManifest_refresh(self, showinfo=None): mydict = {"Date": self.ui.lblDate, "IsEncrypted": self.ui.lblIsEncrypted, "SystemDomainsVersion": self.ui.lblSystemDomainsVersion, "Version": self.ui.lblVersion, "WasPasscodeSet": self.ui.lblWasPasscodeSet, "BackupKeyBag": self.ui.lblHasBackupKeybag } for i in mydict: if showinfo is not None: value = unicode(showinfo.get(i, "missing")) if i == "BackupKeyBag": value = showinfo.has_key("BackupKeyBag") else: value = '' try: mydict[i].setText(value) except: pass def mruAddArchive(self, description, path): """ Update the list of Most Recently Used archives, with a newly opened archive. description = The "Display name" of the open archive (e.g. "MyPhone (iPhone3)") path = The filesystem path of the archive. The function updates the MRU list, the application settings file, and the "File" Menu. """ # Remove the path, if it already exists tmp = filter(lambda x: x[0] == path, self.mru_list) if len(tmp) > 0: self.mru_list.remove(tmp[0]) # Add the new archive, to the beginning of the list self.mru_list.insert(0, ( path, description )) self.mruSaveList() self.mruUpdateFileMenu() def mruSaveList(self): """ Saves the list of MRU files to the application settings file. """ qs = QSettings() qs.remove("mru") qs.beginWriteArray("mru") for i, m in enumerate(self.mru_list): (path, description) = m qs.setArrayIndex(i) qs.setValue("path", path) qs.setValue("description", description) qs.endArray() def mruLoadList(self): """ Loads the list of MRU files from the pplication settings file. """ self.mru_list = list() qs = QSettings() count = qs.beginReadArray("mru") for i in range(count): qs.setArrayIndex(i) path = qs.value("path") description = qs.value("description") if os.path.exists(path): self.mru_list.append((path, description)) qs.endArray() def mruUpdateFileMenu(self): items = self.ui.menuReopen.actions() found_separator = False for i, item in enumerate(items): if found_separator: self.ui.menuReopen.removeAction(item) if (not found_separator) and item == self.ui.separatorMRUList: found_separator = True # Re-create MRU list # (Menu item for each MRU item) self.ui.separatorMRUList.setVisible(len(self.mru_list) != 0) for i, m in enumerate(self.mru_list): (path, description) = m text = "%d %s" % (i + 1, description) if i < 9: text = '&' + text action = self.ui.menuReopen.addAction(text) action.triggered.connect(lambda p=path: self.openBackup(path))
def openBackup(self, path=None): if path is not None: self.backuppath = path self.manifest = readManifest(self.backuppath) if self.manifest is None: self.informationMessage("%s seems not to be a valid backup directory" % self.backuppath) self.ui.statusbar.showMessage("Stop...") return False else: # refresh gridLayoutManifest self.gridLayoutManifest_refresh(self.manifest) self.infoplist = readInfo(self.backuppath) if self.infoplist is None: self.informationMessage("Can't find Info.plist in directory %s. Not a valid backup directory?" % self.backuppath) self.ui.statusbar.showMessage("Stop...") return False else: # refresh gridLayoutInfo self.gridLayoutInfo_refresh(self.infoplist) if not self.manifest.has_key("BackupKeyBag"): self.informationMessage("Only iOSBackup >= Version 5 Supported") if self.manifest["IsEncrypted"]: self.passwd = self.passwordDialog() if self.passwd is None: self.informationMessage("Password not given! Will not be able to extract information...") progressBar = QtGui.QProgressBar() self.ui.statusbar.addWidget(progressBar) self.mbdb = MBDB(self.backuppath) if self.passwd is not None: kb = Keybag.createWithBackupManifest(self.manifest, self.passwd) if not kb: self.informationMessage( "Can not extract backup key.\nYou can only browse through the domains and apps...") # return False self.manifest["password"] = self.passwd self.mbdb.keybag = kb progressBar.setMaximum(self.mbdb.numoffiles) if TestMode is True: self.database, self.cursor = iOSBackupDB(TestDatabase) else: self.database, self.cursor = iOSBackupDB() store2db(self.cursor, self.mbdb) self.database.commit() self.ui.treeViewDomains.setHeaderLabel("Files/Domains/Apps") standardFiles = QtGui.QTreeWidgetItem(None) standardFiles.setText(0, "Standard files") self.ui.treeViewDomains.addTopLevelItem(standardFiles) for elementName in ['Manifest.plist', 'Info.plist', 'Status.plist']: newItem = QtGui.QTreeWidgetItem(standardFiles) newItem.setText(0, elementName) newItem.setText(1, "X") self.ui.treeViewDomains.addTopLevelItem(newItem) self.cursor.execute("SELECT DISTINCT(mbdomain_type) FROM indice") domain_types = self.cursor.fetchall() for domain_type_u in domain_types: domain_type = str(domain_type_u[0]) newDomainFamily = QtGui.QTreeWidgetItem(None) newDomainFamily.setText(0, domain_type) self.ui.treeViewDomains.addTopLevelItem(newDomainFamily) # show new domain family in main view QtGui.QApplication.processEvents() query = "SELECT DISTINCT(mbapp_name) FROM indice WHERE mbdomain_type = ? ORDER BY mbdomain_type" self.cursor.execute(query, (domain_type,)) domain_names = self.cursor.fetchall() for domain_name_u in domain_names: domain_name = str(domain_name_u[0]) if (len(domain_names) > 1): newDomain = QtGui.QTreeWidgetItem(newDomainFamily) newDomain.setText(0, domain_name) self.ui.treeViewDomains.addTopLevelItem(newDomain) rootNode = newDomain else: rootNode = newDomainFamily # query = "SELECT path, mbfile_path, mbfile_name, size, fileid, mbfile_type FROM indice WHERE mbdomain_type = ? AND mbapp_name = ? ORDER BY mbfile_path, mbfile_name" query = "SELECT mbfile_path, mbfile_name, size, id, mbfile_type FROM indice WHERE mbdomain_type = ? AND mbapp_name = ? ORDER BY mbfile_path, mbfile_name" self.cursor.execute(query, (domain_type, domain_name)) nodes = self.cursor.fetchall() pathToNode = {'': rootNode} for nodeData in nodes: path = str(nodeData[0]) # finding parent directory lookup = path missing = collections.deque() dirNode = None while dirNode is None: dirNode = pathToNode.get(lookup, None) if dirNode is None: lookup, sep, component = lookup.rpartition('/') missing.appendleft(component) # creating parent directory if neccesary for component in missing: newPath = QtGui.QTreeWidgetItem(dirNode) newPath.setText(0, component) newPath.setToolTip(0, component) self.ui.treeViewDomains.addTopLevelItem(newPath) dirNode = newPath #lookup = posixpath.join(lookup, component) lookup = path pathToNode[lookup] = newPath try: file_name = str(nodeData[1].encode("utf-8")) except: file_name = nodeData[1] if (nodeData[2]) < 1024: file_dim = str(nodeData[2]) + " b" else: file_dim = str(nodeData[2] / 1024) + " kb" file_id = int(nodeData[3]) file_type = str(nodeData[4]) if file_type == 'd': newFile = dirNode else: newFile = QtGui.QTreeWidgetItem(newPath) self.ui.treeViewDomains.addTopLevelItem(newFile) newFile.setText(0, file_name) newFile.setToolTip(0, file_name) newFile.setText(2, str(file_dim)) newFile.setText(1, file_type) newFile.setText(3, str(file_id)) newFile.setText(4, domain_type) newFile.setText(5, domain_name) rawFiles = QtGui.QTreeWidgetItem(None) rawFiles.setText(0, "Raw files") self.ui.treeViewDomains.addTopLevelItem(rawFiles) # query = "SELECT mbfile_path, mbfile_name, size, id, mbfile_type FROM indice ORDER BY mbfile_path, mbfile_name" query = "SELECT domain, path, size, id, mbfile_type FROM indice ORDER BY domain, path" self.cursor.execute(query) nodes = self.cursor.fetchall() for nodeData in nodes: domain_name = str(nodeData[0]).replace("-", "/", 1) + "/" + str(nodeData[1]) newFile = QtGui.QTreeWidgetItem(rawFiles) self.ui.treeViewDomains.addTopLevelItem(newFile) if (nodeData[2]) < 1024: file_dim = str(nodeData[2]) + " b" else: file_dim = str(nodeData[2] / 1024) + " kb" file_id = int(nodeData[3]) file_type = str(nodeData[4]) newFile.setText(0, domain_name) newFile.setToolTip(0, domain_name) newFile.setText(2, str(file_dim)) newFile.setText(1, file_type) newFile.setText(3, str(file_id)) self.ui.statusbar.removeWidget(progressBar) self.activateMenu(True) return True