From a12c4e6b93060b9b0a450728ba9f14136833215e Mon Sep 17 00:00:00 2001 From: Nex Date: Wed, 15 Jun 2022 17:41:19 +0200 Subject: [PATCH 1/6] First commit to refactor of command definitions --- mvt/android/cli.py | 193 ++---------------- mvt/android/cmd_check_adb.py | 24 +++ mvt/android/cmd_check_backup.py | 82 ++++++++ mvt/android/cmd_check_bugreport.py | 50 +++++ ...{download_apks.py => cmd_download_apks.py} | 0 mvt/android/modules/adb/base.py | 6 +- mvt/android/modules/adb/chrome_history.py | 6 +- .../modules/adb/dumpsys_accessibility.py | 6 +- mvt/android/modules/adb/dumpsys_activities.py | 6 +- mvt/android/modules/adb/dumpsys_appops.py | 7 +- .../modules/adb/dumpsys_battery_daily.py | 6 +- .../modules/adb/dumpsys_battery_history.py | 6 +- mvt/android/modules/adb/dumpsys_dbinfo.py | 7 +- mvt/android/modules/adb/dumpsys_full.py | 10 +- mvt/android/modules/adb/dumpsys_receivers.py | 6 +- mvt/android/modules/adb/files.py | 6 +- mvt/android/modules/adb/getprop.py | 7 +- mvt/android/modules/adb/logcat.py | 12 +- mvt/android/modules/adb/packages.py | 8 +- mvt/android/modules/adb/processes.py | 6 +- mvt/android/modules/adb/root_binaries.py | 6 +- mvt/android/modules/adb/selinux_status.py | 9 +- mvt/android/modules/adb/settings.py | 6 +- mvt/android/modules/adb/sms.py | 8 +- mvt/android/modules/adb/whatsapp.py | 6 +- mvt/android/modules/backup/sms.py | 7 +- .../modules/bugreport/accessibility.py | 6 +- mvt/android/modules/bugreport/activities.py | 6 +- mvt/android/modules/bugreport/appops.py | 6 +- .../modules/bugreport/battery_daily.py | 6 +- .../modules/bugreport/battery_history.py | 6 +- mvt/android/modules/bugreport/dbinfo.py | 6 +- mvt/android/modules/bugreport/getprop.py | 7 +- mvt/android/modules/bugreport/packages.py | 6 +- mvt/android/modules/bugreport/receivers.py | 6 +- mvt/android/parsers/backup.py | 12 +- mvt/common/command.py | 94 +++++++++ mvt/common/module.py | 18 +- setup.cfg | 2 +- tests/android/test_backup_parser.py | 1 - tests/android/test_bugreport_appops.py | 1 - tests/android/test_dumpsys_parser.py | 3 - 42 files changed, 384 insertions(+), 298 deletions(-) create mode 100644 mvt/android/cmd_check_adb.py create mode 100644 mvt/android/cmd_check_backup.py create mode 100644 mvt/android/cmd_check_bugreport.py rename mvt/android/{download_apks.py => cmd_download_apks.py} (100%) create mode 100644 mvt/common/command.py diff --git a/mvt/android/cli.py b/mvt/android/cli.py index 32c3ed0..d8bd05b 100644 --- a/mvt/android/cli.py +++ b/mvt/android/cli.py @@ -3,32 +3,25 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ -import getpass -import io import logging import os -import tarfile -from pathlib import Path -from zipfile import ZipFile import click from rich.logging import RichHandler -from mvt.android.parsers.backup import (AndroidBackupParsingError, - InvalidBackupPassword, parse_ab_header, - parse_backup_file) +from mvt.android.cmd_check_adb import CmdAndroidCheckADB +from mvt.android.cmd_check_backup import CmdAndroidCheckBackup +from mvt.android.cmd_check_bugreport import CmdAndroidCheckBugreport from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_OUTPUT, HELP_MSG_SERIAL) from mvt.common.indicators import Indicators, download_indicators_files from mvt.common.logo import logo -from mvt.common.module import run_module, save_timeline -from .download_apks import DownloadAPKs +from .cmd_download_apks import DownloadAPKs from .modules.adb import ADB_MODULES from .modules.adb.packages import Packages from .modules.backup import BACKUP_MODULES -from .modules.bugreport import BUGREPORT_MODULES # Setup logging using Rich. LOG_FORMAT = "[%(name)s] %(message)s" @@ -122,48 +115,14 @@ def download_apks(ctx, all_apks, virustotal, output, from_file, serial): @click.option("--module", "-m", help=HELP_MSG_MODULE) @click.pass_context def check_adb(ctx, iocs, output, fast, list_modules, module, serial): - if list_modules: - log.info("Following is the list of available check-adb modules:") - for adb_module in ADB_MODULES: - log.info(" - %s", adb_module.__name__) + cmd = CmdAndroidCheckADB(results_path=output, ioc_files=iocs, + module_name=module, serial=serial, fast_mode=fast) + if list_modules: + cmd.list_modules() return - log.info("Checking Android through adb bridge") - - if output and not os.path.exists(output): - try: - os.makedirs(output) - except Exception as e: - log.critical("Unable to create output folder %s: %s", output, e) - ctx.exit(1) - - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - timeline = [] - timeline_detected = [] - for adb_module in ADB_MODULES: - if module and adb_module.__name__ != module: - continue - - m = adb_module(output_folder=output, fast_mode=fast, - log=logging.getLogger(adb_module.__module__)) - if indicators.total_ioc_count: - m.indicators = indicators - m.indicators.log = m.log - if serial: - m.serial = serial - - run_module(m) - timeline.extend(m.timeline) - timeline_detected.extend(m.timeline_detected) - - if output: - if len(timeline) > 0: - save_timeline(timeline, os.path.join(output, "timeline.csv")) - if len(timeline_detected) > 0: - save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv")) + cmd.run() #============================================================================== @@ -178,66 +137,14 @@ def check_adb(ctx, iocs, output, fast, list_modules, module, serial): @click.argument("BUGREPORT_PATH", type=click.Path(exists=True)) @click.pass_context def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path): - if list_modules: - log.info("Following is the list of available check-bugreport modules:") - for adb_module in BUGREPORT_MODULES: - log.info(" - %s", adb_module.__name__) + cmd = CmdAndroidCheckBugreport(target_path=bugreport_path, results_path=output, + ioc_files=iocs, module_name=module) + if list_modules: + cmd.list_modules() return - log.info("Checking an Android Bug Report located at: %s", bugreport_path) - - if output and not os.path.exists(output): - try: - os.makedirs(output) - except Exception as e: - log.critical("Unable to create output folder %s: %s", output, e) - ctx.exit(1) - - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - if os.path.isfile(bugreport_path): - bugreport_format = "zip" - zip_archive = ZipFile(bugreport_path) - zip_files = [] - for file_name in zip_archive.namelist(): - zip_files.append(file_name) - elif os.path.isdir(bugreport_path): - bugreport_format = "dir" - folder_files = [] - parent_path = Path(bugreport_path).absolute().as_posix() - for root, subdirs, subfiles in os.walk(os.path.abspath(bugreport_path)): - for file_name in subfiles: - folder_files.append(os.path.relpath(os.path.join(root, file_name), parent_path)) - - timeline = [] - timeline_detected = [] - for bugreport_module in BUGREPORT_MODULES: - if module and bugreport_module.__name__ != module: - continue - - m = bugreport_module(base_folder=bugreport_path, output_folder=output, - log=logging.getLogger(bugreport_module.__module__)) - - if bugreport_format == "zip": - m.from_zip(zip_archive, zip_files) - else: - m.from_folder(bugreport_path, folder_files) - - if indicators.total_ioc_count: - m.indicators = indicators - m.indicators.log = m.log - - run_module(m) - timeline.extend(m.timeline) - timeline_detected.extend(m.timeline_detected) - - if output: - if len(timeline) > 0: - save_timeline(timeline, os.path.join(output, "timeline.csv")) - if len(timeline_detected) > 0: - save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv")) + cmd.run() #============================================================================== @@ -248,74 +155,18 @@ def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path): @click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True, default=[], help=HELP_MSG_IOC) @click.option("--output", "-o", type=click.Path(exists=False), help=HELP_MSG_OUTPUT) +@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.argument("BACKUP_PATH", type=click.Path(exists=True)) @click.pass_context -def check_backup(ctx, iocs, output, backup_path, serial): - log.info("Checking ADB backup located at: %s", backup_path) +def check_backup(ctx, iocs, output, list_modules, backup_path, serial): + cmd = CmdAndroidCheckBackup(target_path=backup_path, results_path=output, + ioc_files=iocs) - if os.path.isfile(backup_path): - # AB File - backup_type = "ab" - with open(backup_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") - ctx.exit(1) - password = None - if header["encryption"] != "none": - password = getpass.getpass(prompt="Backup Password: ", stream=None) - try: - tardata = parse_backup_file(data, password=password) - except InvalidBackupPassword: - log.critical("Invalid backup password") - ctx.exit(1) - except AndroidBackupParsingError: - log.critical("Impossible to parse this backup file, please use Android Backup Extractor instead") - ctx.exit(1) + if list_modules: + cmd.list_modules() + return - dbytes = io.BytesIO(tardata) - tar = tarfile.open(fileobj=dbytes) - files = [] - for member in tar: - files.append(member.name) - - elif os.path.isdir(backup_path): - backup_type = "folder" - backup_path = Path(backup_path).absolute().as_posix() - files = [] - 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)) - else: - log.critical("Invalid backup path, path should be a folder or an Android Backup (.ab) file") - ctx.exit(1) - - if output and not os.path.exists(output): - try: - os.makedirs(output) - except Exception as e: - log.critical("Unable to create output folder %s: %s", output, e) - ctx.exit(1) - - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - for module in BACKUP_MODULES: - m = module(base_folder=backup_path, output_folder=output, - log=logging.getLogger(module.__module__)) - if indicators.total_ioc_count: - m.indicators = indicators - m.indicators.log = m.log - if serial: - m.serial = serial - - if backup_type == "folder": - m.from_folder(backup_path, files) - else: - m.from_ab(backup_path, tar, files) - - run_module(m) + cmd.run() #============================================================================== diff --git a/mvt/android/cmd_check_adb.py b/mvt/android/cmd_check_adb.py new file mode 100644 index 0000000..b8ac374 --- /dev/null +++ b/mvt/android/cmd_check_adb.py @@ -0,0 +1,24 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging + +from mvt.common.command import Command + +from .modules.adb import ADB_MODULES + +log = logging.getLogger(__name__) + + +class CmdAndroidCheckADB(Command): + + name = "check-adb" + modules = ADB_MODULES + + def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, + serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, ioc_files=ioc_files, + module_name=module_name, serial=serial, + fast_mode=fast_mode, log=log) diff --git a/mvt/android/cmd_check_backup.py b/mvt/android/cmd_check_backup.py new file mode 100644 index 0000000..391130d --- /dev/null +++ b/mvt/android/cmd_check_backup.py @@ -0,0 +1,82 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import getpass +import io +import logging +import os +import sys +import tarfile +from pathlib import Path + +from mvt.android.parsers.backup import (AndroidBackupParsingError, + InvalidBackupPassword, parse_ab_header, + parse_backup_file) +from mvt.common.command import Command + +from .modules.backup import BACKUP_MODULES + +log = logging.getLogger(__name__) + + +class CmdAndroidCheckBackup(Command): + + name = "check-backup" + modules = BACKUP_MODULES + + def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, + serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, ioc_files=ioc_files, + module_name=module_name, serial=serial, + fast_mode=fast_mode, log=log) + + self.backup_type = None + self.backup_archive = None + self.backup_files = [] + + def init(self): + 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 = getpass.getpass(prompt="Backup Password: ", stream=None) + try: + tardata = parse_backup_file(data, password=password) + except InvalidBackupPassword: + log.critical("Invalid backup password") + sys.exit(1) + except AndroidBackupParsingError as e: + log.critical("Impossible to parse this backup file: %s", e) + 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) + + elif os.path.isdir(self.target_path): + self.backup_type = "folder" + self.target_path = Path(self.target_path).absolute().as_posix() + for root, subdirs, subfiles in os.walk(os.path.abspath(self.target_path)): + for fname in subfiles: + self.backup_files.append(os.path.relpath(os.path.join(root, fname), self.target_path)) + else: + log.critical("Invalid backup path, path should be a folder or an Android Backup (.ab) file") + sys.exit(1) + + def module_init(self, module): + if self.backup_type == "folder": + module.from_folder(self.target_path, self.backup_files) + else: + module.from_ab(self.target_path, self.backup_archive, self.backup_files) diff --git a/mvt/android/cmd_check_bugreport.py b/mvt/android/cmd_check_bugreport.py new file mode 100644 index 0000000..58f5aba --- /dev/null +++ b/mvt/android/cmd_check_bugreport.py @@ -0,0 +1,50 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging +import os +from pathlib import Path +from zipfile import ZipFile + +from mvt.common.command import Command + +from .modules.bugreport import BUGREPORT_MODULES + +log = logging.getLogger(__name__) + + +class CmdAndroidCheckBugreport(Command): + + name = "check-bugreport" + modules = BUGREPORT_MODULES + + def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, + serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, ioc_files=ioc_files, + module_name=module_name, serial=serial, + fast_mode=fast_mode, log=log) + + self.bugreport_format = None + self.bugreport_archive = None + self.bugreport_files = [] + + def init(self): + 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) + elif os.path.isdir(self.target_path): + self.bugreport_format = "dir" + parent_path = Path(self.target_path).absolute().as_posix() + for root, subdirs, subfiles in os.walk(os.path.abspath(self.target_path)): + for file_name in subfiles: + self.bugreport_files.append(os.path.relpath(os.path.join(root, file_name), parent_path)) + + def module_init(self, module): + if self.bugreport_format == "zip": + module.from_zip(self.bugreport_archive, self.bugreport_files) + else: + module.from_folder(self.target_path, self.bugreport_files) diff --git a/mvt/android/download_apks.py b/mvt/android/cmd_download_apks.py similarity index 100% rename from mvt/android/download_apks.py rename to mvt/android/cmd_download_apks.py diff --git a/mvt/android/modules/adb/base.py b/mvt/android/modules/adb/base.py index 4f01eaf..5134325 100644 --- a/mvt/android/modules/adb/base.py +++ b/mvt/android/modules/adb/base.py @@ -33,10 +33,10 @@ ADB_PUB_KEY_PATH = os.path.expanduser("~/.android/adbkey.pub") class AndroidExtraction(MVTModule): """This class provides a base for all Android extraction modules.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.device = None diff --git a/mvt/android/modules/adb/chrome_history.py b/mvt/android/modules/adb/chrome_history.py index 58040c3..f9315b3 100644 --- a/mvt/android/modules/adb/chrome_history.py +++ b/mvt/android/modules/adb/chrome_history.py @@ -20,10 +20,10 @@ CHROME_HISTORY_PATH = "data/data/com.android.chrome/app_chrome/Default/History" class ChromeHistory(AndroidExtraction): """This module extracts records from Android's Chrome browsing history.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/adb/dumpsys_accessibility.py b/mvt/android/modules/adb/dumpsys_accessibility.py index a78aab5..20651b4 100644 --- a/mvt/android/modules/adb/dumpsys_accessibility.py +++ b/mvt/android/modules/adb/dumpsys_accessibility.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class DumpsysAccessibility(AndroidExtraction): """This module extracts stats on accessibility.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/adb/dumpsys_activities.py b/mvt/android/modules/adb/dumpsys_activities.py index e3e6abf..5a0311e 100644 --- a/mvt/android/modules/adb/dumpsys_activities.py +++ b/mvt/android/modules/adb/dumpsys_activities.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class DumpsysActivities(AndroidExtraction): """This module extracts details on receivers for risky activities.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = results if results else {} diff --git a/mvt/android/modules/adb/dumpsys_appops.py b/mvt/android/modules/adb/dumpsys_appops.py index ac922b1..1019102 100644 --- a/mvt/android/modules/adb/dumpsys_appops.py +++ b/mvt/android/modules/adb/dumpsys_appops.py @@ -4,7 +4,6 @@ # https://license.mvt.re/1.1/ import logging -import re from mvt.android.parsers.dumpsys import parse_dumpsys_appops @@ -18,10 +17,10 @@ class DumpsysAppOps(AndroidExtraction): slug = "dumpsys_appops" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/adb/dumpsys_battery_daily.py b/mvt/android/modules/adb/dumpsys_battery_daily.py index 9b20103..9b83c3d 100644 --- a/mvt/android/modules/adb/dumpsys_battery_daily.py +++ b/mvt/android/modules/adb/dumpsys_battery_daily.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class DumpsysBatteryDaily(AndroidExtraction): """This module extracts records from battery daily updates.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/adb/dumpsys_battery_history.py b/mvt/android/modules/adb/dumpsys_battery_history.py index 9d7aef3..c69d080 100644 --- a/mvt/android/modules/adb/dumpsys_battery_history.py +++ b/mvt/android/modules/adb/dumpsys_battery_history.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class DumpsysBatteryHistory(AndroidExtraction): """This module extracts records from battery history events.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/adb/dumpsys_dbinfo.py b/mvt/android/modules/adb/dumpsys_dbinfo.py index 6b2a7f9..44a78ce 100644 --- a/mvt/android/modules/adb/dumpsys_dbinfo.py +++ b/mvt/android/modules/adb/dumpsys_dbinfo.py @@ -4,7 +4,6 @@ # https://license.mvt.re/1.1/ import logging -import re from mvt.android.parsers import parse_dumpsys_dbinfo @@ -18,10 +17,10 @@ class DumpsysDBInfo(AndroidExtraction): slug = "dumpsys_dbinfo" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/adb/dumpsys_full.py b/mvt/android/modules/adb/dumpsys_full.py index a762576..ba39e55 100644 --- a/mvt/android/modules/adb/dumpsys_full.py +++ b/mvt/android/modules/adb/dumpsys_full.py @@ -14,18 +14,18 @@ log = logging.getLogger(__name__) class DumpsysFull(AndroidExtraction): """This module extracts stats on battery consumption by processes.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): self._adb_connect() output = self._adb_command("dumpsys") - if self.output_folder: - output_path = os.path.join(self.output_folder, "dumpsys.txt") + if self.results_path: + output_path = os.path.join(self.results_path, "dumpsys.txt") with open(output_path, "w", encoding="utf-8") as handle: handle.write(output) diff --git a/mvt/android/modules/adb/dumpsys_receivers.py b/mvt/android/modules/adb/dumpsys_receivers.py index b285ca4..c58c009 100644 --- a/mvt/android/modules/adb/dumpsys_receivers.py +++ b/mvt/android/modules/adb/dumpsys_receivers.py @@ -21,10 +21,10 @@ INTENT_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL" class DumpsysReceivers(AndroidExtraction): """This module extracts details on receivers for risky activities.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = results if results else {} diff --git a/mvt/android/modules/adb/files.py b/mvt/android/modules/adb/files.py index 0344ccd..08f4de5 100644 --- a/mvt/android/modules/adb/files.py +++ b/mvt/android/modules/adb/files.py @@ -17,10 +17,10 @@ log = logging.getLogger(__name__) class Files(AndroidExtraction): """This module extracts the list of files on the device.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.full_find = False diff --git a/mvt/android/modules/adb/getprop.py b/mvt/android/modules/adb/getprop.py index e5b370a..657b9b8 100644 --- a/mvt/android/modules/adb/getprop.py +++ b/mvt/android/modules/adb/getprop.py @@ -4,7 +4,6 @@ # https://license.mvt.re/1.1/ import logging -import re from datetime import datetime, timedelta from mvt.android.parsers import parse_getprop @@ -17,10 +16,10 @@ log = logging.getLogger(__name__) class Getprop(AndroidExtraction): """This module extracts device properties from getprop command.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} if not results else results diff --git a/mvt/android/modules/adb/logcat.py b/mvt/android/modules/adb/logcat.py index cc89b83..d06f80a 100644 --- a/mvt/android/modules/adb/logcat.py +++ b/mvt/android/modules/adb/logcat.py @@ -14,10 +14,10 @@ log = logging.getLogger(__name__) class Logcat(AndroidExtraction): """This module extracts details on installed packages.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): @@ -28,8 +28,8 @@ class Logcat(AndroidExtraction): # Get the locat prior to last reboot. last_output = self._adb_command("logcat -L") - if self.output_folder: - logcat_path = os.path.join(self.output_folder, + if self.results_path: + logcat_path = os.path.join(self.results_path, "logcat.txt") with open(logcat_path, "w", encoding="utf-8") as handle: handle.write(output) @@ -37,7 +37,7 @@ class Logcat(AndroidExtraction): log.info("Current logcat logs stored at %s", logcat_path) - logcat_last_path = os.path.join(self.output_folder, + logcat_last_path = os.path.join(self.results_path, "logcat_last.txt") with open(logcat_last_path, "w", encoding="utf-8") as handle: handle.write(last_output) diff --git a/mvt/android/modules/adb/packages.py b/mvt/android/modules/adb/packages.py index b07348a..ddec724 100644 --- a/mvt/android/modules/adb/packages.py +++ b/mvt/android/modules/adb/packages.py @@ -4,9 +4,7 @@ # https://license.mvt.re/1.1/ import logging -import os -import pkg_resources from rich.console import Console from rich.progress import track from rich.table import Table @@ -74,10 +72,10 @@ ROOT_PACKAGES = [ class Packages(AndroidExtraction): """This module extracts the list of installed packages.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/adb/processes.py b/mvt/android/modules/adb/processes.py index be94594..5843b61 100644 --- a/mvt/android/modules/adb/processes.py +++ b/mvt/android/modules/adb/processes.py @@ -13,10 +13,10 @@ log = logging.getLogger(__name__) class Processes(AndroidExtraction): """This module extracts details on running processes.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/adb/root_binaries.py b/mvt/android/modules/adb/root_binaries.py index 03acf1a..a9dedec 100644 --- a/mvt/android/modules/adb/root_binaries.py +++ b/mvt/android/modules/adb/root_binaries.py @@ -13,10 +13,10 @@ log = logging.getLogger(__name__) class RootBinaries(AndroidExtraction): """This module extracts the list of installed packages.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): diff --git a/mvt/android/modules/adb/selinux_status.py b/mvt/android/modules/adb/selinux_status.py index 0c97ffa..c0169ec 100644 --- a/mvt/android/modules/adb/selinux_status.py +++ b/mvt/android/modules/adb/selinux_status.py @@ -4,9 +4,6 @@ # https://license.mvt.re/1.1/ import logging -import os - -import pkg_resources from .base import AndroidExtraction @@ -18,10 +15,10 @@ class SELinuxStatus(AndroidExtraction): slug = "selinux_status" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} if not results else results diff --git a/mvt/android/modules/adb/settings.py b/mvt/android/modules/adb/settings.py index bd6cb35..9e6a5f6 100644 --- a/mvt/android/modules/adb/settings.py +++ b/mvt/android/modules/adb/settings.py @@ -57,10 +57,10 @@ ANDROID_DANGEROUS_SETTINGS = [ class Settings(AndroidExtraction): """This module extracts Android system settings.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} if not results else results diff --git a/mvt/android/modules/adb/sms.py b/mvt/android/modules/adb/sms.py index c2b4f1b..aceffc9 100644 --- a/mvt/android/modules/adb/sms.py +++ b/mvt/android/modules/adb/sms.py @@ -3,8 +3,6 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ -import base64 -import getpass import logging import os import sqlite3 @@ -48,10 +46,10 @@ FROM sms; class SMS(AndroidExtraction): """This module extracts all SMS messages containing links.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/adb/whatsapp.py b/mvt/android/modules/adb/whatsapp.py index 2f3f6d1..9d4c544 100644 --- a/mvt/android/modules/adb/whatsapp.py +++ b/mvt/android/modules/adb/whatsapp.py @@ -20,10 +20,10 @@ WHATSAPP_PATH = "data/data/com.whatsapp/databases/msgstore.db" class Whatsapp(AndroidExtraction): """This module extracts all WhatsApp messages containing links.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/backup/sms.py b/mvt/android/modules/backup/sms.py index 4a35093..e06dc53 100644 --- a/mvt/android/modules/backup/sms.py +++ b/mvt/android/modules/backup/sms.py @@ -5,14 +5,13 @@ from mvt.android.modules.backup.base import BackupExtraction from mvt.android.parsers.backup import parse_sms_file -from mvt.common.utils import check_for_links class SMS(BackupExtraction): - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = [] diff --git a/mvt/android/modules/bugreport/accessibility.py b/mvt/android/modules/bugreport/accessibility.py index bf0e1ff..cb001e8 100644 --- a/mvt/android/modules/bugreport/accessibility.py +++ b/mvt/android/modules/bugreport/accessibility.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class Accessibility(BugReportModule): """This module extracts stats on accessibility.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/bugreport/activities.py b/mvt/android/modules/bugreport/activities.py index 30bf5f8..6bc0fdd 100644 --- a/mvt/android/modules/bugreport/activities.py +++ b/mvt/android/modules/bugreport/activities.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class Activities(BugReportModule): """This module extracts details on receivers for risky activities.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = results if results else {} diff --git a/mvt/android/modules/bugreport/appops.py b/mvt/android/modules/bugreport/appops.py index ba48522..63b381f 100644 --- a/mvt/android/modules/bugreport/appops.py +++ b/mvt/android/modules/bugreport/appops.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class Appops(BugReportModule): """This module extracts information on package from App-Ops Manager.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/bugreport/battery_daily.py b/mvt/android/modules/bugreport/battery_daily.py index a687f97..93eab5e 100644 --- a/mvt/android/modules/bugreport/battery_daily.py +++ b/mvt/android/modules/bugreport/battery_daily.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class BatteryDaily(BugReportModule): """This module extracts records from battery daily updates.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/bugreport/battery_history.py b/mvt/android/modules/bugreport/battery_history.py index f25585a..0dd0ff7 100644 --- a/mvt/android/modules/bugreport/battery_history.py +++ b/mvt/android/modules/bugreport/battery_history.py @@ -15,10 +15,10 @@ log = logging.getLogger(__name__) class BatteryHistory(BugReportModule): """This module extracts records from battery daily updates.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/bugreport/dbinfo.py b/mvt/android/modules/bugreport/dbinfo.py index abf1a00..07d2d28 100644 --- a/mvt/android/modules/bugreport/dbinfo.py +++ b/mvt/android/modules/bugreport/dbinfo.py @@ -17,10 +17,10 @@ class DBInfo(BugReportModule): slug = "dbinfo" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def check_indicators(self): diff --git a/mvt/android/modules/bugreport/getprop.py b/mvt/android/modules/bugreport/getprop.py index f5ee4a2..3783c59 100644 --- a/mvt/android/modules/bugreport/getprop.py +++ b/mvt/android/modules/bugreport/getprop.py @@ -4,7 +4,6 @@ # https://license.mvt.re/1.1/ import logging -import re from datetime import datetime, timedelta from mvt.android.parsers import parse_getprop @@ -17,10 +16,10 @@ log = logging.getLogger(__name__) class Getprop(BugReportModule): """This module extracts device properties from getprop command.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} if not results else results diff --git a/mvt/android/modules/bugreport/packages.py b/mvt/android/modules/bugreport/packages.py index 397901b..4137ae0 100644 --- a/mvt/android/modules/bugreport/packages.py +++ b/mvt/android/modules/bugreport/packages.py @@ -14,10 +14,10 @@ log = logging.getLogger(__name__) class Packages(BugReportModule): """This module extracts details on receivers for risky activities.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/android/modules/bugreport/receivers.py b/mvt/android/modules/bugreport/receivers.py index 7f56f25..3c2b069 100644 --- a/mvt/android/modules/bugreport/receivers.py +++ b/mvt/android/modules/bugreport/receivers.py @@ -21,10 +21,10 @@ INTENT_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL" class Receivers(BugReportModule): """This module extracts details on receivers for risky activities.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, serial=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = results if results else {} diff --git a/mvt/android/parsers/backup.py b/mvt/android/parsers/backup.py index 8f9a0d7..4915fb0 100644 --- a/mvt/android/parsers/backup.py +++ b/mvt/android/parsers/backup.py @@ -70,11 +70,11 @@ def decrypt_master_key(password, user_salt, user_iv, pbkdf2_rounds, master_key_b The backup master key is extracted from the master key blog after decryption. """ - # Derive key from password using PBKDF2 + # Derive key from password using PBKDF2. kdf = PBKDF2HMAC(algorithm=hashes.SHA1(), length=32, salt=user_salt, iterations=pbkdf2_rounds) key = kdf.derive(password.encode("utf-8")) - # Decrypt master key blob + # Decrypt master key blob. cipher = Cipher(algorithms.AES(key), modes.CBC(user_iv)) decryptor = cipher.decryptor() try: @@ -93,7 +93,7 @@ def decrypt_master_key(password, user_salt, user_iv, pbkdf2_rounds, master_key_b except TypeError: raise InvalidBackupPassword() - # Handle quirky encoding of master key bytes in Android original Java crypto code + # Handle quirky encoding of master key bytes in Android original Java crypto code. if format_version > 1: hmac_mk = to_utf8_bytes(master_key) else: @@ -112,6 +112,7 @@ def decrypt_master_key(password, user_salt, user_iv, pbkdf2_rounds, master_key_b def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_version): """ Generate encryption keyffrom password and do decryption + """ if encryption_algo != b"AES-256": raise AndroidBackupNotImplemented("Encryption Algorithm not implemented") @@ -126,12 +127,12 @@ def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_vers user_iv = bytes.fromhex(user_iv.decode("utf-8")) master_key_blob = bytes.fromhex(master_key_blob.decode("utf-8")) - # Derive decryption master key from password + # Derive decryption master key from password. master_key, master_iv = decrypt_master_key(password=password, user_salt=user_salt, user_iv=user_iv, pbkdf2_rounds=pbkdf2_rounds, master_key_blob=master_key_blob, format_version=format_version, checksum_salt=checksum_salt) - # Decrypt and unpad backup data using derivied key + # Decrypt and unpad backup data using derivied key. cipher = Cipher(algorithms.AES(master_key), modes.CBC(master_iv)) decryptor = cipher.decryptor() decrypted_tar = decryptor.update(encrypted_data) + decryptor.finalize() @@ -143,6 +144,7 @@ def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_vers def parse_backup_file(data, password=None): """ Parse an ab file, returns a tar file + """ if not data.startswith(b"ANDROID BACKUP"): raise AndroidBackupParsingError("Invalid file header") diff --git a/mvt/common/command.py b/mvt/common/command.py new file mode 100644 index 0000000..fbfd3c2 --- /dev/null +++ b/mvt/common/command.py @@ -0,0 +1,94 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging +import os +import sys + +from mvt.common.indicators import Indicators +from mvt.common.module import run_module, save_timeline + + +class Command(object): + + def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, + serial=None, fast_mode=False, log=logging.getLogger(__name__)): + self.target_path = target_path + self.results_path = results_path + self.ioc_files = ioc_files + self.module_name = module_name + self.serial = serial + self.fast_mode = fast_mode + self.log = log + + self.iocs = Indicators(log=log) + self.iocs.load_indicators_files(ioc_files) + + self.timeline = [] + self.timeline_detected = [] + + def list_modules(self): + self.log.info("Following is the list of available %s modules:", self.name) + for module in self.modules: + self.log.info(" - %s", module.__name__) + + def _create_storage(self): + if self.results_path and not os.path.exists(self.results_path): + try: + os.makedirs(self.results_path) + except Exception as e: + self.log.critical("Unable to create output folder %s: %s", + self.results_path, e) + sys.exit(1) + + def _store_timeline(self): + if self.results_path: + if len(self.timeline) > 0: + save_timeline(self.timeline, + os.path.join(self.results_path, "timeline.csv")) + + if len(self.timeline_detected) > 0: + save_timeline(self.timeline_detected, + os.path.join(self.results_path, "timeline_detected.csv")) + + def init(self): + raise NotImplementedError + + def module_init(self, module): + raise NotImplementedError + + def run(self): + self._create_storage() + + try: + self.init() + except NotImplementedError: + pass + + for module in self.modules: + if self.module_name and module.__name__ != self.module_name: + continue + + m = module(target_path=self.target_path, results_path=self.results_path, fast_mode=self.fast_mode, + log=logging.getLogger(module.__module__)) + + if self.iocs.total_ioc_count: + m.indicators = self.iocs + m.indicators.log = m.log + + if self.serial: + m.serial = self.serial + + try: + self.module_init(m) + except NotImplementedError: + pass + + run_module(m) + + self.timeline.extend(m.timeline) + self.timeline_detected.extend(m.timeline_detected) + + self._store_timeline() diff --git a/mvt/common/module.py b/mvt/common/module.py index 63832b7..59855c9 100644 --- a/mvt/common/module.py +++ b/mvt/common/module.py @@ -28,16 +28,16 @@ class MVTModule(object): enabled = True slug = None - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=None): """Initialize module. :param file_path: Path to the module's database file, if there is any :type file_path: str - :param base_folder: Path to the base folder (backup or filesystem dump) + :param target_path: Path to the target folder (backup or filesystem dump) :type file_path: str - :param output_folder: Folder where results will be stored - :type output_folder: str + :param results_path: Folder where results will be stored + :type results_path: str :param fast_mode: Flag to enable or disable slow modules :type fast_mode: bool :param log: Handle to logger @@ -45,8 +45,8 @@ class MVTModule(object): :type results: list """ self.file_path = file_path - self.base_folder = base_folder - self.output_folder = output_folder + self.target_path = target_path + self.results_path = results_path self.fast_mode = fast_mode self.log = log self.indicators = None @@ -82,14 +82,14 @@ class MVTModule(object): def save_to_json(self): """Save the collected results to a json file.""" - if not self.output_folder: + if not self.results_path: return name = self.get_slug() if self.results: results_file_name = f"{name}.json" - results_json_path = os.path.join(self.output_folder, results_file_name) + results_json_path = os.path.join(self.results_path, results_file_name) with open(results_json_path, "w", encoding="utf-8") as handle: try: json.dump(self.results, handle, indent=4, default=str) @@ -99,7 +99,7 @@ class MVTModule(object): if self.detected: detected_file_name = f"{name}_detected.json" - detected_json_path = os.path.join(self.output_folder, detected_file_name) + detected_json_path = os.path.join(self.results_path, detected_file_name) with open(detected_json_path, "w", encoding="utf-8") as handle: json.dump(self.detected, handle, indent=4, default=str) diff --git a/setup.cfg b/setup.cfg index a47b7a8..9f91876 100644 --- a/setup.cfg +++ b/setup.cfg @@ -48,7 +48,7 @@ max-line-length = 1000 ignore = C901, E265, - E127, F401, + E127, W503, E226 diff --git a/tests/android/test_backup_parser.py b/tests/android/test_backup_parser.py index 42a0514..d1360a8 100644 --- a/tests/android/test_backup_parser.py +++ b/tests/android/test_backup_parser.py @@ -4,7 +4,6 @@ # https://license.mvt.re/1.1/ import hashlib -import logging from mvt.android.parsers.backup import parse_backup_file, parse_tar_for_sms diff --git a/tests/android/test_bugreport_appops.py b/tests/android/test_bugreport_appops.py index d44ad76..abccdb5 100644 --- a/tests/android/test_bugreport_appops.py +++ b/tests/android/test_bugreport_appops.py @@ -8,7 +8,6 @@ import os from pathlib import Path from mvt.android.modules.bugreport.appops import Appops -from mvt.common.indicators import Indicators from mvt.common.module import run_module from ..utils import get_artifact_folder diff --git a/tests/android/test_dumpsys_parser.py b/tests/android/test_dumpsys_parser.py index b261d27..f535a73 100644 --- a/tests/android/test_dumpsys_parser.py +++ b/tests/android/test_dumpsys_parser.py @@ -3,9 +3,6 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ -import hashlib -import logging - from mvt.android.parsers.dumpsys import parse_dumpsys_appops from ..utils import get_artifact From c54a01ca597b4d1a017bb0c6f5480dc4217d36cf Mon Sep 17 00:00:00 2001 From: Nex Date: Thu, 16 Jun 2022 15:01:07 +0200 Subject: [PATCH 2/6] Fixing exceeding lines length --- mvt/android/cmd_check_adb.py | 10 +++++----- mvt/android/cmd_check_backup.py | 10 +++++----- mvt/android/cmd_check_bugreport.py | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mvt/android/cmd_check_adb.py b/mvt/android/cmd_check_adb.py index b8ac374..ca8aefe 100644 --- a/mvt/android/cmd_check_adb.py +++ b/mvt/android/cmd_check_adb.py @@ -17,8 +17,8 @@ class CmdAndroidCheckADB(Command): name = "check-adb" modules = ADB_MODULES - def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, - serial=None, fast_mode=False): - super().__init__(target_path=target_path, results_path=results_path, ioc_files=ioc_files, - module_name=module_name, serial=serial, - fast_mode=fast_mode, log=log) + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, + ioc_files=ioc_files, module_name=module_name, + serial=serial, fast_mode=fast_mode, log=log) diff --git a/mvt/android/cmd_check_backup.py b/mvt/android/cmd_check_backup.py index 391130d..82ba1cc 100644 --- a/mvt/android/cmd_check_backup.py +++ b/mvt/android/cmd_check_backup.py @@ -26,11 +26,11 @@ class CmdAndroidCheckBackup(Command): name = "check-backup" modules = BACKUP_MODULES - def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, - serial=None, fast_mode=False): - super().__init__(target_path=target_path, results_path=results_path, ioc_files=ioc_files, - module_name=module_name, serial=serial, - fast_mode=fast_mode, log=log) + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, + ioc_files=ioc_files, module_name=module_name, + serial=serial, fast_mode=fast_mode, log=log) self.backup_type = None self.backup_archive = None diff --git a/mvt/android/cmd_check_bugreport.py b/mvt/android/cmd_check_bugreport.py index 58f5aba..4f13b67 100644 --- a/mvt/android/cmd_check_bugreport.py +++ b/mvt/android/cmd_check_bugreport.py @@ -20,11 +20,11 @@ class CmdAndroidCheckBugreport(Command): name = "check-bugreport" modules = BUGREPORT_MODULES - def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, - serial=None, fast_mode=False): - super().__init__(target_path=target_path, results_path=results_path, ioc_files=ioc_files, - module_name=module_name, serial=serial, - fast_mode=fast_mode, log=log) + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, + ioc_files=ioc_files, module_name=module_name, + serial=serial, fast_mode=fast_mode, log=log) self.bugreport_format = None self.bugreport_archive = None From e7fe30e20195b29dd61a397fd9669cb58097a18b Mon Sep 17 00:00:00 2001 From: Nex Date: Thu, 16 Jun 2022 15:18:50 +0200 Subject: [PATCH 3/6] Refactoring cli commands for iOS too --- mvt/android/cli.py | 6 +- mvt/ios/cli.py | 98 ++++--------------- mvt/ios/cmd_check_backup.py | 25 +++++ mvt/ios/cmd_check_fs.py | 25 +++++ mvt/ios/modules/backup/backup_info.py | 8 +- .../modules/backup/configuration_profiles.py | 6 +- mvt/ios/modules/backup/manifest.py | 8 +- mvt/ios/modules/backup/profile_events.py | 6 +- mvt/ios/modules/base.py | 12 +-- mvt/ios/modules/fs/analytics.py | 6 +- mvt/ios/modules/fs/cache_files.py | 10 +- mvt/ios/modules/fs/filesystem.py | 12 +-- mvt/ios/modules/fs/net_netusage.py | 6 +- mvt/ios/modules/fs/safari_favicon.py | 6 +- mvt/ios/modules/fs/shutdownlog.py | 6 +- mvt/ios/modules/fs/version_history.py | 6 +- mvt/ios/modules/fs/webkit_base.py | 2 +- mvt/ios/modules/fs/webkit_indexeddb.py | 6 +- mvt/ios/modules/fs/webkit_localstorage.py | 6 +- .../modules/fs/webkit_safariviewservice.py | 6 +- mvt/ios/modules/mixed/calls.py | 6 +- mvt/ios/modules/mixed/chrome_favicon.py | 6 +- mvt/ios/modules/mixed/chrome_history.py | 6 +- mvt/ios/modules/mixed/contacts.py | 6 +- mvt/ios/modules/mixed/firefox_favicon.py | 6 +- mvt/ios/modules/mixed/firefox_history.py | 6 +- mvt/ios/modules/mixed/idstatuscache.py | 6 +- mvt/ios/modules/mixed/interactionc.py | 6 +- mvt/ios/modules/mixed/locationd.py | 6 +- mvt/ios/modules/mixed/net_datausage.py | 6 +- mvt/ios/modules/mixed/osanalytics_addaily.py | 6 +- mvt/ios/modules/mixed/safari_browserstate.py | 8 +- mvt/ios/modules/mixed/safari_history.py | 8 +- mvt/ios/modules/mixed/shortcuts.py | 6 +- mvt/ios/modules/mixed/sms.py | 6 +- mvt/ios/modules/mixed/sms_attachments.py | 6 +- mvt/ios/modules/mixed/tcc.py | 6 +- .../mixed/webkit_resource_load_statistics.py | 8 +- .../mixed/webkit_session_resource_log.py | 8 +- mvt/ios/modules/mixed/whatsapp.py | 6 +- mvt/ios/modules/net_base.py | 8 +- 41 files changed, 195 insertions(+), 207 deletions(-) create mode 100644 mvt/ios/cmd_check_backup.py create mode 100644 mvt/ios/cmd_check_fs.py diff --git a/mvt/android/cli.py b/mvt/android/cli.py index d8bd05b..8cba92c 100644 --- a/mvt/android/cli.py +++ b/mvt/android/cli.py @@ -9,15 +9,15 @@ import os import click from rich.logging import RichHandler -from mvt.android.cmd_check_adb import CmdAndroidCheckADB -from mvt.android.cmd_check_backup import CmdAndroidCheckBackup -from mvt.android.cmd_check_bugreport import CmdAndroidCheckBugreport from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_OUTPUT, HELP_MSG_SERIAL) from mvt.common.indicators import Indicators, download_indicators_files from mvt.common.logo import logo +from .cmd_check_adb import CmdAndroidCheckADB +from .cmd_check_backup import CmdAndroidCheckBackup +from .cmd_check_bugreport import CmdAndroidCheckBugreport from .cmd_download_apks import DownloadAPKs from .modules.adb import ADB_MODULES from .modules.adb.packages import Packages diff --git a/mvt/ios/cli.py b/mvt/ios/cli.py index 951b241..26bba39 100644 --- a/mvt/ios/cli.py +++ b/mvt/ios/cli.py @@ -15,9 +15,10 @@ from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, HELP_MSG_OUTPUT) from mvt.common.indicators import Indicators, download_indicators_files from mvt.common.logo import logo -from mvt.common.module import run_module, save_timeline from mvt.common.options import MutuallyExclusiveOption +from .cmd_check_backup import CmdIOSCheckBackup +from .cmd_check_fs import CmdIOSCheckFS from .decrypt import DecryptBackup from .modules.backup import BACKUP_MODULES from .modules.fs import FS_MODULES @@ -140,51 +141,20 @@ def extract_key(password, backup_path, key_file): @click.argument("BACKUP_PATH", type=click.Path(exists=True)) @click.pass_context def check_backup(ctx, iocs, output, fast, backup_path, list_modules, module): - if list_modules: - log.info("Following is the list of available check-backup modules:") - for backup_module in BACKUP_MODULES + MIXED_MODULES: - log.info(" - %s", backup_module.__name__) + cmd = CmdIOSCheckBackup(target_path=backup_path, results_path=output, + ioc_files=iocs, module_name=module, fast_mode=fast) + if list_modules: + cmd.list_modules() return log.info("Checking iTunes backup located at: %s", backup_path) - if output and not os.path.exists(output): - try: - os.makedirs(output) - except Exception as e: - log.critical("Unable to create output folder %s: %s", output, e) - ctx.exit(1) + cmd.run() - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - timeline = [] - timeline_detected = [] - for backup_module in BACKUP_MODULES + MIXED_MODULES: - if module and backup_module.__name__ != module: - continue - - m = backup_module(base_folder=backup_path, output_folder=output, fast_mode=fast, - log=logging.getLogger(backup_module.__module__)) - m.is_backup = True - if indicators.total_ioc_count > 0: - m.indicators = indicators - m.indicators.log = m.log - - run_module(m) - timeline.extend(m.timeline) - timeline_detected.extend(m.timeline_detected) - - if output: - if len(timeline) > 0: - save_timeline(timeline, os.path.join(output, "timeline.csv")) - if len(timeline_detected) > 0: - save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv")) - - if len(timeline_detected) > 0: + if len(cmd.timeline_detected) > 0: log.warning("The analysis of the backup produced %d detections!", - len(timeline_detected)) + len(cmd.timeline_detected)) #============================================================================== @@ -200,52 +170,20 @@ def check_backup(ctx, iocs, output, fast, backup_path, list_modules, module): @click.argument("DUMP_PATH", type=click.Path(exists=True)) @click.pass_context def check_fs(ctx, iocs, output, fast, dump_path, list_modules, module): - if list_modules: - log.info("Following is the list of available check-fs modules:") - for fs_module in FS_MODULES + MIXED_MODULES: - log.info(" - %s", fs_module.__name__) + cmd = CmdIOSCheckFS(target_path=dump_path, results_path=output, + ioc_files=iocs, module_name=module, fast_mode=fast) + if list_modules: + cmd.list_modules() return - log.info("Checking filesystem dump located at: %s", dump_path) + log.info("Checking iOS filesystem located at: %s", dump_path) - if output and not os.path.exists(output): - try: - os.makedirs(output) - except Exception as e: - log.critical("Unable to create output folder %s: %s", output, e) - ctx.exit(1) + cmd.run() - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - timeline = [] - timeline_detected = [] - for fs_module in FS_MODULES + MIXED_MODULES: - if module and fs_module.__name__ != module: - continue - - m = fs_module(base_folder=dump_path, output_folder=output, fast_mode=fast, - log=logging.getLogger(fs_module.__module__)) - - m.is_fs_dump = True - if indicators.total_ioc_count > 0: - m.indicators = indicators - m.indicators.log = m.log - - run_module(m) - timeline.extend(m.timeline) - timeline_detected.extend(m.timeline_detected) - - if output: - if len(timeline) > 0: - save_timeline(timeline, os.path.join(output, "timeline.csv")) - if len(timeline_detected) > 0: - save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv")) - - if len(timeline_detected) > 0: - log.warning("The analysis of the filesystem produced %d detections!", - len(timeline_detected)) + if len(cmd.timeline_detected) > 0: + log.warning("The analysis of the iOS filesystem produced %d detections!", + len(cmd.timeline_detected)) #============================================================================== diff --git a/mvt/ios/cmd_check_backup.py b/mvt/ios/cmd_check_backup.py new file mode 100644 index 0000000..6b1f41d --- /dev/null +++ b/mvt/ios/cmd_check_backup.py @@ -0,0 +1,25 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging + +from mvt.common.command import Command + +from .modules.backup import BACKUP_MODULES +from .modules.mixed import MIXED_MODULES + +log = logging.getLogger(__name__) + + +class CmdIOSCheckBackup(Command): + + name = "check-backup" + modules = BACKUP_MODULES + MIXED_MODULES + + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, + ioc_files=ioc_files, module_name=module_name, + serial=serial, fast_mode=fast_mode, log=log) diff --git a/mvt/ios/cmd_check_fs.py b/mvt/ios/cmd_check_fs.py new file mode 100644 index 0000000..b823184 --- /dev/null +++ b/mvt/ios/cmd_check_fs.py @@ -0,0 +1,25 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging + +from mvt.common.command import Command + +from .modules.fs import FS_MODULES +from .modules.mixed import MIXED_MODULES + +log = logging.getLogger(__name__) + + +class CmdIOSChecKFS(Command): + + name = "check-fs" + modules = FS_MODULES + MIXED_MODULES + + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, + ioc_files=ioc_files, module_name=module_name, + serial=serial, fast_mode=fast_mode, log=log) diff --git a/mvt/ios/modules/backup/backup_info.py b/mvt/ios/modules/backup/backup_info.py index 4ef81be..1608d89 100644 --- a/mvt/ios/modules/backup/backup_info.py +++ b/mvt/ios/modules/backup/backup_info.py @@ -15,16 +15,16 @@ from ..base import IOSExtraction class BackupInfo(IOSExtraction): """This module extracts information about the device and the backup.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} def run(self): - info_path = os.path.join(self.base_folder, "Info.plist") + info_path = os.path.join(self.target_path, "Info.plist") if not os.path.exists(info_path): raise DatabaseNotFoundError("No Info.plist at backup path, unable to extract device information") diff --git a/mvt/ios/modules/backup/configuration_profiles.py b/mvt/ios/modules/backup/configuration_profiles.py index 844cdaa..98cf9e1 100644 --- a/mvt/ios/modules/backup/configuration_profiles.py +++ b/mvt/ios/modules/backup/configuration_profiles.py @@ -17,10 +17,10 @@ CONF_PROFILES_DOMAIN = "SysSharedContainerDomain-systemgroup.com.apple.configura class ConfigurationProfiles(IOSExtraction): """This module extracts the full plist data from configuration profiles.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/backup/manifest.py b/mvt/ios/modules/backup/manifest.py index b11c280..fc7e75a 100644 --- a/mvt/ios/modules/backup/manifest.py +++ b/mvt/ios/modules/backup/manifest.py @@ -18,10 +18,10 @@ from ..base import IOSExtraction class Manifest(IOSExtraction): """This module extracts information from a backup Manifest.db file.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def _get_key(self, dictionary, key): @@ -93,7 +93,7 @@ class Manifest(IOSExtraction): self.detected.append(result) def run(self): - manifest_db_path = os.path.join(self.base_folder, "Manifest.db") + manifest_db_path = os.path.join(self.target_path, "Manifest.db") if not os.path.isfile(manifest_db_path): raise DatabaseNotFoundError("unable to find backup's Manifest.db") diff --git a/mvt/ios/modules/backup/profile_events.py b/mvt/ios/modules/backup/profile_events.py index c311c03..81036d4 100644 --- a/mvt/ios/modules/backup/profile_events.py +++ b/mvt/ios/modules/backup/profile_events.py @@ -19,10 +19,10 @@ class ProfileEvents(IOSExtraction): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/base.py b/mvt/ios/modules/base.py index bd2b498..e542877 100644 --- a/mvt/ios/modules/base.py +++ b/mvt/ios/modules/base.py @@ -16,10 +16,10 @@ from mvt.common.module import (DatabaseCorruptedError, DatabaseNotFoundError, class IOSExtraction(MVTModule): """This class provides a base for all iOS filesystem/backup extraction modules.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.is_backup = False @@ -73,7 +73,7 @@ class IOSExtraction(MVTModule): :param domain: Domain to use as filter from Manifest.db. (Default value = None) """ - manifest_db_path = os.path.join(self.base_folder, "Manifest.db") + manifest_db_path = os.path.join(self.target_path, "Manifest.db") if not os.path.exists(manifest_db_path): raise DatabaseNotFoundError("unable to find backup's Manifest.db") @@ -101,7 +101,7 @@ class IOSExtraction(MVTModule): } def _get_backup_file_from_id(self, file_id): - file_path = os.path.join(self.base_folder, file_id[0:2], file_id) + file_path = os.path.join(self.target_path, file_id[0:2], file_id) if os.path.exists(file_path): return file_path @@ -109,7 +109,7 @@ class IOSExtraction(MVTModule): def _get_fs_files_from_patterns(self, root_paths): for root_path in root_paths: - for found_path in glob.glob(os.path.join(self.base_folder, root_path)): + for found_path in glob.glob(os.path.join(self.target_path, root_path)): if not os.path.exists(found_path): continue diff --git a/mvt/ios/modules/fs/analytics.py b/mvt/ios/modules/fs/analytics.py index 6d64e9b..7761d60 100644 --- a/mvt/ios/modules/fs/analytics.py +++ b/mvt/ios/modules/fs/analytics.py @@ -18,10 +18,10 @@ ANALYTICS_DB_PATH = [ class Analytics(IOSExtraction): """This module extracts information from the private/var/Keychains/Analytics/*.db files.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/fs/cache_files.py b/mvt/ios/modules/fs/cache_files.py index 21405e4..0277449 100644 --- a/mvt/ios/modules/fs/cache_files.py +++ b/mvt/ios/modules/fs/cache_files.py @@ -11,10 +11,10 @@ from ..base import IOSExtraction class CacheFiles(IOSExtraction): - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): @@ -55,7 +55,7 @@ class CacheFiles(IOSExtraction): except sqlite3.OperationalError: return - key_name = os.path.relpath(file_path, self.base_folder) + key_name = os.path.relpath(file_path, self.target_path) if key_name not in self.results: self.results[key_name] = [] @@ -71,7 +71,7 @@ class CacheFiles(IOSExtraction): def run(self): self.results = {} - for root, dirs, files in os.walk(self.base_folder): + for root, dirs, files in os.walk(self.target_path): for file_name in files: if file_name != "Cache.db": continue diff --git a/mvt/ios/modules/fs/filesystem.py b/mvt/ios/modules/fs/filesystem.py index 4a3672e..538fa30 100644 --- a/mvt/ios/modules/fs/filesystem.py +++ b/mvt/ios/modules/fs/filesystem.py @@ -18,10 +18,10 @@ class Filesystem(IOSExtraction): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): @@ -58,12 +58,12 @@ class Filesystem(IOSExtraction): self.detected.append(result) def run(self): - for root, dirs, files in os.walk(self.base_folder): + for root, dirs, files in os.walk(self.target_path): for dir_name in dirs: try: dir_path = os.path.join(root, dir_name) result = { - "path": os.path.relpath(dir_path, self.base_folder), + "path": os.path.relpath(dir_path, self.target_path), "modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(dir_path).st_mtime)), } except Exception: @@ -75,7 +75,7 @@ class Filesystem(IOSExtraction): try: file_path = os.path.join(root, file_name) result = { - "path": os.path.relpath(file_path, self.base_folder), + "path": os.path.relpath(file_path, self.target_path), "modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(file_path).st_mtime)), } except Exception: diff --git a/mvt/ios/modules/fs/net_netusage.py b/mvt/ios/modules/fs/net_netusage.py index e768643..c860a96 100644 --- a/mvt/ios/modules/fs/net_netusage.py +++ b/mvt/ios/modules/fs/net_netusage.py @@ -20,10 +20,10 @@ class Netusage(NetBase): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): diff --git a/mvt/ios/modules/fs/safari_favicon.py b/mvt/ios/modules/fs/safari_favicon.py index 7bae6d9..941ab5d 100644 --- a/mvt/ios/modules/fs/safari_favicon.py +++ b/mvt/ios/modules/fs/safari_favicon.py @@ -18,10 +18,10 @@ SAFARI_FAVICON_ROOT_PATHS = [ class SafariFavicon(IOSExtraction): """This module extracts all Safari favicon records.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/fs/shutdownlog.py b/mvt/ios/modules/fs/shutdownlog.py index ae9093d..ef9d170 100644 --- a/mvt/ios/modules/fs/shutdownlog.py +++ b/mvt/ios/modules/fs/shutdownlog.py @@ -15,10 +15,10 @@ SHUTDOWN_LOG_PATH = [ class ShutdownLog(IOSExtraction): """This module extracts processes information from the shutdown log file.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/fs/version_history.py b/mvt/ios/modules/fs/version_history.py index 66ff9b7..be5bd4c 100644 --- a/mvt/ios/modules/fs/version_history.py +++ b/mvt/ios/modules/fs/version_history.py @@ -18,10 +18,10 @@ IOS_ANALYTICS_JOURNAL_PATHS = [ class IOSVersionHistory(IOSExtraction): """This module extracts iOS update history from Analytics Journal log files.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/fs/webkit_base.py b/mvt/ios/modules/fs/webkit_base.py index a155c4f..88b32d8 100644 --- a/mvt/ios/modules/fs/webkit_base.py +++ b/mvt/ios/modules/fs/webkit_base.py @@ -26,7 +26,7 @@ class WebkitBase(IOSExtraction): def _process_webkit_folder(self, root_paths): for found_path in self._get_fs_files_from_patterns(root_paths): - key = os.path.relpath(found_path, self.base_folder) + key = os.path.relpath(found_path, self.target_path) for name in os.listdir(found_path): if not name.startswith("http"): diff --git a/mvt/ios/modules/fs/webkit_indexeddb.py b/mvt/ios/modules/fs/webkit_indexeddb.py index 3c23317..4745e76 100644 --- a/mvt/ios/modules/fs/webkit_indexeddb.py +++ b/mvt/ios/modules/fs/webkit_indexeddb.py @@ -19,10 +19,10 @@ class WebkitIndexedDB(WebkitBase): slug = "webkit_indexeddb" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/fs/webkit_localstorage.py b/mvt/ios/modules/fs/webkit_localstorage.py index 963bd42..323a8bb 100644 --- a/mvt/ios/modules/fs/webkit_localstorage.py +++ b/mvt/ios/modules/fs/webkit_localstorage.py @@ -17,10 +17,10 @@ class WebkitLocalStorage(WebkitBase): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/fs/webkit_safariviewservice.py b/mvt/ios/modules/fs/webkit_safariviewservice.py index 5c77ddf..56a9863 100644 --- a/mvt/ios/modules/fs/webkit_safariviewservice.py +++ b/mvt/ios/modules/fs/webkit_safariviewservice.py @@ -17,10 +17,10 @@ class WebkitSafariViewService(WebkitBase): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): diff --git a/mvt/ios/modules/mixed/calls.py b/mvt/ios/modules/mixed/calls.py index e540eec..53688f2 100644 --- a/mvt/ios/modules/mixed/calls.py +++ b/mvt/ios/modules/mixed/calls.py @@ -20,10 +20,10 @@ CALLS_ROOT_PATHS = [ class Calls(IOSExtraction): """This module extracts phone calls details""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/chrome_favicon.py b/mvt/ios/modules/mixed/chrome_favicon.py index 3fd8c26..3941638 100644 --- a/mvt/ios/modules/mixed/chrome_favicon.py +++ b/mvt/ios/modules/mixed/chrome_favicon.py @@ -23,10 +23,10 @@ CHROME_FAVICON_ROOT_PATHS = [ class ChromeFavicon(IOSExtraction): """This module extracts all Chrome favicon records.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/chrome_history.py b/mvt/ios/modules/mixed/chrome_history.py index c37e478..c44d2c9 100644 --- a/mvt/ios/modules/mixed/chrome_history.py +++ b/mvt/ios/modules/mixed/chrome_history.py @@ -22,10 +22,10 @@ CHROME_HISTORY_ROOT_PATHS = [ class ChromeHistory(IOSExtraction): """This module extracts all Chome visits.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/contacts.py b/mvt/ios/modules/mixed/contacts.py index 6b781bd..dc2cf40 100644 --- a/mvt/ios/modules/mixed/contacts.py +++ b/mvt/ios/modules/mixed/contacts.py @@ -18,10 +18,10 @@ CONTACTS_ROOT_PATHS = [ class Contacts(IOSExtraction): """This module extracts all contact details from the phone's address book.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): diff --git a/mvt/ios/modules/mixed/firefox_favicon.py b/mvt/ios/modules/mixed/firefox_favicon.py index 28e535c..7af9678 100644 --- a/mvt/ios/modules/mixed/firefox_favicon.py +++ b/mvt/ios/modules/mixed/firefox_favicon.py @@ -21,10 +21,10 @@ FIREFOX_HISTORY_ROOT_PATHS = [ class FirefoxFavicon(IOSExtraction): """This module extracts all Firefox favicon""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/firefox_history.py b/mvt/ios/modules/mixed/firefox_history.py index 0d0d92f..b6f50b9 100644 --- a/mvt/ios/modules/mixed/firefox_history.py +++ b/mvt/ios/modules/mixed/firefox_history.py @@ -25,10 +25,10 @@ class FirefoxHistory(IOSExtraction): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/idstatuscache.py b/mvt/ios/modules/mixed/idstatuscache.py index 4f95b61..8e9df3e 100644 --- a/mvt/ios/modules/mixed/idstatuscache.py +++ b/mvt/ios/modules/mixed/idstatuscache.py @@ -22,10 +22,10 @@ IDSTATUSCACHE_ROOT_PATHS = [ class IDStatusCache(IOSExtraction): """Extracts Apple Authentication information from idstatuscache.plist""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/interactionc.py b/mvt/ios/modules/mixed/interactionc.py index 434c308..e16e58a 100644 --- a/mvt/ios/modules/mixed/interactionc.py +++ b/mvt/ios/modules/mixed/interactionc.py @@ -20,10 +20,10 @@ INTERACTIONC_ROOT_PATHS = [ class InteractionC(IOSExtraction): """This module extracts data from InteractionC db.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.timestamps = [ diff --git a/mvt/ios/modules/mixed/locationd.py b/mvt/ios/modules/mixed/locationd.py index 1617bc7..c2576f3 100644 --- a/mvt/ios/modules/mixed/locationd.py +++ b/mvt/ios/modules/mixed/locationd.py @@ -21,10 +21,10 @@ LOCATIOND_ROOT_PATHS = [ class LocationdClients(IOSExtraction): """Extract information from apps who used geolocation.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.timestamps = [ diff --git a/mvt/ios/modules/mixed/net_datausage.py b/mvt/ios/modules/mixed/net_datausage.py index c653ba8..4b63842 100644 --- a/mvt/ios/modules/mixed/net_datausage.py +++ b/mvt/ios/modules/mixed/net_datausage.py @@ -20,10 +20,10 @@ class Datausage(NetBase): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def run(self): diff --git a/mvt/ios/modules/mixed/osanalytics_addaily.py b/mvt/ios/modules/mixed/osanalytics_addaily.py index bcb592e..1c12e02 100644 --- a/mvt/ios/modules/mixed/osanalytics_addaily.py +++ b/mvt/ios/modules/mixed/osanalytics_addaily.py @@ -20,10 +20,10 @@ OSANALYTICS_ADDAILY_ROOT_PATHS = [ class OSAnalyticsADDaily(IOSExtraction): """Extract network usage information by process, from com.apple.osanalytics.addaily.plist""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/safari_browserstate.py b/mvt/ios/modules/mixed/safari_browserstate.py index 32140b4..d1a6a7f 100644 --- a/mvt/ios/modules/mixed/safari_browserstate.py +++ b/mvt/ios/modules/mixed/safari_browserstate.py @@ -23,10 +23,10 @@ SAFARI_BROWSER_STATE_ROOT_PATHS = [ class SafariBrowserState(IOSExtraction): """This module extracts all Safari browser state records.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self._session_history_count = 0 @@ -115,7 +115,7 @@ class SafariBrowserState(IOSExtraction): "tab_visible_url": row[2], "last_viewed_timestamp": convert_timestamp_to_iso(convert_mactime_to_unix(row[3])), "session_data": session_entries, - "safari_browser_state_db": os.path.relpath(db_path, self.base_folder), + "safari_browser_state_db": os.path.relpath(db_path, self.target_path), }) def run(self): diff --git a/mvt/ios/modules/mixed/safari_history.py b/mvt/ios/modules/mixed/safari_history.py index 976fcdb..64c39d5 100644 --- a/mvt/ios/modules/mixed/safari_history.py +++ b/mvt/ios/modules/mixed/safari_history.py @@ -25,10 +25,10 @@ class SafariHistory(IOSExtraction): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): @@ -111,7 +111,7 @@ class SafariHistory(IOSExtraction): "isodate": convert_timestamp_to_iso(convert_mactime_to_unix(row[3])), "redirect_source": row[4], "redirect_destination": row[5], - "safari_history_db": os.path.relpath(history_path, self.base_folder), + "safari_history_db": os.path.relpath(history_path, self.target_path), }) cur.close() diff --git a/mvt/ios/modules/mixed/shortcuts.py b/mvt/ios/modules/mixed/shortcuts.py index 4d096c8..b9c3655 100644 --- a/mvt/ios/modules/mixed/shortcuts.py +++ b/mvt/ios/modules/mixed/shortcuts.py @@ -24,10 +24,10 @@ SHORTCUT_ROOT_PATHS = [ class Shortcuts(IOSExtraction): """This module extracts all info about SMS/iMessage attachments.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/sms.py b/mvt/ios/modules/mixed/sms.py index 7358371..5a88256 100644 --- a/mvt/ios/modules/mixed/sms.py +++ b/mvt/ios/modules/mixed/sms.py @@ -22,10 +22,10 @@ SMS_ROOT_PATHS = [ class SMS(IOSExtraction): """This module extracts all SMS messages containing links.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/sms_attachments.py b/mvt/ios/modules/mixed/sms_attachments.py index 03e7d78..0f6ba39 100644 --- a/mvt/ios/modules/mixed/sms_attachments.py +++ b/mvt/ios/modules/mixed/sms_attachments.py @@ -21,10 +21,10 @@ SMS_ROOT_PATHS = [ class SMSAttachments(IOSExtraction): """This module extracts all info about SMS/iMessage attachments.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/tcc.py b/mvt/ios/modules/mixed/tcc.py index 9368d10..226a0d3 100644 --- a/mvt/ios/modules/mixed/tcc.py +++ b/mvt/ios/modules/mixed/tcc.py @@ -47,10 +47,10 @@ AUTH_REASONS = { class TCC(IOSExtraction): """This module extracts records from the TCC.db SQLite database.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/mixed/webkit_resource_load_statistics.py b/mvt/ios/modules/mixed/webkit_resource_load_statistics.py index 40de3b0..12fc08c 100644 --- a/mvt/ios/modules/mixed/webkit_resource_load_statistics.py +++ b/mvt/ios/modules/mixed/webkit_resource_load_statistics.py @@ -22,10 +22,10 @@ class WebkitResourceLoadStatistics(IOSExtraction): """This module extracts records from WebKit ResourceLoadStatistics observations.db.""" # TODO: Add serialize(). - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} if not results else results @@ -85,4 +85,4 @@ class WebkitResourceLoadStatistics(IOSExtraction): self.log.info("Unable to search for WebKit observations.db: %s", e) elif self.is_fs_dump: for db_path in self._get_fs_files_from_patterns(WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS): - self._process_observations_db(db_path=db_path, key=os.path.relpath(db_path, self.base_folder)) + self._process_observations_db(db_path=db_path, key=os.path.relpath(db_path, self.target_path)) diff --git a/mvt/ios/modules/mixed/webkit_session_resource_log.py b/mvt/ios/modules/mixed/webkit_session_resource_log.py index f63c97a..5106d86 100644 --- a/mvt/ios/modules/mixed/webkit_session_resource_log.py +++ b/mvt/ios/modules/mixed/webkit_session_resource_log.py @@ -29,10 +29,10 @@ class WebkitSessionResourceLog(IOSExtraction): """ - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) self.results = {} if not results else results @@ -128,7 +128,7 @@ class WebkitSessionResourceLog(IOSExtraction): elif self.is_fs_dump: for log_path in self._get_fs_files_from_patterns(WEBKIT_SESSION_RESOURCE_LOG_ROOT_PATHS): self.log.info("Found Safari browsing session resource log at path: %s", log_path) - key = os.path.relpath(log_path, self.base_folder) + key = os.path.relpath(log_path, self.target_path) self.results[key] = self._extract_browsing_stats(log_path) self.log.info("Extracted records from %d Safari browsing session resource logs", diff --git a/mvt/ios/modules/mixed/whatsapp.py b/mvt/ios/modules/mixed/whatsapp.py index 3645dfb..6c1b6aa 100644 --- a/mvt/ios/modules/mixed/whatsapp.py +++ b/mvt/ios/modules/mixed/whatsapp.py @@ -24,10 +24,10 @@ WHATSAPP_ROOT_PATHS = [ class Whatsapp(IOSExtraction): """This module extracts all WhatsApp messages containing links.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def serialize(self, record): diff --git a/mvt/ios/modules/net_base.py b/mvt/ios/modules/net_base.py index 20cbe3a..5cb53ed 100644 --- a/mvt/ios/modules/net_base.py +++ b/mvt/ios/modules/net_base.py @@ -15,10 +15,10 @@ from .base import IOSExtraction class NetBase(IOSExtraction): """This class provides a base for DataUsage and NetUsage extraction modules.""" - def __init__(self, file_path=None, base_folder=None, output_folder=None, + def __init__(self, file_path=None, target_path=None, results_path=None, fast_mode=False, log=None, results=[]): - super().__init__(file_path=file_path, base_folder=base_folder, - output_folder=output_folder, fast_mode=fast_mode, + super().__init__(file_path=file_path, target_path=target_path, + results_path=results_path, fast_mode=fast_mode, log=log, results=results) def _extract_net_data(self): @@ -124,7 +124,7 @@ class NetBase(IOSExtraction): self.log.info("Extended search for suspicious processes ...") files = [] - for posix_path in Path(self.base_folder).rglob("*"): + for posix_path in Path(self.target_path).rglob("*"): try: if not posix_path.is_file(): continue From abc0f2768ba63fb7d03a3932f698598edd235b2a Mon Sep 17 00:00:00 2001 From: Nex Date: Thu, 16 Jun 2022 15:24:43 +0200 Subject: [PATCH 4/6] Fixed tests --- mvt/ios/cmd_check_fs.py | 2 +- tests/android/test_backup_module.py | 8 ++++---- tests/android/test_bugreport_appops.py | 2 +- tests/ios/test_backup_info.py | 2 +- tests/ios/test_datausage.py | 4 ++-- tests/ios/test_manifest.py | 4 ++-- tests/ios/test_safari_browserstate.py | 4 ++-- tests/ios/test_sms.py | 4 ++-- tests/ios/test_tcc.py | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/mvt/ios/cmd_check_fs.py b/mvt/ios/cmd_check_fs.py index b823184..46a2961 100644 --- a/mvt/ios/cmd_check_fs.py +++ b/mvt/ios/cmd_check_fs.py @@ -13,7 +13,7 @@ from .modules.mixed import MIXED_MODULES log = logging.getLogger(__name__) -class CmdIOSChecKFS(Command): +class CmdIOSCheckFS(Command): name = "check-fs" modules = FS_MODULES + MIXED_MODULES diff --git a/tests/android/test_backup_module.py b/tests/android/test_backup_module.py index 02ca425..eebc6ed 100644 --- a/tests/android/test_backup_module.py +++ b/tests/android/test_backup_module.py @@ -18,7 +18,7 @@ from ..utils import get_android_backup_folder class TestBackupModule: def test_module_folder(self): backup_path = get_android_backup_folder() - mod = SMS(base_folder=backup_path, log=logging) + mod = SMS(target_path=backup_path, log=logging) files = [] for root, subdirs, subfiles in os.walk(os.path.abspath(backup_path)): for fname in subfiles: @@ -31,7 +31,7 @@ class TestBackupModule: def test_module_file(self): fpath = os.path.join(get_android_backup_folder(), "backup.ab") - mod = SMS(base_folder=fpath, log=logging) + mod = SMS(target_path=fpath, log=logging) with open(fpath, "rb") as f: data = f.read() tardata = parse_backup_file(data) @@ -47,7 +47,7 @@ class TestBackupModule: def test_module_file2(self): fpath = os.path.join(get_android_backup_folder(), "backup2.ab") - mod = SMS(base_folder=fpath, log=logging) + mod = SMS(target_path=fpath, log=logging) with open(fpath, "rb") as f: data = f.read() tardata = parse_backup_file(data, password="123456") @@ -63,7 +63,7 @@ class TestBackupModule: def test_module_file3(self): fpath = os.path.join(get_android_backup_folder(), "backup3.ab") - mod = SMS(base_folder=fpath, log=logging) + mod = SMS(target_path=fpath, log=logging) with open(fpath, "rb") as f: data = f.read() tardata = parse_backup_file(data) diff --git a/tests/android/test_bugreport_appops.py b/tests/android/test_bugreport_appops.py index abccdb5..4b0e748 100644 --- a/tests/android/test_bugreport_appops.py +++ b/tests/android/test_bugreport_appops.py @@ -16,7 +16,7 @@ from ..utils import get_artifact_folder class TestAppopsModule: def test_appops_parsing(self): fpath = os.path.join(get_artifact_folder(), "android_data/bugreport/") - m = Appops(base_folder=fpath, log=logging, results=[]) + m = Appops(target_path=fpath, log=logging, results=[]) folder_files = [] parent_path = Path(fpath).absolute().as_posix() for root, subdirs, subfiles in os.walk(os.path.abspath(fpath)): diff --git a/tests/ios/test_backup_info.py b/tests/ios/test_backup_info.py index 56cafed..01c308b 100644 --- a/tests/ios/test_backup_info.py +++ b/tests/ios/test_backup_info.py @@ -13,7 +13,7 @@ from ..utils import get_ios_backup_folder class TestBackupInfoModule: def test_manifest(self): - m = BackupInfo(base_folder=get_ios_backup_folder(), log=logging) + m = BackupInfo(target_path=get_ios_backup_folder(), log=logging) run_module(m) assert m.results["Build Version"] == "18C66" assert m.results["IMEI"] == "42" diff --git a/tests/ios/test_datausage.py b/tests/ios/test_datausage.py index 1508633..633dcaf 100644 --- a/tests/ios/test_datausage.py +++ b/tests/ios/test_datausage.py @@ -14,14 +14,14 @@ from ..utils import get_ios_backup_folder class TestDatausageModule: def test_datausage(self): - m = Datausage(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = Datausage(target_path=get_ios_backup_folder(), log=logging, results=[]) run_module(m) assert len(m.results) == 42 assert len(m.timeline) == 60 assert len(m.detected) == 0 def test_detection(self, indicator_file): - m = Datausage(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = Datausage(target_path=get_ios_backup_folder(), log=logging, results=[]) ind = Indicators(log=logging) ind.parse_stix2(indicator_file) # Adds a file that exists in the manifest. diff --git a/tests/ios/test_manifest.py b/tests/ios/test_manifest.py index 06e1ec3..c3de353 100644 --- a/tests/ios/test_manifest.py +++ b/tests/ios/test_manifest.py @@ -14,14 +14,14 @@ from ..utils import get_ios_backup_folder class TestManifestModule: def test_manifest(self): - m = Manifest(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = Manifest(target_path=get_ios_backup_folder(), log=logging, results=[]) run_module(m) assert len(m.results) == 3721 assert len(m.timeline) == 5881 assert len(m.detected) == 0 def test_detection(self, indicator_file): - m = Manifest(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = Manifest(target_path=get_ios_backup_folder(), log=logging, results=[]) ind = Indicators(log=logging) ind.parse_stix2(indicator_file) ind.ioc_collections[0]["file_names"].append("com.apple.CoreBrightness.plist") diff --git a/tests/ios/test_safari_browserstate.py b/tests/ios/test_safari_browserstate.py index 6ef5e8e..e44cee0 100644 --- a/tests/ios/test_safari_browserstate.py +++ b/tests/ios/test_safari_browserstate.py @@ -14,7 +14,7 @@ from ..utils import get_ios_backup_folder class TestSafariBrowserStateModule: def test_parsing(self): - m = SafariBrowserState(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = SafariBrowserState(target_path=get_ios_backup_folder(), log=logging, results=[]) m.is_backup = True run_module(m) assert m.file_path is not None @@ -23,7 +23,7 @@ class TestSafariBrowserStateModule: assert len(m.detected) == 0 def test_detection(self, indicator_file): - m = SafariBrowserState(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = SafariBrowserState(target_path=get_ios_backup_folder(), log=logging, results=[]) m.is_backup = True ind = Indicators(log=logging) ind.parse_stix2(indicator_file) diff --git a/tests/ios/test_sms.py b/tests/ios/test_sms.py index 275b2c3..c3774db 100644 --- a/tests/ios/test_sms.py +++ b/tests/ios/test_sms.py @@ -14,14 +14,14 @@ from ..utils import get_ios_backup_folder class TestSMSModule: def test_sms(self): - m = SMS(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = SMS(target_path=get_ios_backup_folder(), log=logging, results=[]) run_module(m) assert len(m.results) == 1 assert len(m.timeline) == 1 assert len(m.detected) == 0 def test_detection(self, indicator_file): - m = SMS(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = SMS(target_path=get_ios_backup_folder(), log=logging, results=[]) ind = Indicators(log=logging) ind.parse_stix2(indicator_file) # Adds a file that exists in the manifest. diff --git a/tests/ios/test_tcc.py b/tests/ios/test_tcc.py index 71d3218..730e2f4 100644 --- a/tests/ios/test_tcc.py +++ b/tests/ios/test_tcc.py @@ -14,7 +14,7 @@ from ..utils import get_ios_backup_folder class TestTCCtModule: def test_tcc(self): - m = TCC(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = TCC(target_path=get_ios_backup_folder(), log=logging, results=[]) run_module(m) assert len(m.results) == 11 assert len(m.timeline) == 11 @@ -24,7 +24,7 @@ class TestTCCtModule: assert m.results[0]["auth_value"] == "allowed" def test_tcc_detection(self, indicator_file): - m = TCC(base_folder=get_ios_backup_folder(), log=logging, results=[]) + m = TCC(target_path=get_ios_backup_folder(), log=logging, results=[]) ind = Indicators(log=logging) ind.parse_stix2(indicator_file) m.indicators = ind From fba4e27757dcfb8cd28bf458d52bd52f45c46afa Mon Sep 17 00:00:00 2001 From: Nex Date: Thu, 16 Jun 2022 17:02:38 +0200 Subject: [PATCH 5/6] Refactored check-iocs command for Android as well --- mvt/android/cli.py | 75 ++++++++++------------------- mvt/android/modules/adb/packages.py | 2 +- mvt/common/cmd_check_iocs.py | 63 ++++++++++++++++++++++++ mvt/ios/cli.py | 51 +++----------------- 4 files changed, 95 insertions(+), 96 deletions(-) create mode 100644 mvt/common/cmd_check_iocs.py diff --git a/mvt/android/cli.py b/mvt/android/cli.py index 8cba92c..6359246 100644 --- a/mvt/android/cli.py +++ b/mvt/android/cli.py @@ -9,10 +9,11 @@ import os import click from rich.logging import RichHandler +from mvt.common.cmd_check_iocs import CmdCheckIOCS from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_OUTPUT, HELP_MSG_SERIAL) -from mvt.common.indicators import Indicators, download_indicators_files +from mvt.common.indicators import download_indicators_files from mvt.common.logo import logo from .cmd_check_adb import CmdAndroidCheckADB @@ -22,6 +23,7 @@ from .cmd_download_apks import DownloadAPKs from .modules.adb import ADB_MODULES from .modules.adb.packages import Packages from .modules.backup import BACKUP_MODULES +from .modules.bugreport import BUGREPORT_MODULES # Setup logging using Rich. LOG_FORMAT = "[%(name)s] %(message)s" @@ -122,8 +124,14 @@ def check_adb(ctx, iocs, output, fast, list_modules, module, serial): cmd.list_modules() return + log.info("Checking Android device over debug bridge") + cmd.run() + if len(cmd.timeline_detected) > 0: + log.warning("The analysis of the Android device produced %d detections!", + len(cmd.timeline_detected)) + #============================================================================== # Command: check-bugreport @@ -144,8 +152,14 @@ def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path): cmd.list_modules() return + log.info("Checking Android bug report at path: %s", bugreport_path) + cmd.run() + if len(cmd.timeline_detected) > 0: + log.warning("The analysis of the Android bug report produced %d detections!", + len(cmd.timeline_detected)) + #============================================================================== # Command: check-backup @@ -166,8 +180,14 @@ def check_backup(ctx, iocs, output, list_modules, backup_path, serial): cmd.list_modules() return + log.info("Checking Android backup at path: %s", backup_path) + cmd.run() + if len(cmd.timeline_detected) > 0: + log.warning("The analysis of the Android backup produced %d detections!", + len(cmd.timeline_detected)) + #============================================================================== # Command: check-iocs @@ -180,59 +200,14 @@ def check_backup(ctx, iocs, output, list_modules, backup_path, serial): @click.argument("FOLDER", type=click.Path(exists=True)) @click.pass_context def check_iocs(ctx, iocs, list_modules, module, folder): - all_modules = [] - for entry in BACKUP_MODULES + ADB_MODULES: - if entry not in all_modules: - all_modules.append(entry) + cmd = CmdCheckIOCS(target_path=folder, ioc_files=iocs, module_name=module) + cmd.modules = BACKUP_MODULES + ADB_MODULES + BUGREPORT_MODULES if list_modules: - log.info("Following is the list of available check-iocs modules:") - for iocs_module in all_modules: - log.info(" - %s", iocs_module.__name__) - + cmd.list_modules() return - log.info("Checking stored results against provided indicators...") - - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - total_detections = 0 - for file_name in os.listdir(folder): - name_only, ext = os.path.splitext(file_name) - file_path = os.path.join(folder, file_name) - - # TODO: Skipping processing of result files that are not json. - # We might want to revisit this eventually. - if ext != ".json": - continue - - for iocs_module in all_modules: - if module and iocs_module.__name__ != module: - continue - - if iocs_module().get_slug() != name_only: - continue - - log.info("Loading results from \"%s\" with module %s", file_name, - iocs_module.__name__) - - m = iocs_module.from_json(file_path, - log=logging.getLogger(iocs_module.__module__)) - if indicators.total_ioc_count > 0: - m.indicators = indicators - m.indicators.log = m.log - - try: - m.check_indicators() - except NotImplementedError: - continue - else: - total_detections += len(m.detected) - - if total_detections > 0: - log.warning("The check of the results produced %d detections!", - total_detections) + cmd.run() #============================================================================== diff --git a/mvt/android/modules/adb/packages.py b/mvt/android/modules/adb/packages.py index ddec724..ca9d7b3 100644 --- a/mvt/android/modules/adb/packages.py +++ b/mvt/android/modules/adb/packages.py @@ -114,7 +114,7 @@ class Packages(AndroidExtraction): self.detected.append(result) continue - for package_file in result["files"]: + for package_file in result.get("files", []): ioc = self.indicators.check_file_hash(package_file["sha256"]) if ioc: result["matched_indicator"] = ioc diff --git a/mvt/common/cmd_check_iocs.py b/mvt/common/cmd_check_iocs.py new file mode 100644 index 0000000..10467fe --- /dev/null +++ b/mvt/common/cmd_check_iocs.py @@ -0,0 +1,63 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 Claudio Guarnieri. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging +import os + +from mvt.common.command import Command + +log = logging.getLogger(__name__) + + +class CmdCheckIOCS(Command): + + name = "check-iocs" + modules = [] + + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False): + super().__init__(target_path=target_path, results_path=results_path, + ioc_files=ioc_files, module_name=module_name, + serial=serial, fast_mode=fast_mode, log=log) + + def run(self): + all_modules = [] + for entry in self.modules: + if entry not in all_modules: + all_modules.append(entry) + + log.info("Checking stored results against provided indicators...") + + total_detections = 0 + for file_name in os.listdir(self.target_path): + name_only, ext = os.path.splitext(file_name) + file_path = os.path.join(self.target_path, file_name) + + for iocs_module in all_modules: + if self.module_name and iocs_module.__name__ != self.module_name: + continue + + if iocs_module().get_slug() != name_only: + continue + + log.info("Loading results from \"%s\" with module %s", file_name, + iocs_module.__name__) + + m = iocs_module.from_json(file_path, + log=logging.getLogger(iocs_module.__module__)) + if self.iocs.total_ioc_count > 0: + m.indicators = self.iocs + m.indicators.log = m.log + + try: + m.check_indicators() + except NotImplementedError: + continue + else: + total_detections += len(m.detected) + + if total_detections > 0: + log.warning("The check of the results produced %d detections!", + total_detections) diff --git a/mvt/ios/cli.py b/mvt/ios/cli.py index 26bba39..212d1a1 100644 --- a/mvt/ios/cli.py +++ b/mvt/ios/cli.py @@ -10,10 +10,11 @@ import click from rich.logging import RichHandler from rich.prompt import Prompt +from mvt.common.cmd_check_iocs import CmdCheckIOCS from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_OUTPUT) -from mvt.common.indicators import Indicators, download_indicators_files +from mvt.common.indicators import download_indicators_files from mvt.common.logo import logo from mvt.common.options import MutuallyExclusiveOption @@ -197,54 +198,14 @@ def check_fs(ctx, iocs, output, fast, dump_path, list_modules, module): @click.argument("FOLDER", type=click.Path(exists=True)) @click.pass_context def check_iocs(ctx, iocs, list_modules, module, folder): - all_modules = [] - for entry in BACKUP_MODULES + FS_MODULES + MIXED_MODULES: - if entry not in all_modules: - all_modules.append(entry) + cmd = CmdCheckIOCS(target_path=folder, ioc_files=iocs, module_name=module) + cmd.modules = BACKUP_MODULES + FS_MODULES + MIXED_MODULES if list_modules: - log.info("Following is the list of available check-iocs modules:") - for iocs_module in all_modules: - log.info(" - %s", iocs_module.__name__) - + cmd.list_modules() return - log.info("Checking stored results against provided indicators...") - - indicators = Indicators(log=log) - indicators.load_indicators_files(iocs) - - total_detections = 0 - for file_name in os.listdir(folder): - name_only, ext = os.path.splitext(file_name) - file_path = os.path.join(folder, file_name) - - for iocs_module in all_modules: - if module and iocs_module.__name__ != module: - continue - - if iocs_module().get_slug() != name_only: - continue - - log.info("Loading results from \"%s\" with module %s", file_name, - iocs_module.__name__) - - m = iocs_module.from_json(file_path, - log=logging.getLogger(iocs_module.__module__)) - if indicators.total_ioc_count > 0: - m.indicators = indicators - m.indicators.log = m.log - - try: - m.check_indicators() - except NotImplementedError: - continue - else: - total_detections += len(m.detected) - - if total_detections > 0: - log.warning("The check of the results produced %d detections!", - total_detections) + cmd.run() #============================================================================== From 2dbfef322ad3cf9a01ee10ad38be86ea810a2156 Mon Sep 17 00:00:00 2001 From: Nex Date: Thu, 16 Jun 2022 17:08:42 +0200 Subject: [PATCH 6/6] Some marginal code style fix --- mvt/common/command.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mvt/common/command.py b/mvt/common/command.py index fbfd3c2..3334700 100644 --- a/mvt/common/command.py +++ b/mvt/common/command.py @@ -13,8 +13,9 @@ from mvt.common.module import run_module, save_timeline class Command(object): - def __init__(self, target_path=None, results_path=None, ioc_files=[], module_name=None, - serial=None, fast_mode=False, log=logging.getLogger(__name__)): + def __init__(self, target_path=None, results_path=None, ioc_files=[], + module_name=None, serial=None, fast_mode=False, + log=logging.getLogger(__name__)): self.target_path = target_path self.results_path = results_path self.ioc_files = ioc_files