diff --git a/mvt/ios/modules/base.py b/mvt/ios/modules/base.py index cab0c30..4eb1309 100644 --- a/mvt/ios/modules/base.py +++ b/mvt/ios/modules/base.py @@ -26,27 +26,28 @@ class IOSExtraction(MVTModule): self.is_fs_dump = False self.is_sysdiagnose = False - def _recover_sqlite_db_if_needed(self, file_path): + def _recover_sqlite_db_if_needed(self, file_path, forced=False): """Tries to recover a malformed database by running a .clone command. :param file_path: Path to the malformed database file. """ # TODO: Find a better solution. - conn = sqlite3.connect(file_path) - cur = conn.cursor() + if not forced: + conn = sqlite3.connect(file_path) + cur = conn.cursor() - try: - recover = False - cur.execute("SELECT name FROM sqlite_master WHERE type='table';") - except sqlite3.DatabaseError as e: - if "database disk image is malformed" in str(e): - recover = True - finally: - conn.close() + try: + recover = False + cur.execute("SELECT name FROM sqlite_master WHERE type='table';") + except sqlite3.DatabaseError as e: + if "database disk image is malformed" in str(e): + recover = True + finally: + conn.close() - if not recover: - return + if not recover: + return self.log.info("Database at path %s is malformed. Trying to recover...", file_path) diff --git a/mvt/ios/modules/mixed/sms.py b/mvt/ios/modules/mixed/sms.py index c5cc3ea..60425b7 100644 --- a/mvt/ios/modules/mixed/sms.py +++ b/mvt/ios/modules/mixed/sms.py @@ -51,18 +51,37 @@ class SMS(IOSExtraction): root_paths=SMS_ROOT_PATHS) self.log.info("Found SMS database at path: %s", self.file_path) - conn = sqlite3.connect(self.file_path) - cur = conn.cursor() - cur.execute(""" - SELECT - message.*, - handle.id as "phone_number" - FROM message, handle - WHERE handle.rowid = message.handle_id; - """) + try: + conn = sqlite3.connect(self.file_path) + cur = conn.cursor() + cur.execute(""" + SELECT + message.*, + handle.id as "phone_number" + FROM message, handle + WHERE handle.rowid = message.handle_id; + """) + # Force the query early to catch database issues + items = list(cur) + except sqlite3.DatabaseError as e: + conn.close() + if "database disk image is malformed" in str(e): + self._recover_sqlite_db_if_needed(self.file_path, forced=True) + conn = sqlite3.connect(self.file_path) + cur = conn.cursor() + cur.execute(""" + SELECT + message.*, + handle.id as "phone_number" + FROM message, handle + WHERE handle.rowid = message.handle_id; + """) + items = list(cur) + else: + raise e names = [description[0] for description in cur.description] - for item in cur: + for item in items: message = {} for index, value in enumerate(item): # We base64 escape some of the attributes that could contain