diff --git a/mvt/ios/modules/base.py b/mvt/ios/modules/base.py index e45eb54..dfcc72d 100644 --- a/mvt/ios/modules/base.py +++ b/mvt/ios/modules/base.py @@ -68,6 +68,34 @@ class IOSExtraction(MVTModule): self.log.info("Database at path %s recovered successfully!", file_path) + def _get_files_from_manifest(self, relative_path=None, domain=None): + """Locate files from Manifest.db. + :param relative_path: Relative path to use as filter from Manifest.db. + :param domain: Domain to use as filter from Manifest.db. + """ + manifest_db_path = os.path.join(self.base_folder, "Manifest.db") + if not os.path.exists(manifest_db_path): + raise Exception("Unable to find backup's Manifest.db") + + base_sql = "SELECT fileID, domain, relativePath FROM Files WHERE " + + try: + conn = sqlite3.connect(manifest_db_path) + cur = conn.cursor() + if relative_path and domain: + cur.execute(f"{base_sql} relativePath = ? AND domain = ?;", + (relative_path, domain)) + else: + if relative_path: + cur.execute(f"{base_sql} relativePath = ?;", (relative_path,)) + elif domain: + cur.execute(f"{base_sql} domain = ?;", (domain,)) + except Exception as e: + raise Exception("Query to Manifest.db failed: %s", e) + + for row in cur: + yield dict(file_id=row[0], domain=row[1], relative_path=row[2]) + def _find_ios_database(self, backup_ids=None, root_paths=[]): """Try to locate the module's database file from either an iTunes backup or a full filesystem dump. diff --git a/mvt/ios/modules/mixed/webkit_resource_load_statistics.py b/mvt/ios/modules/mixed/webkit_resource_load_statistics.py index 36187ac..7735334 100644 --- a/mvt/ios/modules/mixed/webkit_resource_load_statistics.py +++ b/mvt/ios/modules/mixed/webkit_resource_load_statistics.py @@ -75,24 +75,13 @@ class WebkitResourceLoadStatistics(IOSExtraction): self.results = {} if self.is_backup: - manifest_db_path = os.path.join(self.base_folder, "Manifest.db") - if not os.path.exists(manifest_db_path): - self.log.info("Unable to search for WebKit observations.db files in backup because of missing Manifest.db") - return - try: - conn = sqlite3.connect(manifest_db_path) - cur = conn.cursor() - cur.execute("SELECT fileID, domain FROM Files WHERE relativePath = ?;", (WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH,)) + for backup_file in self._get_files_from_manifest(relative_path=WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH): + db_path = os.path.join(self.base_folder, backup_file["file_id"][0:2], backup_file["file_id"]) + key = f"{backup_file['domain']}/{WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH}" + self._process_observations_db(db_path=db_path, key=key) except Exception as e: - self.log.error("Unable to search for WebKit observations.db files in backup because of failed query to Manifest.db: %s", e) - - for row in cur: - file_id = row[0] - domain = row[1] - db_path = os.path.join(self.base_folder, file_id[0:2], file_id) - if os.path.exists(db_path): - self._process_observations_db(db_path=db_path, key=f"{domain}/{WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH}") + self.log.info("Unable to search for WebKit observations.db: %s", e) elif self.is_fs_dump: for db_path in self._find_paths(WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS): self._process_observations_db(db_path=db_path, key=os.path.relpath(db_path, self.base_folder))