diff --git a/src/mvt/android/cmd_check_adb.py b/src/mvt/android/cmd_check_adb.py index e274040..c1444f4 100644 --- a/src/mvt/android/cmd_check_adb.py +++ b/src/mvt/android/cmd_check_adb.py @@ -7,6 +7,7 @@ import logging from typing import Optional from mvt.common.command import Command +from mvt.common.indicators import Indicators from .modules.adb import ADB_MODULES @@ -19,17 +20,23 @@ class CmdAndroidCheckADB(Command): target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, + hashes: Optional[bool] = False, + sub_command: Optional[bool] = False, ) -> None: super().__init__( target_path=target_path, results_path=results_path, ioc_files=ioc_files, + iocs=iocs, module_name=module_name, serial=serial, module_options=module_options, + hashes=hashes, + sub_command=sub_command, log=log, ) diff --git a/src/mvt/android/cmd_check_androidqf.py b/src/mvt/android/cmd_check_androidqf.py index e079807..628548c 100644 --- a/src/mvt/android/cmd_check_androidqf.py +++ b/src/mvt/android/cmd_check_androidqf.py @@ -10,58 +10,182 @@ from pathlib import Path from typing import List, Optional from mvt.common.command import Command +from mvt.common.indicators import Indicators + +from mvt.android.cmd_check_bugreport import CmdAndroidCheckBugreport +from mvt.android.cmd_check_backup import CmdAndroidCheckBackup from .modules.androidqf import ANDROIDQF_MODULES +from .modules.androidqf.base import AndroidQFModule log = logging.getLogger(__name__) +class NoAndroidQFTargetPath(Exception): + pass + + +class NoAndroidQFBugReport(Exception): + pass + + +class NoAndroidQFBackup(Exception): + pass + + class CmdAndroidCheckAndroidQF(Command): def __init__( self, target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, - hashes: bool = False, + hashes: Optional[bool] = False, + sub_command: Optional[bool] = False, ) -> None: super().__init__( target_path=target_path, results_path=results_path, ioc_files=ioc_files, + iocs=iocs, module_name=module_name, serial=serial, module_options=module_options, hashes=hashes, + sub_command=sub_command, log=log, ) self.name = "check-androidqf" self.modules = ANDROIDQF_MODULES - self.format: Optional[str] = None - self.archive: Optional[zipfile.ZipFile] = None - self.files: List[str] = [] + self.__format: Optional[str] = None + self.__zip: Optional[zipfile.ZipFile] = None + self.__files: List[str] = [] def init(self): if os.path.isdir(self.target_path): - self.format = "dir" + self.__format = "dir" parent_path = Path(self.target_path).absolute().parent.as_posix() target_abs_path = os.path.abspath(self.target_path) for root, subdirs, subfiles in os.walk(target_abs_path): for fname in subfiles: file_path = os.path.relpath(os.path.join(root, fname), parent_path) - self.files.append(file_path) + self.__files.append(file_path) elif os.path.isfile(self.target_path): - self.format = "zip" - self.archive = zipfile.ZipFile(self.target_path) - self.files = self.archive.namelist() + self.__format = "zip" + self.__zip = zipfile.ZipFile(self.target_path) + self.__files = self.__zip.namelist() - def module_init(self, module): - if self.format == "zip": - module.from_zip_file(self.archive, self.files) + def module_init(self, module: AndroidQFModule) -> None: # type: ignore[override] + if self.__format == "zip" and self.__zip: + module.from_zip(self.__zip, self.__files) + return + + if not self.target_path: + raise NoAndroidQFTargetPath + + parent_path = Path(self.target_path).absolute().parent.as_posix() + module.from_dir(parent_path, self.__files) + + def load_bugreport(self) -> zipfile.ZipFile: + bugreport_zip_path = None + for file_name in self.__files: + if file_name.endswith("bugreport.zip"): + bugreport_zip_path = file_name + break else: + raise NoAndroidQFBugReport + + if self.__format == "zip" and self.__zip: + handle = self.__zip.open(bugreport_zip_path) + return zipfile.ZipFile(handle) + + if self.__format == "dir" and self.target_path: parent_path = Path(self.target_path).absolute().parent.as_posix() - module.from_folder(parent_path, self.files) + bug_report_path = os.path.join(parent_path, bugreport_zip_path) + return zipfile.ZipFile(bug_report_path) + + raise NoAndroidQFBugReport + + def load_backup(self) -> bytes: + backup_ab_path = None + for file_name in self.__files: + if file_name.endswith("backup.ab"): + backup_ab_path = file_name + break + else: + raise NoAndroidQFBackup + + if self.__format == "zip" and self.__zip: + backup_file_handle = self.__zip.open(backup_ab_path) + return backup_file_handle.read() + + if self.__format == "dir" and self.target_path: + parent_path = Path(self.target_path).absolute().parent.as_posix() + backup_path = os.path.join(parent_path, backup_ab_path) + with open(backup_path, "rb") as backup_file: + backup_ab_data = backup_file.read() + return backup_ab_data + + raise NoAndroidQFBackup + + def run_bugreport_cmd(self) -> bool: + try: + bugreport = self.load_bugreport() + except NoAndroidQFBugReport: + self.log.warning( + "Skipping bugreport modules as no bugreport.zip found in AndroidQF data." + ) + return False + else: + cmd = CmdAndroidCheckBugreport( + target_path=None, + results_path=self.results_path, + ioc_files=self.ioc_files, + iocs=self.iocs, + module_options=self.module_options, + hashes=self.hashes, + sub_command=True, + ) + cmd.from_zip(bugreport) + cmd.run() + + self.detected_count += cmd.detected_count + self.timeline.extend(cmd.timeline) + self.timeline_detected.extend(cmd.timeline_detected) + + def run_backup_cmd(self) -> bool: + try: + backup = self.load_backup() + except NoAndroidQFBugReport: + self.log.warning( + "Skipping backup modules as no backup.ab found in AndroidQF data." + ) + return False + else: + cmd = CmdAndroidCheckBackup( + target_path=None, + results_path=self.results_path, + ioc_files=self.ioc_files, + iocs=self.iocs, + module_options=self.module_options, + hashes=self.hashes, + sub_command=True, + ) + cmd.from_ab(backup) + cmd.run() + + self.detected_count += cmd.detected_count + self.timeline.extend(cmd.timeline) + self.timeline_detected.extend(cmd.timeline_detected) + + def finish(self) -> None: + """ + Run the bugreport and backup modules if the respective files are found in the AndroidQF data. + """ + self.run_bugreport_cmd() + self.run_backup_cmd() diff --git a/src/mvt/android/cmd_check_backup.py b/src/mvt/android/cmd_check_backup.py index 2a68900..e366d2b 100644 --- a/src/mvt/android/cmd_check_backup.py +++ b/src/mvt/android/cmd_check_backup.py @@ -20,6 +20,7 @@ from mvt.android.parsers.backup import ( parse_backup_file, ) from mvt.common.command import Command +from mvt.common.indicators import Indicators from .modules.backup import BACKUP_MODULES @@ -32,19 +33,23 @@ class CmdAndroidCheckBackup(Command): target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, - hashes: bool = False, + hashes: Optional[bool] = False, + sub_command: Optional[bool] = False, ) -> None: super().__init__( target_path=target_path, results_path=results_path, ioc_files=ioc_files, + iocs=iocs, module_name=module_name, serial=serial, module_options=module_options, hashes=hashes, + sub_command=sub_command, log=log, ) @@ -55,6 +60,34 @@ class CmdAndroidCheckBackup(Command): self.backup_archive: Optional[tarfile.TarFile] = None self.backup_files: List[str] = [] + def from_ab(self, ab_file_bytes: bytes) -> None: + self.backup_type = "ab" + header = parse_ab_header(ab_file_bytes) + if not header["backup"]: + log.critical("Invalid backup format, file should be in .ab format") + sys.exit(1) + + password = None + if header["encryption"] != "none": + password = prompt_or_load_android_backup_password(log, self.module_options) + if not password: + log.critical("No backup password provided.") + sys.exit(1) + try: + tardata = parse_backup_file(ab_file_bytes, password=password) + except InvalidBackupPassword: + log.critical("Invalid backup password") + sys.exit(1) + except AndroidBackupParsingError as exc: + log.critical("Impossible to parse this backup file: %s", exc) + log.critical("Please use Android Backup Extractor (ABE) instead") + sys.exit(1) + + dbytes = io.BytesIO(tardata) + self.backup_archive = tarfile.open(fileobj=dbytes) + for member in self.backup_archive: + self.backup_files.append(member.name) + def init(self) -> None: if not self.target_path: return @@ -62,35 +95,8 @@ class CmdAndroidCheckBackup(Command): if os.path.isfile(self.target_path): self.backup_type = "ab" with open(self.target_path, "rb") as handle: - data = handle.read() - - header = parse_ab_header(data) - if not header["backup"]: - log.critical("Invalid backup format, file should be in .ab format") - sys.exit(1) - - password = None - if header["encryption"] != "none": - password = prompt_or_load_android_backup_password( - log, self.module_options - ) - if not password: - log.critical("No backup password provided.") - sys.exit(1) - try: - tardata = parse_backup_file(data, password=password) - except InvalidBackupPassword: - log.critical("Invalid backup password") - sys.exit(1) - except AndroidBackupParsingError as exc: - log.critical("Impossible to parse this backup file: %s", exc) - log.critical("Please use Android Backup Extractor (ABE) instead") - sys.exit(1) - - dbytes = io.BytesIO(tardata) - self.backup_archive = tarfile.open(fileobj=dbytes) - for member in self.backup_archive: - self.backup_files.append(member.name) + ab_file_bytes = handle.read() + self.from_ab(ab_file_bytes) elif os.path.isdir(self.target_path): self.backup_type = "folder" @@ -109,6 +115,6 @@ class CmdAndroidCheckBackup(Command): def module_init(self, module: BackupExtraction) -> None: # type: ignore[override] if self.backup_type == "folder": - module.from_folder(self.target_path, self.backup_files) + module.from_dir(self.target_path, self.backup_files) else: module.from_ab(self.target_path, self.backup_archive, self.backup_files) diff --git a/src/mvt/android/cmd_check_bugreport.py b/src/mvt/android/cmd_check_bugreport.py index 08a266f..a3d9b3b 100644 --- a/src/mvt/android/cmd_check_bugreport.py +++ b/src/mvt/android/cmd_check_bugreport.py @@ -11,6 +11,7 @@ from zipfile import ZipFile from mvt.android.modules.bugreport.base import BugReportModule from mvt.common.command import Command +from mvt.common.indicators import Indicators from .modules.bugreport import BUGREPORT_MODULES @@ -23,54 +24,76 @@ class CmdAndroidCheckBugreport(Command): target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, - hashes: bool = False, + hashes: Optional[bool] = False, + sub_command: Optional[bool] = False, ) -> None: super().__init__( target_path=target_path, results_path=results_path, ioc_files=ioc_files, + iocs=iocs, module_name=module_name, serial=serial, module_options=module_options, hashes=hashes, + sub_command=sub_command, log=log, ) self.name = "check-bugreport" self.modules = BUGREPORT_MODULES - self.bugreport_format: str = "" - self.bugreport_archive: Optional[ZipFile] = None - self.bugreport_files: List[str] = [] + self.__format: str = "" + self.__zip: Optional[ZipFile] = None + self.__files: List[str] = [] + + def from_dir(self, dir_path: str) -> None: + """This method is used to initialize the bug report analysis from an + uncompressed directory. + """ + self.__format = "dir" + self.target_path = dir_path + parent_path = Path(dir_path).absolute().as_posix() + for root, _, subfiles in os.walk(os.path.abspath(dir_path)): + for file_name in subfiles: + file_path = os.path.relpath(os.path.join(root, file_name), parent_path) + self.__files.append(file_path) + + def from_zip(self, bugreport_zip: ZipFile) -> None: + """This method is used to initialize the bug report analysis from a + compressed archive. + """ + # NOTE: This will be invoked either by the CLI directly,or by the + # check-androidqf command. We need this because we want to support + # check-androidqf to analyse compressed archives itself too. + # So, we'll need to extract bugreport.zip from a 'androidqf.zip', and + # since nothing is written on disk, we need to be able to pass this + # command a ZipFile instance in memory. + + self.__format = "zip" + self.__zip = bugreport_zip + for file_name in self.__zip.namelist(): + self.__files.append(file_name) def init(self) -> None: if not self.target_path: return if os.path.isfile(self.target_path): - self.bugreport_format = "zip" - self.bugreport_archive = ZipFile(self.target_path) - for file_name in self.bugreport_archive.namelist(): - self.bugreport_files.append(file_name) + self.from_zip(ZipFile(self.target_path)) elif os.path.isdir(self.target_path): - self.bugreport_format = "dir" - parent_path = Path(self.target_path).absolute().as_posix() - for root, _, subfiles in os.walk(os.path.abspath(self.target_path)): - for file_name in subfiles: - file_path = os.path.relpath( - os.path.join(root, file_name), parent_path - ) - self.bugreport_files.append(file_path) + self.from_dir(self.target_path) def module_init(self, module: BugReportModule) -> None: # type: ignore[override] - if self.bugreport_format == "zip": - module.from_zip(self.bugreport_archive, self.bugreport_files) + if self.__format == "zip": + module.from_zip(self.__zip, self.__files) else: - module.from_folder(self.target_path, self.bugreport_files) + module.from_dir(self.target_path, self.__files) def finish(self) -> None: - if self.bugreport_archive: - self.bugreport_archive.close() + if self.__zip: + self.__zip.close() diff --git a/src/mvt/android/modules/androidqf/base.py b/src/mvt/android/modules/androidqf/base.py index d871059..43e6210 100644 --- a/src/mvt/android/modules/androidqf/base.py +++ b/src/mvt/android/modules/androidqf/base.py @@ -37,11 +37,11 @@ class AndroidQFModule(MVTModule): self.files: List[str] = [] self.archive: Optional[zipfile.ZipFile] = None - def from_folder(self, parent_path: str, files: List[str]): + def from_dir(self, parent_path: str, files: List[str]) -> None: self.parent_path = parent_path self.files = files - def from_zip_file(self, archive: zipfile.ZipFile, files: List[str]): + def from_zip(self, archive: zipfile.ZipFile, files: List[str]) -> None: self.archive = archive self.files = files diff --git a/src/mvt/android/modules/backup/base.py b/src/mvt/android/modules/backup/base.py index 5141bfe..29238ba 100644 --- a/src/mvt/android/modules/backup/base.py +++ b/src/mvt/android/modules/backup/base.py @@ -37,10 +37,7 @@ class BackupExtraction(MVTModule): self.tar = None self.files = [] - def from_folder(self, backup_path: Optional[str], files: List[str]) -> None: - """ - Get all the files and list them - """ + def from_dir(self, backup_path: Optional[str], files: List[str]) -> None: self.backup_path = backup_path self.files = files @@ -58,14 +55,16 @@ class BackupExtraction(MVTModule): return fnmatch.filter(self.files, pattern) def _get_file_content(self, file_path: str) -> bytes: - if self.ab: + if self.tar: try: member = self.tar.getmember(file_path) except KeyError: return None handle = self.tar.extractfile(member) - else: + elif self.backup_path: handle = open(os.path.join(self.backup_path, file_path), "rb") + else: + raise ValueError("No backup path or tar file provided") data = handle.read() handle.close() diff --git a/src/mvt/android/modules/backup/sms.py b/src/mvt/android/modules/backup/sms.py index a75be26..a194a1e 100644 --- a/src/mvt/android/modules/backup/sms.py +++ b/src/mvt/android/modules/backup/sms.py @@ -50,13 +50,13 @@ class SMS(BackupExtraction): def run(self) -> None: sms_path = "apps/com.android.providers.telephony/d_f/*_sms_backup" for file in self._get_files_by_pattern(sms_path): - self.log.info("Processing SMS backup file at %s", file) + self.log.debug("Processing SMS backup file at %s", file) data = self._get_file_content(file) self.results.extend(parse_sms_file(data)) mms_path = "apps/com.android.providers.telephony/d_f/*_mms_backup" for file in self._get_files_by_pattern(mms_path): - self.log.info("Processing MMS backup file at %s", file) + self.log.debug("Processing MMS backup file at %s", file) data = self._get_file_content(file) self.results.extend(parse_sms_file(data)) diff --git a/src/mvt/android/modules/bugreport/base.py b/src/mvt/android/modules/bugreport/base.py index 77802b2..158bc28 100644 --- a/src/mvt/android/modules/bugreport/base.py +++ b/src/mvt/android/modules/bugreport/base.py @@ -39,9 +39,7 @@ class BugReportModule(MVTModule): self.extract_files: List[str] = [] self.zip_files: List[str] = [] - def from_folder( - self, extract_path: Optional[str], extract_files: List[str] - ) -> None: + def from_dir(self, extract_path: str, extract_files: List[str]) -> None: self.extract_path = extract_path self.extract_files = extract_files diff --git a/src/mvt/common/cmd_check_iocs.py b/src/mvt/common/cmd_check_iocs.py index 696803a..1f8bde5 100644 --- a/src/mvt/common/cmd_check_iocs.py +++ b/src/mvt/common/cmd_check_iocs.py @@ -22,6 +22,8 @@ class CmdCheckIOCS(Command): module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, + hashes: Optional[bool] = False, + sub_command: Optional[bool] = False, ) -> None: super().__init__( target_path=target_path, @@ -30,6 +32,8 @@ class CmdCheckIOCS(Command): module_name=module_name, serial=serial, module_options=module_options, + hashes=hashes, + sub_command=sub_command, log=log, ) diff --git a/src/mvt/common/command.py b/src/mvt/common/command.py index 7f65843..b6d7aaf 100644 --- a/src/mvt/common/command.py +++ b/src/mvt/common/command.py @@ -27,10 +27,12 @@ class Command: target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, - hashes: bool = False, + hashes: Optional[bool] = False, + sub_command: Optional[bool] = False, log: logging.Logger = logging.getLogger(__name__), ) -> None: self.name = "" @@ -42,6 +44,7 @@ class Command: self.module_name = module_name self.serial = serial self.log = log + self.sub_command = sub_command # This dictionary can contain options that will be passed down from # the Command to all modules. This can for example be used to pass @@ -60,8 +63,12 @@ class Command: # Load IOCs self._create_storage() self._setup_logging() - self.iocs = Indicators(log=log) - self.iocs.load_indicators_files(self.ioc_files) + + if iocs is not None: + self.iocs = iocs + else: + self.iocs = Indicators(self.log) + self.iocs.load_indicators_files(self.ioc_files) def _create_storage(self) -> None: if self.results_path and not os.path.exists(self.results_path): @@ -247,6 +254,10 @@ class Command: except NotImplementedError: pass + # We only store the timeline from the parent/main command + if self.sub_command: + return + self._store_timeline() self._store_info() diff --git a/src/mvt/ios/cmd_check_backup.py b/src/mvt/ios/cmd_check_backup.py index 66dfc8e..dcdc013 100644 --- a/src/mvt/ios/cmd_check_backup.py +++ b/src/mvt/ios/cmd_check_backup.py @@ -7,6 +7,7 @@ import logging from typing import Optional from mvt.common.command import Command +from mvt.common.indicators import Indicators from .modules.backup import BACKUP_MODULES from .modules.mixed import MIXED_MODULES @@ -20,19 +21,23 @@ class CmdIOSCheckBackup(Command): target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, hashes: bool = False, + sub_command: bool = False, ) -> None: super().__init__( target_path=target_path, results_path=results_path, ioc_files=ioc_files, + iocs=iocs, module_name=module_name, serial=serial, module_options=module_options, hashes=hashes, + sub_command=sub_command, log=log, ) diff --git a/src/mvt/ios/cmd_check_fs.py b/src/mvt/ios/cmd_check_fs.py index 3484138..605bfd0 100644 --- a/src/mvt/ios/cmd_check_fs.py +++ b/src/mvt/ios/cmd_check_fs.py @@ -7,6 +7,7 @@ import logging from typing import Optional from mvt.common.command import Command +from mvt.common.indicators import Indicators from .modules.fs import FS_MODULES from .modules.mixed import MIXED_MODULES @@ -20,19 +21,23 @@ class CmdIOSCheckFS(Command): target_path: Optional[str] = None, results_path: Optional[str] = None, ioc_files: Optional[list] = None, + iocs: Optional[Indicators] = None, module_name: Optional[str] = None, serial: Optional[str] = None, module_options: Optional[dict] = None, hashes: bool = False, + sub_command: bool = False, ) -> None: super().__init__( target_path=target_path, results_path=results_path, ioc_files=ioc_files, + iocs=iocs, module_name=module_name, serial=serial, module_options=module_options, hashes=hashes, + sub_command=sub_command, log=log, ) diff --git a/tests/android/test_backup_module.py b/tests/android/test_backup_module.py index 29bc8e9..57cb891 100644 --- a/tests/android/test_backup_module.py +++ b/tests/android/test_backup_module.py @@ -22,7 +22,7 @@ class TestBackupModule: for root, subdirs, subfiles in os.walk(os.path.abspath(backup_path)): for fname in subfiles: files.append(os.path.relpath(os.path.join(root, fname), backup_path)) - mod.from_folder(backup_path, files) + mod.from_dir(backup_path, files) run_module(mod) assert len(mod.results) == 2 assert len(mod.results[0]["links"]) == 1 diff --git a/tests/android_androidqf/test_dumpsys_adbstate.py b/tests/android_androidqf/test_dumpsys_adbstate.py index c94fe34..a3ac72e 100644 --- a/tests/android_androidqf/test_dumpsys_adbstate.py +++ b/tests/android_androidqf/test_dumpsys_adbstate.py @@ -17,7 +17,7 @@ class TestDumpsysADBModule: m = DumpsysADBState(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 1 assert len(m.detected) == 0 diff --git a/tests/android_androidqf/test_dumpsys_battery_daily.py b/tests/android_androidqf/test_dumpsys_battery_daily.py index 66a45d7..f82f330 100644 --- a/tests/android_androidqf/test_dumpsys_battery_daily.py +++ b/tests/android_androidqf/test_dumpsys_battery_daily.py @@ -17,7 +17,7 @@ class TestDumpsysBatteryDailyModule: m = DumpsysBatteryDaily(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 3 assert len(m.timeline) == 3 diff --git a/tests/android_androidqf/test_dumpsys_battery_history.py b/tests/android_androidqf/test_dumpsys_battery_history.py index 8b76459..fd1d0ae 100644 --- a/tests/android_androidqf/test_dumpsys_battery_history.py +++ b/tests/android_androidqf/test_dumpsys_battery_history.py @@ -17,7 +17,7 @@ class TestDumpsysBatteryHistoryModule: m = DumpsysBatteryHistory(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 6 assert len(m.timeline) == 0 diff --git a/tests/android_androidqf/test_dumpsys_dbinfo.py b/tests/android_androidqf/test_dumpsys_dbinfo.py index 83addbf..371a3bc 100644 --- a/tests/android_androidqf/test_dumpsys_dbinfo.py +++ b/tests/android_androidqf/test_dumpsys_dbinfo.py @@ -17,7 +17,7 @@ class TestDumpsysDBInfoModule: m = DumpsysDBInfo(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 6 assert len(m.timeline) == 0 diff --git a/tests/android_androidqf/test_dumpsys_platform_compat.py b/tests/android_androidqf/test_dumpsys_platform_compat.py index 8123432..bddc322 100644 --- a/tests/android_androidqf/test_dumpsys_platform_compat.py +++ b/tests/android_androidqf/test_dumpsys_platform_compat.py @@ -17,7 +17,7 @@ class TestDumpsysPlatformCompatModule: m = DumpsysPlatformCompat(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 2 assert len(m.detected) == 0 diff --git a/tests/android_androidqf/test_dumpsysaccessbility.py b/tests/android_androidqf/test_dumpsysaccessbility.py index 1a217d0..b437275 100644 --- a/tests/android_androidqf/test_dumpsysaccessbility.py +++ b/tests/android_androidqf/test_dumpsysaccessbility.py @@ -17,7 +17,7 @@ class TestDumpsysAccessibilityModule: m = DumpsysAccessibility(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 4 assert len(m.detected) == 0 diff --git a/tests/android_androidqf/test_dumpsysappops.py b/tests/android_androidqf/test_dumpsysappops.py index b0649a1..ce74d53 100644 --- a/tests/android_androidqf/test_dumpsysappops.py +++ b/tests/android_androidqf/test_dumpsysappops.py @@ -17,7 +17,7 @@ class TestDumpsysAppOpsModule: m = DumpsysAppops(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 12 assert len(m.timeline) == 16 diff --git a/tests/android_androidqf/test_dumpsyspackages.py b/tests/android_androidqf/test_dumpsyspackages.py index 798628f..e801b0a 100644 --- a/tests/android_androidqf/test_dumpsyspackages.py +++ b/tests/android_androidqf/test_dumpsyspackages.py @@ -19,7 +19,7 @@ class TestDumpsysPackagesModule: m = DumpsysPackages(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 2 assert len(m.detected) == 0 @@ -34,7 +34,7 @@ class TestDumpsysPackagesModule: m = DumpsysPackages(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) ind = Indicators(log=logging.getLogger()) ind.parse_stix2(indicator_file) ind.ioc_collections[0]["app_ids"].append("com.sec.android.app.DataCreate") diff --git a/tests/android_androidqf/test_dumpsysreceivers.py b/tests/android_androidqf/test_dumpsysreceivers.py index ce4b37a..0a06bab 100644 --- a/tests/android_androidqf/test_dumpsysreceivers.py +++ b/tests/android_androidqf/test_dumpsysreceivers.py @@ -17,7 +17,7 @@ class TestDumpsysReceiversModule: m = DumpsysReceivers(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 4 assert len(m.detected) == 0 diff --git a/tests/android_androidqf/test_files.py b/tests/android_androidqf/test_files.py index 80981a2..de8269c 100644 --- a/tests/android_androidqf/test_files.py +++ b/tests/android_androidqf/test_files.py @@ -18,7 +18,7 @@ class TestAndroidqfFilesAnalysis: m = Files(target_path=data_path, log=logging) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 3 assert len(m.timeline) == 6 diff --git a/tests/android_androidqf/test_getprop.py b/tests/android_androidqf/test_getprop.py index 4688b73..89fb522 100644 --- a/tests/android_androidqf/test_getprop.py +++ b/tests/android_androidqf/test_getprop.py @@ -20,7 +20,7 @@ class TestAndroidqfGetpropAnalysis: m = Getprop(target_path=data_path, log=logging) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 10 assert m.results[0]["name"] == "dalvik.vm.appimageformat" @@ -32,7 +32,7 @@ class TestAndroidqfGetpropAnalysis: fpath = get_artifact("androidqf.zip") m = Getprop(target_path=fpath, log=logging) archive = zipfile.ZipFile(fpath) - m.from_zip_file(archive, archive.namelist()) + m.from_zip(archive, archive.namelist()) run_module(m) assert len(m.results) == 10 assert m.results[0]["name"] == "dalvik.vm.appimageformat" @@ -45,7 +45,7 @@ class TestAndroidqfGetpropAnalysis: m = Getprop(target_path=data_path, log=logging) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) ind = Indicators(log=logging.getLogger()) ind.parse_stix2(indicator_file) ind.ioc_collections[0]["android_property_names"].append("dalvik.vm.heapmaxfree") diff --git a/tests/android_androidqf/test_packages.py b/tests/android_androidqf/test_packages.py index a7fce95..d911315 100644 --- a/tests/android_androidqf/test_packages.py +++ b/tests/android_androidqf/test_packages.py @@ -32,7 +32,7 @@ def file_list(data_path): @pytest.fixture() def module(parent_data_path, file_list): m = Packages(target_path=parent_data_path, log=logging) - m.from_folder(parent_data_path, file_list) + m.from_dir(parent_data_path, file_list) return m diff --git a/tests/android_androidqf/test_processes.py b/tests/android_androidqf/test_processes.py index 8aacb0b..98b5d2a 100644 --- a/tests/android_androidqf/test_processes.py +++ b/tests/android_androidqf/test_processes.py @@ -18,7 +18,7 @@ class TestAndroidqfProcessesAnalysis: m = Processes(target_path=data_path, log=logging) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 15 assert len(m.timeline) == 0 diff --git a/tests/android_androidqf/test_settings.py b/tests/android_androidqf/test_settings.py index c282901..44ee89c 100644 --- a/tests/android_androidqf/test_settings.py +++ b/tests/android_androidqf/test_settings.py @@ -17,7 +17,7 @@ class TestSettingsModule: m = Settings(target_path=data_path) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 1 assert "random" in m.results.keys() diff --git a/tests/android_androidqf/test_sms.py b/tests/android_androidqf/test_sms.py index 8bff799..d7433cf 100644 --- a/tests/android_androidqf/test_sms.py +++ b/tests/android_androidqf/test_sms.py @@ -21,7 +21,7 @@ class TestAndroidqfSMSAnalysis: m = SMS(target_path=data_path, log=logging) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 2 assert len(m.timeline) == 0 @@ -36,7 +36,7 @@ class TestAndroidqfSMSAnalysis: ) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 1 @@ -52,7 +52,7 @@ class TestAndroidqfSMSAnalysis: ) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert prompt_mock.call_count == 1 assert len(m.results) == 1 @@ -67,7 +67,7 @@ class TestAndroidqfSMSAnalysis: ) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 0 assert "Invalid backup password" in caplog.text @@ -82,7 +82,7 @@ class TestAndroidqfSMSAnalysis: ) files = list_files(data_path) parent_path = Path(data_path).absolute().parent.as_posix() - m.from_folder(parent_path, files) + m.from_dir(parent_path, files) run_module(m) assert len(m.results) == 0 assert ( diff --git a/tests/android_bugreport/test_bugreport.py b/tests/android_bugreport/test_bugreport.py index cc9afec..98744a6 100644 --- a/tests/android_bugreport/test_bugreport.py +++ b/tests/android_bugreport/test_bugreport.py @@ -25,7 +25,7 @@ class TestBugreportAnalysis: folder_files.append( os.path.relpath(os.path.join(root, file_name), parent_path) ) - m.from_folder(fpath, folder_files) + m.from_dir(fpath, folder_files) run_module(m) return m diff --git a/tests/test_check_android_androidqf.py b/tests/test_check_android_androidqf.py index 167b5b7..c6e4221 100644 --- a/tests/test_check_android_androidqf.py +++ b/tests/test_check_android_androidqf.py @@ -32,7 +32,8 @@ class TestCheckAndroidqfCommand: path = os.path.join(get_artifact_folder(), "androidqf_encrypted") result = runner.invoke(check_androidqf, [path]) - assert prompt_mock.call_count == 1 + # Called twice, once in AnroidQF SMS module and once in Backup SMS module + assert prompt_mock.call_count == 2 assert result.exit_code == 0 def test_check_encrypted_backup_cli(self, mocker):