From 815cdc0a88299679c36964e6971f1d77ddf9c588 Mon Sep 17 00:00:00 2001 From: Nex Date: Mon, 27 Jun 2022 14:41:40 +0200 Subject: [PATCH 01/10] Adding system to check for updates of indicators files and notify if any are available --- mvt/common/indicators.py | 45 ++--------- mvt/common/logo.py | 39 +++++++-- mvt/common/updates.py | 170 +++++++++++++++++++++++++++++++++++++-- mvt/ios/cli.py | 5 +- setup.cfg | 1 + 5 files changed, 205 insertions(+), 55 deletions(-) diff --git a/mvt/common/indicators.py b/mvt/common/indicators.py index 2c4041e..5a0684d 100644 --- a/mvt/common/indicators.py +++ b/mvt/common/indicators.py @@ -12,6 +12,9 @@ from appdirs import user_data_dir from .url import URL +MVT_DATA_FOLDER = user_data_dir("mvt") +MVT_INDICATORS_FOLDER = os.path.join(MVT_DATA_FOLDER, "indicators") + class Indicators: """This class is used to parse indicators from a STIX2 file and provide @@ -19,18 +22,17 @@ class Indicators: """ def __init__(self, log=logging.Logger) -> None: - self.data_dir = user_data_dir("mvt") self.log = log self.ioc_collections = [] self.total_ioc_count = 0 def _load_downloaded_indicators(self) -> None: - if not os.path.isdir(self.data_dir): + if not os.path.isdir(MVT_INDICATORS_FOLDER): return - for f in os.listdir(self.data_dir): - if f.lower().endswith(".stix2"): - self.parse_stix2(os.path.join(self.data_dir, f)) + for ioc_file_name in os.listdir(MVT_INDICATORS_FOLDER): + if ioc_file_name.lower().endswith(".stix2"): + self.parse_stix2(os.path.join(MVT_INDICATORS_FOLDER, ioc_file_name)) def _check_stix2_env_variable(self) -> None: """ @@ -446,36 +448,3 @@ class Indicators: self.log.warning("Found a known suspicious app with ID \"%s\" matching indicators from \"%s\"", app_id, ioc["name"]) return ioc - - -def download_indicators_files(log: logging.Logger) -> None: - """ - Download indicators from repo into MVT app data directory. - """ - data_dir = user_data_dir("mvt") - if not os.path.isdir(data_dir): - os.makedirs(data_dir, exist_ok=True) - - # Download latest list of indicators from the MVT repo. - res = requests.get("https://raw.githubusercontent.com/mvt-project/mvt-indicators/main/indicators.json") - if res.status_code != 200: - log.warning("Unable to find retrieve list of indicators from the MVT repository.") - return - - for ioc_entry in res.json(): - ioc_url = ioc_entry["stix2_url"] - log.info("Downloading indicator file %s from %s", ioc_entry["name"], ioc_url) - - res = requests.get(ioc_url) - if res.status_code != 200: - log.warning("Could not find indicator file %s", ioc_url) - continue - - clean_file_name = ioc_url.lstrip("https://").replace("/", "_") - ioc_path = os.path.join(data_dir, clean_file_name) - - # Write file to disk. This will overwrite any older version of the STIX2 file. - with open(ioc_path, "w", encoding="utf-8") as handle: - handle.write(res.text) - - log.info("Saved indicator file to %s", os.path.basename(ioc_path)) diff --git a/mvt/common/logo.py b/mvt/common/logo.py index 908ca3b..2f4665f 100644 --- a/mvt/common/logo.py +++ b/mvt/common/logo.py @@ -5,22 +5,45 @@ from rich import print -from .updates import check_for_updates +from .updates import MVTUpdates, IndicatorsUpdates from .version import MVT_VERSION +def check_updates() -> None: + # First we check for MVT version udpates. + mvt_updates = MVTUpdates() + try: + latest_version = mvt_updates.check() + except Exception: + pass + else: + if latest_version: + print(f"\t\t[bold]Version {latest_version} is available! Upgrade mvt![/bold]") + + # Then we check for indicators files updates. + ioc_updates = IndicatorsUpdates() + + # Before proceeding, we check if we have downloaded an indicators index. + # If not, there's no point in proceeding with the updates check. + if ioc_updates.get_latest_update() == 0: + print("\t\t[bold]You have not yet downloaded any indicators, check the `download-iocs` command!") + return + + try: + ioc_to_update = ioc_updates.check() + except Exception: + pass + else: + if ioc_to_update: + print("\t\t[bold]There are updates to your indicators files! Run the `download-iocs` command to update!") + return + def logo() -> None: print("\n") print("\t[bold]MVT[/bold] - Mobile Verification Toolkit") print("\t\thttps://mvt.re") print(f"\t\tVersion: {MVT_VERSION}") - try: - latest_version = check_for_updates() - except Exception: - pass - else: - if latest_version: - print(f"\t\t[bold]Version {latest_version} is available! Upgrade mvt![/bold]") + check_updates() print("\n") diff --git a/mvt/common/updates.py b/mvt/common/updates.py index 4057bef..b66833a 100644 --- a/mvt/common/updates.py +++ b/mvt/common/updates.py @@ -3,18 +3,174 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ +import os +import yaml +import logging +from datetime import datetime + import requests from packaging import version +from .indicators import MVT_DATA_FOLDER, MVT_INDICATORS_FOLDER from .version import MVT_VERSION +log = logging.getLogger(__name__) -def check_for_updates() -> str: - res = requests.get("https://pypi.org/pypi/mvt/json") - data = res.json() - latest_version = data.get("info", {}).get("version", "") - if version.parse(latest_version) > version.parse(MVT_VERSION): - return latest_version +class MVTUpdates: - return "" + def check(self) -> str: + res = requests.get("https://pypi.org/pypi/mvt/json") + data = res.json() + latest_version = data.get("info", {}).get("version", "") + + if version.parse(latest_version) > version.parse(MVT_VERSION): + return latest_version + + return "" + + +class IndicatorsUpdates: + + def __init__(self) -> None: + self.github_raw_url = "https://raw.githubusercontent.com/{}/{}/{}/{}" + + self.index_owner = "mvt-project" + self.index_repo = "mvt-indicators" + self.index_branch = "main" + self.index_path = "indicators.yaml" + + self.latest_update_path = os.path.join(MVT_DATA_FOLDER, + "latest_indicators_update") + + def get_latest_update(self) -> int: + if not os.path.exists(self.latest_update_path): + return 0 + + with open(self.latest_update_path, "r") as handle: + data = handle.read().strip() + if data: + latest_update = int(data) + else: + latest_update = 0 + + return latest_update + + def set_latest_update(self) -> None: + timestamp = int(datetime.utcnow().timestamp()) + with open(self.latest_update_path, "w") as handle: + handle.write(str(timestamp)) + + def get_remote_index(self) -> dict: + url = self.github_raw_url.format(self.index_owner, self.index_repo, + self.index_branch, self.index_path) + res = requests.get(url) + if res.status_code != 200: + log.error("Failed to retrieve indicators index located at %s (error %d)", + index_url, res.status_code) + return None + + return yaml.safe_load(res.content) + + def download_remote_ioc(self, ioc_url: str) -> str: + res = requests.get(ioc_url) + if res.status_code != 200: + log.error("Failed to download indicators file from %s (error %d)", + ioc_url, res.status_code) + return None + + clean_file_name = ioc_url.lstrip("https://").replace("/", "_") + ioc_path = os.path.join(MVT_INDICATORS_FOLDER, clean_file_name) + + with open(ioc_path, "w", encoding="utf-8") as handle: + handle.write(res.text) + + return ioc_path + + def update(self) -> None: + if not os.path.exists(MVT_INDICATORS_FOLDER): + os.makedirs(MVT_INDICATORS_FOLDER) + + index = self.get_remote_index() + for ioc in index.get("indicators", []): + ioc_type = ioc.get("type", "") + + if ioc_type == "github": + github = ioc.get("github", {}) + owner = github.get("owner", "") + repo = github.get("repo", "") + branch = github.get("branch", "main") + path = github.get("path", "") + + ioc_url = self.github_raw_url.format(owner, repo, branch, path) + else: + ioc_url = ioc.get("download_url", "") + + if not ioc_url: + log.error("Could not find a way to download indicator file for %s", + ioc.get("name")) + continue + + ioc_local_path = self.download_remote_ioc(ioc_url) + if not ioc_local_path: + continue + + log.info("Downloaded indicators \"%s\" to %s", + ioc.get("name"), ioc_local_path) + + self.set_latest_update() + + def _get_remote_file_latest_commit(self, owner: str, repo: str, + branch: str, path: str) -> bool: + file_commit_url = f"https://api.github.com/repos/{self.index_owner}/{self.index_repo}/commits?path={self.index_path}" + res = requests.get(file_commit_url) + if res.status_code != 200: + log.error("Failed to get details about file %s (error %d)", + file_commit_url, res.status_code) + return False + + details = res.json() + if len(details) == 0: + return False + + latest_commit = details[0] + latest_commit_date = latest_commit.get("commit", {}).get("author", {}).get("date", None) + if not latest_commit_date: + log.error("Failed to retrieve date of latest update to indicators index file") + return False + + latest_commit_dt = datetime.strptime(latest_commit_date, '%Y-%m-%dT%H:%M:%SZ') + latest_commit_ts = int(latest_commit_dt.timestamp()) + + return latest_commit_ts + + def check(self) -> bool: + latest_update = self.get_latest_update() + + latest_commit_ts = self._get_remote_file_latest_commit(self.index_owner, + self.index_repo, + self.index_branch, + self.index_path) + + if latest_update < latest_commit_ts: + return True + + index = self.get_remote_index() + for ioc in index.get("indicators", []): + if ioc.get("type", "") != "github": + continue + + github = ioc.get("github", {}) + owner = github.get("owner", "") + repo = github.get("repo", "") + branch = github.get("branch", "main") + path = github.get("path", "") + + file_latest_commit_ts = self._get_remote_file_latest_commit(owner, + repo, + branch, + path) + if latest_update < file_latest_commit_ts: + return True + + return False diff --git a/mvt/ios/cli.py b/mvt/ios/cli.py index 4b5d373..1087b65 100644 --- a/mvt/ios/cli.py +++ b/mvt/ios/cli.py @@ -14,9 +14,9 @@ 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 download_indicators_files from mvt.common.logo import logo from mvt.common.options import MutuallyExclusiveOption +from mvt.common.updates import IndicatorsUpdates from .cmd_check_backup import CmdIOSCheckBackup from .cmd_check_fs import CmdIOSCheckFS @@ -213,4 +213,5 @@ def check_iocs(ctx, iocs, list_modules, module, folder): #============================================================================== @cli.command("download-iocs", help="Download public STIX2 indicators") def download_iocs(): - download_indicators_files(log) + ioc_updates = IndicatorsUpdates() + ioc_updates.update() diff --git a/setup.cfg b/setup.cfg index 9f91876..7f89bff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,7 @@ install_requires = adb-shell >=0.4.2 libusb1 >=2.0.1 cryptography >=36.0.1 + pyyaml >=6.0 [options.packages.find] where = ./ From 8ff8e599d85711544a6ecf2ea85c256c80308407 Mon Sep 17 00:00:00 2001 From: Nex Date: Tue, 28 Jun 2022 12:00:30 +0200 Subject: [PATCH 02/10] Fixed flake8 and minor code style --- mvt/common/indicators.py | 1 - mvt/common/logo.py | 1 + mvt/common/updates.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mvt/common/indicators.py b/mvt/common/indicators.py index 5a0684d..3ddb29d 100644 --- a/mvt/common/indicators.py +++ b/mvt/common/indicators.py @@ -7,7 +7,6 @@ import json import logging import os -import requests from appdirs import user_data_dir from .url import URL diff --git a/mvt/common/logo.py b/mvt/common/logo.py index 2f4665f..eb91c1f 100644 --- a/mvt/common/logo.py +++ b/mvt/common/logo.py @@ -38,6 +38,7 @@ def check_updates() -> None: print("\t\t[bold]There are updates to your indicators files! Run the `download-iocs` command to update!") return + def logo() -> None: print("\n") print("\t[bold]MVT[/bold] - Mobile Verification Toolkit") diff --git a/mvt/common/updates.py b/mvt/common/updates.py index b66833a..dba5d90 100644 --- a/mvt/common/updates.py +++ b/mvt/common/updates.py @@ -67,7 +67,7 @@ class IndicatorsUpdates: res = requests.get(url) if res.status_code != 200: log.error("Failed to retrieve indicators index located at %s (error %d)", - index_url, res.status_code) + url, res.status_code) return None return yaml.safe_load(res.content) From aedef123c953d7f16e8c19f5af79139891eab54d Mon Sep 17 00:00:00 2001 From: Nex Date: Tue, 28 Jun 2022 12:54:33 +0200 Subject: [PATCH 03/10] Added frequency of indicators updates check --- mvt/common/logo.py | 13 ++++++++++-- mvt/common/updates.py | 46 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/mvt/common/logo.py b/mvt/common/logo.py index eb91c1f..a3ea034 100644 --- a/mvt/common/logo.py +++ b/mvt/common/logo.py @@ -5,7 +5,7 @@ from rich import print -from .updates import MVTUpdates, IndicatorsUpdates +from .updates import IndicatorsUpdates, MVTUpdates from .version import MVT_VERSION @@ -29,6 +29,14 @@ def check_updates() -> None: print("\t\t[bold]You have not yet downloaded any indicators, check the `download-iocs` command!") return + # We only perform this check at a fixed frequency, in order to not + # overburden the user with too many lookups if the command is being run + # multiple times. + should_check, hours = ioc_updates.should_check() + if not should_check: + print(f"\t\tIndicators updates checked recently, next automatic check in {int(hours)} hours") + return + try: ioc_to_update = ioc_updates.check() except Exception: @@ -36,7 +44,8 @@ def check_updates() -> None: else: if ioc_to_update: print("\t\t[bold]There are updates to your indicators files! Run the `download-iocs` command to update!") - return + else: + print("\t\tYour indicators files seem to be up to date.") def logo() -> None: diff --git a/mvt/common/updates.py b/mvt/common/updates.py index dba5d90..1e66798 100644 --- a/mvt/common/updates.py +++ b/mvt/common/updates.py @@ -3,12 +3,12 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ -import os -import yaml import logging +import os from datetime import datetime import requests +import yaml from packaging import version from .indicators import MVT_DATA_FOLDER, MVT_INDICATORS_FOLDER @@ -16,6 +16,9 @@ from .version import MVT_VERSION log = logging.getLogger(__name__) +# In hours. +INDICATORS_CHECK_FREQUENCY = 12 + class MVTUpdates: @@ -42,6 +45,24 @@ class IndicatorsUpdates: self.latest_update_path = os.path.join(MVT_DATA_FOLDER, "latest_indicators_update") + self.latest_check_path = os.path.join(MVT_DATA_FOLDER, + "latest_indicators_check") + + def get_latest_check(self) -> int: + if not os.path.exists(self.latest_check_path): + return 0 + + with open(self.latest_check_path, "r") as handle: + data = handle.read().strip() + if data: + return int(data) + + return 0 + + def set_latest_check(self) -> None: + timestamp = int(datetime.utcnow().timestamp()) + with open(self.latest_check_path, "w") as handle: + handle.write(str(timestamp)) def get_latest_update(self) -> int: if not os.path.exists(self.latest_update_path): @@ -50,11 +71,9 @@ class IndicatorsUpdates: with open(self.latest_update_path, "r") as handle: data = handle.read().strip() if data: - latest_update = int(data) - else: - latest_update = 0 + return int(data) - return latest_update + return 0 def set_latest_update(self) -> None: timestamp = int(datetime.utcnow().timestamp()) @@ -144,7 +163,22 @@ class IndicatorsUpdates: return latest_commit_ts + def should_check(self) -> (bool, int): + now = datetime.utcnow() + latest_check_ts = self.get_latest_check() + latest_check_dt = datetime.fromtimestamp(latest_check_ts) + + diff = now - latest_check_dt + diff_hours = divmod(diff.total_seconds(), 3600)[0] + + if diff_hours >= INDICATORS_CHECK_FREQUENCY: + return True, 0 + + return False, INDICATORS_CHECK_FREQUENCY - diff_hours + def check(self) -> bool: + self.set_latest_check() + latest_update = self.get_latest_update() latest_commit_ts = self._get_remote_file_latest_commit(self.index_owner, From b8e5346660e750e2b888a360d3d4f7b235ef78f9 Mon Sep 17 00:00:00 2001 From: Nex Date: Tue, 28 Jun 2022 13:12:09 +0200 Subject: [PATCH 04/10] Updating last check time when forcefully updating iocs --- mvt/common/updates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mvt/common/updates.py b/mvt/common/updates.py index 1e66798..506c8a4 100644 --- a/mvt/common/updates.py +++ b/mvt/common/updates.py @@ -107,6 +107,8 @@ class IndicatorsUpdates: return ioc_path def update(self) -> None: + self.set_latest_check() + if not os.path.exists(MVT_INDICATORS_FOLDER): os.makedirs(MVT_INDICATORS_FOLDER) From ef662c1145d38e08864db64ab17668185e80b033 Mon Sep 17 00:00:00 2001 From: Nex Date: Tue, 28 Jun 2022 15:03:52 +0200 Subject: [PATCH 05/10] Added new indicators update to mvt-android --- mvt/android/cli.py | 5 +++-- mvt/common/updates.py | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mvt/android/cli.py b/mvt/android/cli.py index 0795d84..74deeed 100644 --- a/mvt/android/cli.py +++ b/mvt/android/cli.py @@ -13,8 +13,8 @@ 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 download_indicators_files from mvt.common.logo import logo +from mvt.common.updates import IndicatorsUpdates from .cmd_check_adb import CmdAndroidCheckADB from .cmd_check_backup import CmdAndroidCheckBackup @@ -215,4 +215,5 @@ def check_iocs(ctx, iocs, list_modules, module, folder): #============================================================================== @cli.command("download-iocs", help="Download public STIX2 indicators") def download_indicators(): - download_indicators_files(log) + ioc_updates = IndicatorsUpdates() + ioc_updates.update() diff --git a/mvt/common/updates.py b/mvt/common/updates.py index 506c8a4..f686d75 100644 --- a/mvt/common/updates.py +++ b/mvt/common/updates.py @@ -182,7 +182,6 @@ class IndicatorsUpdates: self.set_latest_check() latest_update = self.get_latest_update() - latest_commit_ts = self._get_remote_file_latest_commit(self.index_owner, self.index_repo, self.index_branch, From b6531e3e70bce1204d64a4558954745ee287afd2 Mon Sep 17 00:00:00 2001 From: Nex Date: Tue, 28 Jun 2022 15:55:52 +0200 Subject: [PATCH 06/10] Forgot closing bold tags --- mvt/common/logo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mvt/common/logo.py b/mvt/common/logo.py index a3ea034..9505ecc 100644 --- a/mvt/common/logo.py +++ b/mvt/common/logo.py @@ -26,7 +26,7 @@ def check_updates() -> None: # Before proceeding, we check if we have downloaded an indicators index. # If not, there's no point in proceeding with the updates check. if ioc_updates.get_latest_update() == 0: - print("\t\t[bold]You have not yet downloaded any indicators, check the `download-iocs` command!") + print("\t\t[bold]You have not yet downloaded any indicators, check the `download-iocs` command![/bold]") return # We only perform this check at a fixed frequency, in order to not @@ -43,7 +43,7 @@ def check_updates() -> None: pass else: if ioc_to_update: - print("\t\t[bold]There are updates to your indicators files! Run the `download-iocs` command to update!") + print("\t\t[bold]There are updates to your indicators files! Run the `download-iocs` command to update![/bold]") else: print("\t\tYour indicators files seem to be up to date.") From f864adf97e6db59b8dd0eaaaa11dec6a58ddd98d Mon Sep 17 00:00:00 2001 From: tek Date: Tue, 28 Jun 2022 20:35:52 +0200 Subject: [PATCH 07/10] First structure for mvt-ios check-usb --- .github/workflows/python-package.yml | 2 +- mvt/ios/cli.py | 33 +++++++++++++- mvt/ios/cmd_check_usb.py | 45 +++++++++++++++++++ mvt/ios/modules/usb/__init__.py | 8 ++++ mvt/ios/modules/usb/base.py | 34 ++++++++++++++ mvt/ios/modules/usb/processes.py | 39 ++++++++++++++++ setup.cfg | 1 + tests/{ios => ios_backup}/__init__.py | 0 tests/{ios => ios_backup}/test_backup_info.py | 0 tests/{ios => ios_backup}/test_datausage.py | 0 tests/{ios => ios_backup}/test_manifest.py | 0 .../test_safari_browserstate.py | 0 tests/{ios => ios_backup}/test_sms.py | 0 tests/{ios => ios_backup}/test_tcc.py | 0 tests/ios_usb/__init__.py | 0 tests/ios_usb/test_processes.py | 31 +++++++++++++ 16 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 mvt/ios/cmd_check_usb.py create mode 100644 mvt/ios/modules/usb/__init__.py create mode 100644 mvt/ios/modules/usb/base.py create mode 100644 mvt/ios/modules/usb/processes.py rename tests/{ios => ios_backup}/__init__.py (100%) rename tests/{ios => ios_backup}/test_backup_info.py (100%) rename tests/{ios => ios_backup}/test_datausage.py (100%) rename tests/{ios => ios_backup}/test_manifest.py (100%) rename tests/{ios => ios_backup}/test_safari_browserstate.py (100%) rename tests/{ios => ios_backup}/test_sms.py (100%) rename tests/{ios => ios_backup}/test_tcc.py (100%) create mode 100644 tests/ios_usb/__init__.py create mode 100644 tests/ios_usb/test_processes.py diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 767248e..36e25de 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -28,7 +28,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 pytest safety stix2 + python -m pip install flake8 pytest safety stix2 pytest-mock if [ -f requirements.txt ]; then pip install -r requirements.txt; fi python -m pip install . - name: Lint with flake8 diff --git a/mvt/ios/cli.py b/mvt/ios/cli.py index 4b5d373..3e159fd 100644 --- a/mvt/ios/cli.py +++ b/mvt/ios/cli.py @@ -13,13 +13,14 @@ 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) + HELP_MSG_OUTPUT, HELP_MSG_SERIAL) from mvt.common.indicators import download_indicators_files from mvt.common.logo import logo from mvt.common.options import MutuallyExclusiveOption from .cmd_check_backup import CmdIOSCheckBackup from .cmd_check_fs import CmdIOSCheckFS +from .cmd_check_usb import CmdIOSCheckUSB from .decrypt import DecryptBackup from .modules.backup import BACKUP_MODULES from .modules.fs import FS_MODULES @@ -214,3 +215,33 @@ def check_iocs(ctx, iocs, list_modules, module, folder): @cli.command("download-iocs", help="Download public STIX2 indicators") def download_iocs(): download_indicators_files(log) + +#============================================================================== +# Command: check-usb +#============================================================================== +@cli.command("check-usb", help="Extract artifacts from a live iPhone through USB / lockdown") +@click.option("--serial", "-s", type=str, help=HELP_MSG_SERIAL) +@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("--fast", "-f", is_flag=True, help=HELP_MSG_FAST) +@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) +@click.option("--module", "-m", help=HELP_MSG_MODULE) +# TODO: serial +# @click.argument("BACKUP_PATH", type=click.Path(exists=True)) +@click.pass_context +def check_usb(ctx, serial, iocs, output, fast, list_modules, module): + cmd = CmdIOSCheckUSB(results_path=output, ioc_files=iocs, + module_name=module, fast_mode=fast, serial=serial) + + if list_modules: + cmd.list_modules() + return + + log.info("Checking iPhone through USB, this may take a while") + cmd.run() + + if len(cmd.timeline_detected) > 0: + log.warning("The analysis of the data produced %d detections!", + len(cmd.timeline_detected)) + diff --git a/mvt/ios/cmd_check_usb.py b/mvt/ios/cmd_check_usb.py new file mode 100644 index 0000000..51ac7b1 --- /dev/null +++ b/mvt/ios/cmd_check_usb.py @@ -0,0 +1,45 @@ +# 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 sys +from pymobiledevice3.lockdown import LockdownClient +from pymobiledevice3.exceptions import ConnectionFailedError + +from mvt.common.command import Command + +from .modules.usb import USB_MODULES + +log = logging.getLogger(__name__) + + +class CmdIOSCheckUSB(Command): + + name = "check-usb" + modules = USB_MODULES + + def __init__(self, target_path: str = None, results_path: str = None, + ioc_files: list = [], module_name: str = None, serial: str = None, + fast_mode: bool = 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.lockdown = None + + def init(self): + try: + if self.serial: + self.lockdown = LockdownClient(udid=self.serial) + else: + self.lockdown = LockdownClient() + except ConnectionRefusedError: + log.error("Unable to connect to the device over USB. Try to unplug, plug the device and start again.") + sys.exit(-1) + except ConnectionFailedError: + log.error("Unable to connect to the device %s", self.serial) + sys.exit(-1) + + def module_init(self, module): + module.lockdown = self.lockdown diff --git a/mvt/ios/modules/usb/__init__.py b/mvt/ios/modules/usb/__init__.py new file mode 100644 index 0000000..67e985f --- /dev/null +++ b/mvt/ios/modules/usb/__init__.py @@ -0,0 +1,8 @@ +# 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/ + +from .processes import Processes + +USB_MODULES = [Processes] diff --git a/mvt/ios/modules/usb/base.py b/mvt/ios/modules/usb/base.py new file mode 100644 index 0000000..0ed0076 --- /dev/null +++ b/mvt/ios/modules/usb/base.py @@ -0,0 +1,34 @@ +# 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 base64 +import getpass +import logging +import os +import random +import string +import sys +import tempfile +import time +from typing import Callable + +from mvt.common.module import InsufficientPrivileges, MVTModule + +log = logging.getLogger(__name__) + + +class IOSUSBExtraction(MVTModule): + """This class provides a base for all iOS USB extraction modules.""" + + def __init__(self, file_path: str = None, target_path: str = None, + results_path: str = None, fast_mode: bool = False, + log: logging.Logger = None, results: list = []) -> None: + 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 + self.serial = None + self.lockdown = None diff --git a/mvt/ios/modules/usb/processes.py b/mvt/ios/modules/usb/processes.py new file mode 100644 index 0000000..0c9137a --- /dev/null +++ b/mvt/ios/modules/usb/processes.py @@ -0,0 +1,39 @@ +# 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 pymobiledevice3.services.os_trace import OsTraceService + +from .base import IOSUSBExtraction + + +class Processes(IOSUSBExtraction): + """This class extracts all processes running on the phone.""" + def __init__(self, file_path: str = None, target_path: str = None, + results_path: str = None, fast_mode: bool = False, + log: logging.Logger = None, results: list = []) -> None: + 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) -> None: + if not self.indicators: + return + + for result in self.results: + ioc = self.indicators.check_process(result["name"]) + if ioc: + result["matched_indicator"] = ioc + self.detected.append(result) + + def run(self) -> None: + processes = OsTraceService(lockdown=self.lockdown).get_pid_list().get('Payload') + for p in processes: + self.results.append({ + "pid": p, + "name": processes[p]["ProcessName"] + }) + + self.log.info("{} running processes identified on the phone".format(len(self.results))) diff --git a/setup.cfg b/setup.cfg index 9f91876..65048ee 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,7 @@ install_requires = adb-shell >=0.4.2 libusb1 >=2.0.1 cryptography >=36.0.1 + pymobiledevice3 >= 1.23.9 [options.packages.find] where = ./ diff --git a/tests/ios/__init__.py b/tests/ios_backup/__init__.py similarity index 100% rename from tests/ios/__init__.py rename to tests/ios_backup/__init__.py diff --git a/tests/ios/test_backup_info.py b/tests/ios_backup/test_backup_info.py similarity index 100% rename from tests/ios/test_backup_info.py rename to tests/ios_backup/test_backup_info.py diff --git a/tests/ios/test_datausage.py b/tests/ios_backup/test_datausage.py similarity index 100% rename from tests/ios/test_datausage.py rename to tests/ios_backup/test_datausage.py diff --git a/tests/ios/test_manifest.py b/tests/ios_backup/test_manifest.py similarity index 100% rename from tests/ios/test_manifest.py rename to tests/ios_backup/test_manifest.py diff --git a/tests/ios/test_safari_browserstate.py b/tests/ios_backup/test_safari_browserstate.py similarity index 100% rename from tests/ios/test_safari_browserstate.py rename to tests/ios_backup/test_safari_browserstate.py diff --git a/tests/ios/test_sms.py b/tests/ios_backup/test_sms.py similarity index 100% rename from tests/ios/test_sms.py rename to tests/ios_backup/test_sms.py diff --git a/tests/ios/test_tcc.py b/tests/ios_backup/test_tcc.py similarity index 100% rename from tests/ios/test_tcc.py rename to tests/ios_backup/test_tcc.py diff --git a/tests/ios_usb/__init__.py b/tests/ios_usb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ios_usb/test_processes.py b/tests/ios_usb/test_processes.py new file mode 100644 index 0000000..9fc5567 --- /dev/null +++ b/tests/ios_usb/test_processes.py @@ -0,0 +1,31 @@ +# 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.module import run_module +from mvt.ios.modules.usb.processes import Processes +from mvt.common.indicators import Indicators + + +class TestUSBProcesses: + def test_run(self, mocker, indicator_file): + # Mock + mocker.patch("pymobiledevice3.services.base_service.BaseService.__init__") + mocker.patch( + "pymobiledevice3.services.os_trace.OsTraceService.get_pid_list", + return_value={"Payload": {"1": {"ProcessName": "storebookkeeperd"}, "1854": {"ProcessName": "cfprefssd"}}} + ) + + # indicators + ind = Indicators(log=logging) + ind.parse_stix2(indicator_file) + ind.ioc_collections[0]["processes"].append("cfprefssd") + + m = Processes(log=logging) + m.indicators = ind + run_module(m) + assert len(m.results) == 2 + assert len(m.detected) == 1 From f98282d6c5909ab0722c2a4729be67ee5e8e0885 Mon Sep 17 00:00:00 2001 From: tek Date: Tue, 28 Jun 2022 23:37:57 +0200 Subject: [PATCH 08/10] Adds applications and device info iOS USB modules --- mvt/ios/cli.py | 5 ++-- mvt/ios/modules/usb/__init__.py | 4 ++- mvt/ios/modules/usb/applications.py | 42 +++++++++++++++++++++++++++++ mvt/ios/modules/usb/device_info.py | 39 +++++++++++++++++++++++++++ tests/ios_usb/test_applications.py | 35 ++++++++++++++++++++++++ tests/ios_usb/test_device_info.py | 34 +++++++++++++++++++++++ 6 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 mvt/ios/modules/usb/applications.py create mode 100644 mvt/ios/modules/usb/device_info.py create mode 100644 tests/ios_usb/test_applications.py create mode 100644 tests/ios_usb/test_device_info.py diff --git a/mvt/ios/cli.py b/mvt/ios/cli.py index 3e159fd..8979265 100644 --- a/mvt/ios/cli.py +++ b/mvt/ios/cli.py @@ -216,6 +216,7 @@ def check_iocs(ctx, iocs, list_modules, module, folder): def download_iocs(): download_indicators_files(log) + #============================================================================== # Command: check-usb #============================================================================== @@ -232,7 +233,8 @@ def download_iocs(): @click.pass_context def check_usb(ctx, serial, iocs, output, fast, list_modules, module): cmd = CmdIOSCheckUSB(results_path=output, ioc_files=iocs, - module_name=module, fast_mode=fast, serial=serial) + module_name=module, fast_mode=fast, + serial=serial) if list_modules: cmd.list_modules() @@ -244,4 +246,3 @@ def check_usb(ctx, serial, iocs, output, fast, list_modules, module): if len(cmd.timeline_detected) > 0: log.warning("The analysis of the data produced %d detections!", len(cmd.timeline_detected)) - diff --git a/mvt/ios/modules/usb/__init__.py b/mvt/ios/modules/usb/__init__.py index 67e985f..b957a4d 100644 --- a/mvt/ios/modules/usb/__init__.py +++ b/mvt/ios/modules/usb/__init__.py @@ -3,6 +3,8 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ +from .applications import Applications +from .device_info import DeviceInfo from .processes import Processes -USB_MODULES = [Processes] +USB_MODULES = [Applications, DeviceInfo, Processes] diff --git a/mvt/ios/modules/usb/applications.py b/mvt/ios/modules/usb/applications.py new file mode 100644 index 0000000..85e1c2d --- /dev/null +++ b/mvt/ios/modules/usb/applications.py @@ -0,0 +1,42 @@ +# 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 pymobiledevice3.services.installation_proxy import InstallationProxyService + +from .base import IOSUSBExtraction + + +class Applications(IOSUSBExtraction): + """This class extracts all applications installed on the phone""" + def __init__(self, file_path: str = None, target_path: str = None, + results_path: str = None, fast_mode: bool = False, + log: logging.Logger = None, results: list = []) -> None: + 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) -> None: + if not self.indicators: + return + + for result in self.results: + ioc = self.indicators.check_app_id(result["CFBundleIdentifier"]) + if ioc: + result["matched_indicator"] = ioc + self.detected.append(result) + + def run(self) -> None: + user_apps = InstallationProxyService(lockdown=self.lockdown).get_apps("User") + for u in user_apps: + u["type"] = "user" + + system_apps = InstallationProxyService(lockdown=self.lockdown).get_apps("System") + for s in system_apps: + s["type"] = "system" + + self.results = user_apps + system_apps + + self.log.info("{} applications identified on the phone".format(len(self.results))) diff --git a/mvt/ios/modules/usb/device_info.py b/mvt/ios/modules/usb/device_info.py new file mode 100644 index 0000000..16a03cb --- /dev/null +++ b/mvt/ios/modules/usb/device_info.py @@ -0,0 +1,39 @@ +# 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 base64 + +from mvt.ios.versions import latest_ios_version + +from .base import IOSUSBExtraction + + +class DeviceInfo(IOSUSBExtraction): + """This class extracts all processes running on the phone.""" + def __init__(self, file_path: str = None, target_path: str = None, + results_path: str = None, fast_mode: bool = False, + log: logging.Logger = None, results: list = []) -> None: + 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) -> None: + self.results = self.lockdown.all_values + + # Base64 encoding of bytes + for entry in self.results: + if isinstance(self.results[entry], bytes): + self.results[entry] = base64.b64encode(self.results[entry]) + elif isinstance(self.results[entry], dict): + for second_entry in self.results[entry]: + if isinstance(self.results[entry][second_entry], bytes): + self.results[entry][second_entry] = base64.b64encode(self.results[entry][second_entry]) + + if "ProductVersion" in self.results: + latest = latest_ios_version() + if self.results["ProductVersion"] != latest["version"]: + self.log.warning("This phone is running an outdated iOS version: %s (latest is %s)", + self.results["ProductVersion"], latest['version']) diff --git a/tests/ios_usb/test_applications.py b/tests/ios_usb/test_applications.py new file mode 100644 index 0000000..e8493fb --- /dev/null +++ b/tests/ios_usb/test_applications.py @@ -0,0 +1,35 @@ +# 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.module import run_module +from mvt.ios.modules.usb.applications import Applications +from pymobiledevice3.lockdown import LockdownClient + + +class TestUSBApplication: + def test_run(self, mocker): + # Mock + mocker.patch("pymobiledevice3.lockdown.LockdownClient.start_service") + mocker.patch("pymobiledevice3.usbmux.select_device") + mocker.patch("pymobiledevice3.service_connection.ServiceConnection.create") + mocker.patch( + "pymobiledevice3.lockdown.LockdownClient.query_type", + return_value="com.apple.mobile.lockdown") + mocker.patch( + "pymobiledevice3.lockdown.LockdownClient.validate_pairing", + return_value=True) + mocker.patch( + "pymobiledevice3.services.installation_proxy.InstallationProxyService.get_apps", + return_value=[{"CFBundleIdentifier": "com.bad.app"}] + ) + + lockdown = LockdownClient() + + m = Applications(log=logging) + m.lockdown = lockdown + run_module(m) + assert len(m.results) == 2 diff --git a/tests/ios_usb/test_device_info.py b/tests/ios_usb/test_device_info.py new file mode 100644 index 0000000..ca435df --- /dev/null +++ b/tests/ios_usb/test_device_info.py @@ -0,0 +1,34 @@ +# 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.module import run_module +from mvt.ios.modules.usb.device_info import DeviceInfo +from pymobiledevice3.lockdown import LockdownClient + + +class TestUSBDeviceInfo: + def test_run(self, mocker): + # Mock + mocker.patch("pymobiledevice3.usbmux.select_device") + mocker.patch("pymobiledevice3.service_connection.ServiceConnection.create") + mocker.patch( + "pymobiledevice3.lockdown.LockdownClient.query_type", + return_value="com.apple.mobile.lockdown") + mocker.patch( + "pymobiledevice3.lockdown.LockdownClient.validate_pairing", + return_value=True) + mocker.patch( + "pymobiledevice3.lockdown.LockdownClient.get_value", + return_value={'DeviceClass': 'iPhone', 'ProductVersion': '14.3'} + ) + + lockdown = LockdownClient() + + m = DeviceInfo(log=logging) + m.lockdown = lockdown + run_module(m) + assert len(m.results) == 2 From 7222bc82e1c7ceeed17cc8d70d3708a05ba829c7 Mon Sep 17 00:00:00 2001 From: Nex Date: Wed, 29 Jun 2022 00:05:36 +0200 Subject: [PATCH 09/10] Sorting imports and removing unused ones --- mvt/ios/cmd_check_usb.py | 3 ++- mvt/ios/modules/usb/applications.py | 4 +++- mvt/ios/modules/usb/base.py | 11 +---------- mvt/ios/modules/usb/device_info.py | 2 +- mvt/ios/modules/usb/processes.py | 1 + tests/ios_usb/test_applications.py | 4 ++-- tests/ios_usb/test_device_info.py | 4 ++-- tests/ios_usb/test_processes.py | 4 +--- 8 files changed, 13 insertions(+), 20 deletions(-) diff --git a/mvt/ios/cmd_check_usb.py b/mvt/ios/cmd_check_usb.py index 51ac7b1..0a48f1d 100644 --- a/mvt/ios/cmd_check_usb.py +++ b/mvt/ios/cmd_check_usb.py @@ -5,8 +5,9 @@ import logging import sys -from pymobiledevice3.lockdown import LockdownClient + from pymobiledevice3.exceptions import ConnectionFailedError +from pymobiledevice3.lockdown import LockdownClient from mvt.common.command import Command diff --git a/mvt/ios/modules/usb/applications.py b/mvt/ios/modules/usb/applications.py index 85e1c2d..d010469 100644 --- a/mvt/ios/modules/usb/applications.py +++ b/mvt/ios/modules/usb/applications.py @@ -4,7 +4,9 @@ # https://license.mvt.re/1.1/ import logging -from pymobiledevice3.services.installation_proxy import InstallationProxyService + +from pymobiledevice3.services.installation_proxy import \ + InstallationProxyService from .base import IOSUSBExtraction diff --git a/mvt/ios/modules/usb/base.py b/mvt/ios/modules/usb/base.py index 0ed0076..e08e232 100644 --- a/mvt/ios/modules/usb/base.py +++ b/mvt/ios/modules/usb/base.py @@ -3,18 +3,9 @@ # 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 random -import string -import sys -import tempfile -import time -from typing import Callable -from mvt.common.module import InsufficientPrivileges, MVTModule +from mvt.common.module import MVTModule log = logging.getLogger(__name__) diff --git a/mvt/ios/modules/usb/device_info.py b/mvt/ios/modules/usb/device_info.py index 16a03cb..de7cafc 100644 --- a/mvt/ios/modules/usb/device_info.py +++ b/mvt/ios/modules/usb/device_info.py @@ -3,8 +3,8 @@ # 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 base64 +import logging from mvt.ios.versions import latest_ios_version diff --git a/mvt/ios/modules/usb/processes.py b/mvt/ios/modules/usb/processes.py index 0c9137a..8663da2 100644 --- a/mvt/ios/modules/usb/processes.py +++ b/mvt/ios/modules/usb/processes.py @@ -4,6 +4,7 @@ # https://license.mvt.re/1.1/ import logging + from pymobiledevice3.services.os_trace import OsTraceService from .base import IOSUSBExtraction diff --git a/tests/ios_usb/test_applications.py b/tests/ios_usb/test_applications.py index e8493fb..90607ea 100644 --- a/tests/ios_usb/test_applications.py +++ b/tests/ios_usb/test_applications.py @@ -5,14 +5,14 @@ import logging +from pymobiledevice3.lockdown import LockdownClient + from mvt.common.module import run_module from mvt.ios.modules.usb.applications import Applications -from pymobiledevice3.lockdown import LockdownClient class TestUSBApplication: def test_run(self, mocker): - # Mock mocker.patch("pymobiledevice3.lockdown.LockdownClient.start_service") mocker.patch("pymobiledevice3.usbmux.select_device") mocker.patch("pymobiledevice3.service_connection.ServiceConnection.create") diff --git a/tests/ios_usb/test_device_info.py b/tests/ios_usb/test_device_info.py index ca435df..349623d 100644 --- a/tests/ios_usb/test_device_info.py +++ b/tests/ios_usb/test_device_info.py @@ -5,14 +5,14 @@ import logging +from pymobiledevice3.lockdown import LockdownClient + from mvt.common.module import run_module from mvt.ios.modules.usb.device_info import DeviceInfo -from pymobiledevice3.lockdown import LockdownClient class TestUSBDeviceInfo: def test_run(self, mocker): - # Mock mocker.patch("pymobiledevice3.usbmux.select_device") mocker.patch("pymobiledevice3.service_connection.ServiceConnection.create") mocker.patch( diff --git a/tests/ios_usb/test_processes.py b/tests/ios_usb/test_processes.py index 9fc5567..26c446f 100644 --- a/tests/ios_usb/test_processes.py +++ b/tests/ios_usb/test_processes.py @@ -5,21 +5,19 @@ import logging +from mvt.common.indicators import Indicators from mvt.common.module import run_module from mvt.ios.modules.usb.processes import Processes -from mvt.common.indicators import Indicators class TestUSBProcesses: def test_run(self, mocker, indicator_file): - # Mock mocker.patch("pymobiledevice3.services.base_service.BaseService.__init__") mocker.patch( "pymobiledevice3.services.os_trace.OsTraceService.get_pid_list", return_value={"Payload": {"1": {"ProcessName": "storebookkeeperd"}, "1854": {"ProcessName": "cfprefssd"}}} ) - # indicators ind = Indicators(log=logging) ind.parse_stix2(indicator_file) ind.ioc_collections[0]["processes"].append("cfprefssd") From 298726ab2b2c012264c4f432589d4c1b7da0552a Mon Sep 17 00:00:00 2001 From: Nex Date: Wed, 29 Jun 2022 00:57:25 +0200 Subject: [PATCH 10/10] Minor style fixes --- mvt/ios/modules/usb/applications.py | 11 ++++++----- mvt/ios/modules/usb/device_info.py | 1 - mvt/ios/modules/usb/processes.py | 10 ++++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mvt/ios/modules/usb/applications.py b/mvt/ios/modules/usb/applications.py index d010469..41b58c2 100644 --- a/mvt/ios/modules/usb/applications.py +++ b/mvt/ios/modules/usb/applications.py @@ -32,13 +32,14 @@ class Applications(IOSUSBExtraction): def run(self) -> None: user_apps = InstallationProxyService(lockdown=self.lockdown).get_apps("User") - for u in user_apps: - u["type"] = "user" + for user_app in user_apps: + user_app["type"] = "user" system_apps = InstallationProxyService(lockdown=self.lockdown).get_apps("System") - for s in system_apps: - s["type"] = "system" + for system_app in system_apps: + system_app["type"] = "system" self.results = user_apps + system_apps - self.log.info("{} applications identified on the phone".format(len(self.results))) + self.log.info("%d applications identified on the phone", + len(self.results)) diff --git a/mvt/ios/modules/usb/device_info.py b/mvt/ios/modules/usb/device_info.py index de7cafc..62c43fc 100644 --- a/mvt/ios/modules/usb/device_info.py +++ b/mvt/ios/modules/usb/device_info.py @@ -23,7 +23,6 @@ class DeviceInfo(IOSUSBExtraction): def run(self) -> None: self.results = self.lockdown.all_values - # Base64 encoding of bytes for entry in self.results: if isinstance(self.results[entry], bytes): self.results[entry] = base64.b64encode(self.results[entry]) diff --git a/mvt/ios/modules/usb/processes.py b/mvt/ios/modules/usb/processes.py index 8663da2..e2a14ec 100644 --- a/mvt/ios/modules/usb/processes.py +++ b/mvt/ios/modules/usb/processes.py @@ -12,6 +12,7 @@ from .base import IOSUSBExtraction class Processes(IOSUSBExtraction): """This class extracts all processes running on the phone.""" + def __init__(self, file_path: str = None, target_path: str = None, results_path: str = None, fast_mode: bool = False, log: logging.Logger = None, results: list = []) -> None: @@ -31,10 +32,11 @@ class Processes(IOSUSBExtraction): def run(self) -> None: processes = OsTraceService(lockdown=self.lockdown).get_pid_list().get('Payload') - for p in processes: + for pid in processes: self.results.append({ - "pid": p, - "name": processes[p]["ProcessName"] + "pid": pid, + "name": processes[pid]["ProcessName"] }) - self.log.info("{} running processes identified on the phone".format(len(self.results))) + self.log.info("%d running processes identified on the phone", + len(self.results))