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
예제 #2
0
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
예제 #3
0
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")
예제 #4
0
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)
예제 #5
0
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?"
예제 #6
0
    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