mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-30 21:19:41 +02:00
Fix merge conflicts
This commit is contained in:
commit
15c0d71933
82 files changed
+1261
-579
No files matched your search
+3
-3
@@ -1,4 +1,4 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
@@ -1,6 +1,6 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .cli import cli
|
||||
+33
-14
@@ -1,17 +1,19 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 sys
|
||||
import click
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import click
|
||||
from rich.logging import RichHandler
|
||||
|
||||
from mvt.common.module import run_module, save_timeline
|
||||
from mvt.common.indicators import Indicators
|
||||
from mvt.common.module import run_module, save_timeline
|
||||
|
||||
from .download_apks import DownloadAPKs
|
||||
from .lookups.koodous import koodous_lookup
|
||||
from .lookups.virustotal import virustotal_lookup
|
||||
@@ -45,8 +47,8 @@ def cli():
|
||||
@click.option("--virustotal", "-v", is_flag=True, help="Check packages on VirusTotal")
|
||||
@click.option("--koodous", "-k", is_flag=True, help="Check packages on Koodous")
|
||||
@click.option("--all-checks", "-A", is_flag=True, help="Run all available checks")
|
||||
@click.option("--output", "-o", type=click.Path(exists=True),
|
||||
help="Specify a path to a folder where you want to store JSON results")
|
||||
@click.option("--output", "-o", type=click.Path(exists=False),
|
||||
help="Specify a path to a folder where you want to store the APKs")
|
||||
@click.option("--from-file", "-f", type=click.Path(exists=True),
|
||||
help="Instead of acquiring from phone, load an existing packages.json file for lookups (mainly for debug purposes)")
|
||||
@click.option("--serial", "-s", type=str, help="Use the Android device with a given serial number")
|
||||
@@ -55,9 +57,12 @@ def download_apks(all_apks, virustotal, koodous, all_checks, output, from_file,
|
||||
if from_file:
|
||||
download = DownloadAPKs.from_json(from_file)
|
||||
else:
|
||||
if not output:
|
||||
log.critical("You need to specify an output folder (with --output, -o) when extracting APKs from a device")
|
||||
sys.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)
|
||||
sys.exit(-1)
|
||||
|
||||
download = DownloadAPKs(output_folder=output, all_apks=all_apks, serial=serial)
|
||||
download.run()
|
||||
@@ -82,7 +87,7 @@ def download_apks(all_apks, virustotal, koodous, all_checks, output, from_file,
|
||||
#==============================================================================
|
||||
@cli.command("check-adb", help="Check an Android device over adb")
|
||||
@click.option("--iocs", "-i", type=click.Path(exists=True), help="Path to indicators file")
|
||||
@click.option("--output", "-o", type=click.Path(exists=True),
|
||||
@click.option("--output", "-o", type=click.Path(exists=False),
|
||||
help="Specify a path to a folder where you want to store JSON results")
|
||||
@click.option("--list-modules", "-l", is_flag=True, help="Print list of available modules and exit")
|
||||
@click.option("--module", "-m", help="Name of a single module you would like to run instead of all")
|
||||
@@ -97,6 +102,13 @@ def check_adb(iocs, output, list_modules, module, serial):
|
||||
|
||||
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)
|
||||
sys.exit(-1)
|
||||
|
||||
if iocs:
|
||||
# Pre-load indicators for performance reasons.
|
||||
log.info("Loading indicators from provided file at %s", iocs)
|
||||
@@ -129,12 +141,19 @@ def check_adb(iocs, output, list_modules, module, serial):
|
||||
#==============================================================================
|
||||
@cli.command("check-backup", help="Check an Android Backup")
|
||||
@click.option("--iocs", "-i", type=click.Path(exists=True), help="Path to indicators file")
|
||||
@click.option("--output", "-o", type=click.Path(exists=True), help=OUTPUT_HELP_MESSAGE)
|
||||
@click.option("--output", "-o", type=click.Path(exists=False), help=OUTPUT_HELP_MESSAGE)
|
||||
@click.option("--serial", "-s", type=str, help="Use the Android device with a given serial")
|
||||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||
def check_backup(iocs, output, backup_path, serial):
|
||||
log.info("Checking ADB 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)
|
||||
sys.exit(-1)
|
||||
|
||||
if iocs:
|
||||
# Pre-load indicators for performance reasons.
|
||||
log.info("Loading indicators from provided file at %s", iocs)
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pkg_resources
|
||||
from tqdm import tqdm
|
||||
|
||||
from mvt.common.utils import get_sha256_from_file_path
|
||||
|
||||
from .modules.adb.base import AndroidExtraction
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# TODO: Would be better to replace tqdm with rich.progress to reduce
|
||||
# the number of dependencies. Need to investigate whether
|
||||
# it's possible to have a simialr callback system.
|
||||
# it's possible to have a similar callback system.
|
||||
class PullProgress(tqdm):
|
||||
"""PullProgress is a tqdm update system for APK downloads."""
|
||||
|
||||
@@ -42,7 +44,7 @@ class DownloadAPKs(AndroidExtraction):
|
||||
"""Initialize module.
|
||||
:param output_folder: Path to the folder where data should be stored
|
||||
:param all_apks: Boolean indicating whether to download all packages
|
||||
or filter known-goods
|
||||
or filter known-goods
|
||||
:param packages: Provided list of packages, typically for JSON checks
|
||||
:param serial: The USB device serial ID
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
@@ -1,15 +1,15 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import requests
|
||||
import logging
|
||||
|
||||
from rich.text import Text
|
||||
from rich.table import Table
|
||||
from rich.progress import track
|
||||
import requests
|
||||
from rich.console import Console
|
||||
from rich.progress import track
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 requests
|
||||
import logging
|
||||
from rich.text import Text
|
||||
from rich.table import Table
|
||||
from rich.progress import track
|
||||
from rich.console import Console
|
||||
from rich.progress import track
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
@@ -1,17 +1,17 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .chrome_history import ChromeHistory
|
||||
from .dumpsys_batterystats import DumpsysBatterystats
|
||||
from .dumpsys_packages import DumpsysPackages
|
||||
from .dumpsys_procstats import DumpsysProcstats
|
||||
from .packages import Packages
|
||||
from .processes import Processes
|
||||
from .rootbinaries import RootBinaries
|
||||
from .sms import SMS
|
||||
from .whatsapp import Whatsapp
|
||||
from .packages import Packages
|
||||
from .rootbinaries import RootBinaries
|
||||
|
||||
ADB_MODULES = [ChromeHistory, SMS, Whatsapp, Processes,
|
||||
DumpsysBatterystats, DumpsysProcstats,
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 sys
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from adb_shell.adb_device import AdbDeviceUsb, AdbDeviceTcp
|
||||
from adb_shell.auth.keygen import keygen, write_public_keyfile
|
||||
from adb_shell.auth.sign_pythonrsa import PythonRSASigner
|
||||
from adb_shell.exceptions import DeviceAuthError, AdbCommandFailureException
|
||||
from usb1 import USBErrorBusy, USBErrorAccess
|
||||
from adb_shell.exceptions import AdbCommandFailureException, DeviceAuthError
|
||||
from usb1 import USBErrorAccess, USBErrorBusy
|
||||
|
||||
from mvt.common.module import MVTModule
|
||||
from mvt.common.module import MVTModule, InsufficientPrivileges
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -106,13 +108,13 @@ class AndroidExtraction(MVTModule):
|
||||
"""Check if we have a `su` binary on the Android device.
|
||||
:returns: Boolean indicating whether a `su` binary is present or not
|
||||
"""
|
||||
return bool(self._adb_command("[ ! -f /sbin/su ] || echo 1"))
|
||||
return bool(self._adb_command("command -v su"))
|
||||
|
||||
def _adb_root_or_die(self):
|
||||
"""Check if we have a `su` binary, otherwise raise an Exception.
|
||||
"""
|
||||
if not self._adb_check_if_root():
|
||||
raise Exception("The Android device does not seem to have a `su` binary. Cannot run this module.")
|
||||
raise InsufficientPrivileges("The Android device does not seem to have a `su` binary. Cannot run this module.")
|
||||
|
||||
def _adb_command_as_root(self, command):
|
||||
"""Execute an adb shell command.
|
||||
@@ -120,8 +122,23 @@ class AndroidExtraction(MVTModule):
|
||||
:returns: Output of command
|
||||
"""
|
||||
return self._adb_command(f"su -c {command}")
|
||||
|
||||
def _adb_check_file_exists(self, file):
|
||||
"""Verify that a file exists.
|
||||
:param file: Path of the file
|
||||
:returns: Boolean indicating whether the file exists or not
|
||||
"""
|
||||
|
||||
def _adb_download(self, remote_path, local_path, progress_callback=None):
|
||||
# TODO: Need to support checking files without root privileges as well.
|
||||
|
||||
# Connect to the device over adb.
|
||||
self._adb_connect()
|
||||
# Check if we have root, if not raise an Exception.
|
||||
self._adb_root_or_die()
|
||||
|
||||
return bool(self._adb_command_as_root(f"[ ! -f {file} ] || echo 1"))
|
||||
|
||||
def _adb_download(self, remote_path, local_path, progress_callback=None, retry_root=True):
|
||||
"""Download a file form the device.
|
||||
:param remote_path: Path to download from the device
|
||||
:param local_path: Path to where to locally store the copy of the file
|
||||
@@ -129,6 +146,37 @@ class AndroidExtraction(MVTModule):
|
||||
"""
|
||||
try:
|
||||
self.device.pull(remote_path, local_path, progress_callback)
|
||||
except AdbCommandFailureException as e:
|
||||
if retry_root:
|
||||
self._adb_download_root(remote_path, local_path, progress_callback)
|
||||
else:
|
||||
raise Exception(f"Unable to download file {remote_path}: {e}")
|
||||
|
||||
def _adb_download_root(self, remote_path, local_path, progress_callback=None):
|
||||
try:
|
||||
# Check if we have root, if not raise an Exception.
|
||||
self._adb_root_or_die()
|
||||
|
||||
# We generate a random temporary filename.
|
||||
tmp_filename = "tmp_" + ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=10))
|
||||
|
||||
# We create a temporary local file.
|
||||
new_remote_path = f"/sdcard/{tmp_filename}"
|
||||
|
||||
# We copy the file from the data folder to /sdcard/.
|
||||
cp = self._adb_command_as_root(f"cp {remote_path} {new_remote_path}")
|
||||
if cp.startswith("cp: ") and "No such file or directory" in cp:
|
||||
raise Exception(f"Unable to process file {remote_path}: File not found")
|
||||
elif cp.startswith("cp: ") and "Permission denied" in cp:
|
||||
raise Exception(f"Unable to process file {remote_path}: Permission denied")
|
||||
|
||||
# We download from /sdcard/ to the local temporary file.
|
||||
# If it doesn't work now, don't try again (retry_root=False)
|
||||
self._adb_download(new_remote_path, local_path, retry_root=False)
|
||||
|
||||
# Delete the copy on /sdcard/.
|
||||
self._adb_command(f"rm -rf {new_remote_path}")
|
||||
|
||||
except AdbCommandFailureException as e:
|
||||
raise Exception(f"Unable to download file {remote_path}: {e}")
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 sqlite3
|
||||
import logging
|
||||
|
||||
from mvt.common.utils import convert_chrometime_to_unix, convert_timestamp_to_iso
|
||||
from mvt.common.utils import (convert_chrometime_to_unix,
|
||||
convert_timestamp_to_iso)
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 logging
|
||||
import os
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 logging
|
||||
import os
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 logging
|
||||
import os
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 logging
|
||||
import os
|
||||
|
||||
import pkg_resources
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 logging
|
||||
import os
|
||||
|
||||
import pkg_resources
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
@@ -1,18 +1,43 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 sqlite3
|
||||
import logging
|
||||
|
||||
from mvt.common.utils import check_for_links, convert_timestamp_to_iso
|
||||
|
||||
from .base import AndroidExtraction
|
||||
from mvt.common.utils import convert_timestamp_to_iso, check_for_links
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
SMS_PATH = "data/data/com.google.android.apps.messaging/databases/bugle_db"
|
||||
SMS_BUGLE_PATH = "data/data/com.google.android.apps.messaging/databases/bugle_db"
|
||||
SMS_BUGLE_QUERY = """
|
||||
SELECT
|
||||
ppl.normalized_destination AS number,
|
||||
p.timestamp AS timestamp,
|
||||
CASE WHEN m.sender_id IN
|
||||
(SELECT _id FROM participants WHERE contact_id=-1)
|
||||
THEN 2 ELSE 1 END incoming, p.text AS text
|
||||
FROM messages m, conversations c, parts p,
|
||||
participants ppl, conversation_participants cp
|
||||
WHERE (m.conversation_id = c._id)
|
||||
AND (m._id = p.message_id)
|
||||
AND (cp.conversation_id = c._id)
|
||||
AND (cp.participant_id = ppl._id);
|
||||
"""
|
||||
|
||||
SMS_MMSSMS_PATH = "data/data/com.android.providers.telephony/databases/mmssms.db"
|
||||
SMS_MMSMS_QUERY = """
|
||||
SELECT
|
||||
address AS number,
|
||||
date_sent AS timestamp,
|
||||
type as incoming,
|
||||
body AS text
|
||||
FROM sms;
|
||||
"""
|
||||
|
||||
class SMS(AndroidExtraction):
|
||||
"""This module extracts all SMS messages containing links."""
|
||||
@@ -50,20 +75,12 @@ class SMS(AndroidExtraction):
|
||||
"""
|
||||
conn = sqlite3.connect(db_path)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT
|
||||
ppl.normalized_destination AS number,
|
||||
p.timestamp AS timestamp,
|
||||
CASE WHEN m.sender_id IN
|
||||
(SELECT _id FROM participants WHERE contact_id=-1)
|
||||
THEN 2 ELSE 1 END incoming, p.text AS text
|
||||
FROM messages m, conversations c, parts p,
|
||||
participants ppl, conversation_participants cp
|
||||
WHERE (m.conversation_id = c._id)
|
||||
AND (m._id = p.message_id)
|
||||
AND (cp.conversation_id = c._id)
|
||||
AND (cp.participant_id = ppl._id);
|
||||
""")
|
||||
|
||||
if (self.SMS_DB_TYPE == 1):
|
||||
cur.execute(SMS_BUGLE_QUERY)
|
||||
elif (self.SMS_DB_TYPE == 2):
|
||||
cur.execute(SMS_MMSMS_QUERY)
|
||||
|
||||
names = [description[0] for description in cur.description]
|
||||
|
||||
for item in cur:
|
||||
@@ -85,7 +102,15 @@ class SMS(AndroidExtraction):
|
||||
log.info("Extracted a total of %d SMS messages containing links", len(self.results))
|
||||
|
||||
def run(self):
|
||||
# Checking the SMS database path
|
||||
try:
|
||||
self._adb_process_file(os.path.join("/", SMS_PATH), self._parse_db)
|
||||
if (self._adb_check_file_exists(os.path.join("/", SMS_BUGLE_PATH))):
|
||||
self.SMS_DB_TYPE = 1
|
||||
self._adb_process_file(os.path.join("/", SMS_BUGLE_PATH), self._parse_db)
|
||||
elif (self._adb_check_file_exists(os.path.join("/", SMS_MMSSMS_PATH))):
|
||||
self.SMS_DB_TYPE = 2
|
||||
self._adb_process_file(os.path.join("/", SMS_MMSSMS_PATH), self._parse_db)
|
||||
else:
|
||||
self.log.error("No SMS database found")
|
||||
except Exception as e:
|
||||
self.log.error(e)
|
||||
@@ -1,14 +1,16 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 logging
|
||||
import os
|
||||
import sqlite3
|
||||
import logging
|
||||
|
||||
from mvt.common.utils import check_for_links, convert_timestamp_to_iso
|
||||
|
||||
from .base import AndroidExtraction
|
||||
from mvt.common.utils import convert_timestamp_to_iso, check_for_links
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -69,6 +71,8 @@ class Whatsapp(AndroidExtraction):
|
||||
|
||||
# If we find links in the messages or if they are empty we add them to the list.
|
||||
if check_for_links(message["data"]) or message["data"].strip() == "":
|
||||
if (message.get('thumb_image') is not None):
|
||||
message['thumb_image'] = base64.b64encode(message['thumb_image'])
|
||||
messages.append(message)
|
||||
|
||||
cur.close()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .sms import SMS
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 json
|
||||
import os
|
||||
import zlib
|
||||
|
||||
from mvt.common.module import MVTModule
|
||||
from mvt.common.utils import check_for_links
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
from mvt.common.utils import check_for_links, convert_timestamp_to_iso
|
||||
|
||||
|
||||
class SMS(MVTModule):
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
@@ -1,13 +1,14 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 json
|
||||
import os
|
||||
|
||||
from .url import URL
|
||||
|
||||
|
||||
class Indicators:
|
||||
"""This class is used to parse indicators from a STIX2 file and provide
|
||||
functions to compare extracted artifacts to the indicators.
|
||||
|
||||
+41
-19
@@ -1,18 +1,29 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import csv
|
||||
import glob
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
import simplejson as json
|
||||
|
||||
from .indicators import Indicators
|
||||
|
||||
|
||||
class DatabaseNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class DatabaseCorruptedError(Exception):
|
||||
pass
|
||||
|
||||
class InsufficientPrivileges(Exception):
|
||||
pass
|
||||
|
||||
class MVTModule(object):
|
||||
"""This class provides a base for all extraction modules."""
|
||||
|
||||
@@ -69,7 +80,7 @@ class MVTModule(object):
|
||||
self.indicators = Indicators(file_path, self.log)
|
||||
|
||||
def check_indicators(self):
|
||||
"""Check the results of this module againt a provided list of
|
||||
"""Check the results of this module against a provided list of
|
||||
indicators."""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -85,7 +96,11 @@ class MVTModule(object):
|
||||
results_file_name = f"{name}.json"
|
||||
results_json_path = os.path.join(self.output_folder, results_file_name)
|
||||
with open(results_json_path, "w") as handle:
|
||||
json.dump(self.results, handle, indent=4)
|
||||
try:
|
||||
json.dump(self.results, handle, indent=4)
|
||||
except Exception as e:
|
||||
self.log.error("Unable to store results of module %s to file %s: %s",
|
||||
self.__class__.__name__, results_file_name, e)
|
||||
|
||||
if self.detected:
|
||||
detected_file_name = f"{name}_detected.json"
|
||||
@@ -101,19 +116,21 @@ class MVTModule(object):
|
||||
"""
|
||||
for result in self.results:
|
||||
record = self.serialize(result)
|
||||
if type(record) == list:
|
||||
self.timeline.extend(record)
|
||||
else:
|
||||
self.timeline.append(record)
|
||||
if record:
|
||||
if type(record) == list:
|
||||
self.timeline.extend(record)
|
||||
else:
|
||||
self.timeline.append(record)
|
||||
|
||||
for detected in self.detected:
|
||||
record = self.serialize(detected)
|
||||
if type(record) == list:
|
||||
self.timeline_detected.extend(record)
|
||||
else:
|
||||
self.timeline_detected.append(record)
|
||||
if record:
|
||||
if type(record) == list:
|
||||
self.timeline_detected.extend(record)
|
||||
else:
|
||||
self.timeline_detected.append(record)
|
||||
|
||||
# De-duplicate timeline entries
|
||||
# De-duplicate timeline entries.
|
||||
self.timeline = self.timeline_deduplicate(self.timeline)
|
||||
self.timeline_detected = self.timeline_deduplicate(self.timeline_detected)
|
||||
|
||||
@@ -138,8 +155,13 @@ def run_module(module):
|
||||
except NotImplementedError:
|
||||
module.log.exception("The run() procedure of module %s was not implemented yet!",
|
||||
module.__class__.__name__)
|
||||
except FileNotFoundError as e:
|
||||
module.log.error("There might be no data to extract by module %s: %s",
|
||||
except InsufficientPrivileges as e:
|
||||
module.log.info("Insufficient privileges for module %s: %s", module.__class__.__name__, e)
|
||||
except DatabaseNotFoundError as e:
|
||||
module.log.info("There might be no data to extract by module %s: %s",
|
||||
module.__class__.__name__, e)
|
||||
except DatabaseCorruptedError as e:
|
||||
module.log.error("The %s module database seems to be corrupted and recovery failed: %s",
|
||||
module.__class__.__name__, e)
|
||||
except Exception as e:
|
||||
module.log.exception("Error in running extraction from module %s: %s",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
# From: https://gist.github.com/stanchan/bce1c2d030c76fe9223b5ff6ad0f03db
|
||||
|
||||
from click import command, option, Option, UsageError
|
||||
from click import Option, UsageError, command, option
|
||||
|
||||
|
||||
class MutuallyExclusiveOption(Option):
|
||||
"""This class extends click to support mutually exclusive options.
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import requests
|
||||
from tld import get_tld
|
||||
|
||||
+6
-5
@@ -1,12 +1,13 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 re
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
def convert_mactime_to_unix(timestamp, from_2001=True):
|
||||
"""Converts Mac Standard Time to a Unix timestamp.
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .cli import cli
|
||||
+79
-16
@@ -1,18 +1,20 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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
|
||||
import click
|
||||
import tarfile
|
||||
import logging
|
||||
from rich.logging import RichHandler
|
||||
|
||||
import click
|
||||
from rich.logging import RichHandler
|
||||
from rich.prompt import Prompt
|
||||
|
||||
from mvt.common.indicators import Indicators
|
||||
from mvt.common.module import run_module, save_timeline
|
||||
from mvt.common.options import MutuallyExclusiveOption
|
||||
from mvt.common.indicators import Indicators
|
||||
|
||||
from .decrypt import DecryptBackup
|
||||
from .modules.fs import BACKUP_MODULES, FS_MODULES
|
||||
@@ -26,6 +28,8 @@ log = logging.getLogger(__name__)
|
||||
# Help messages of repeating options.
|
||||
OUTPUT_HELP_MESSAGE = "Specify a path to a folder where you want to store JSON results"
|
||||
|
||||
# Set this environment variable to a password if needed.
|
||||
PASSWD_ENV = "MVT_IOS_BACKUP_PASSWORD"
|
||||
|
||||
#==============================================================================
|
||||
# Main
|
||||
@@ -42,8 +46,7 @@ def cli():
|
||||
@click.option("--destination", "-d", required=True,
|
||||
help="Path to the folder where to store the decrypted backup")
|
||||
@click.option("--password", "-p", cls=MutuallyExclusiveOption,
|
||||
help="Password to use to decrypt the backup",
|
||||
prompt="Enter backup password", hide_input=True, prompt_required=False,
|
||||
help=f"Password to use to decrypt the backup (or, set {PASSWD_ENV} environment variable)",
|
||||
mutually_exclusive=["key_file"])
|
||||
@click.option("--key-file", "-k", cls=MutuallyExclusiveOption,
|
||||
type=click.Path(exists=True),
|
||||
@@ -52,13 +55,59 @@ def cli():
|
||||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||
def decrypt_backup(destination, password, key_file, backup_path):
|
||||
backup = DecryptBackup(backup_path, destination)
|
||||
if password:
|
||||
backup.decrypt_with_password(password)
|
||||
elif key_file:
|
||||
|
||||
if key_file:
|
||||
if PASSWD_ENV in os.environ:
|
||||
log.info(f"Ignoring {PASSWD_ENV} environment variable, using --key-file '{key_file}' instead")
|
||||
|
||||
backup.decrypt_with_key_file(key_file)
|
||||
elif password:
|
||||
log.info("Your password may be visible in the process table because it was supplied on the command line!")
|
||||
|
||||
if PASSWD_ENV in os.environ:
|
||||
log.info(f"Ignoring {PASSWD_ENV} environment variable, using --password argument instead")
|
||||
|
||||
backup.decrypt_with_password(password)
|
||||
elif PASSWD_ENV in os.environ:
|
||||
log.info(f"Using password from {PASSWD_ENV} environment variable")
|
||||
backup.decrypt_with_password(os.environ[PASSWD_ENV])
|
||||
else:
|
||||
raise click.ClickException("Missing required option. Specify either "
|
||||
"--password or --key-file.")
|
||||
sekrit = Prompt.ask("Enter backup password", password=True)
|
||||
backup.decrypt_with_password(sekrit)
|
||||
|
||||
backup.process_backup()
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Command: extract-key
|
||||
#==============================================================================
|
||||
@cli.command("extract-key", help="Extract decryption key from an iTunes backup")
|
||||
@click.option("--password", "-p",
|
||||
help=f"Password to use to decrypt the backup (or, set {PASSWD_ENV} environment variable)")
|
||||
@click.option("--key-file", "-k",
|
||||
help="Key file to be written (if unset, will print to STDOUT)",
|
||||
required=False,
|
||||
type=click.Path(exists=False, file_okay=True, dir_okay=False, writable=True))
|
||||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||
def extract_key(password, backup_path, key_file):
|
||||
backup = DecryptBackup(backup_path)
|
||||
|
||||
if password:
|
||||
log.info("Your password may be visible in the process table because it was supplied on the command line!")
|
||||
|
||||
if PASSWD_ENV in os.environ:
|
||||
log.info(f"Ignoring {PASSWD_ENV} environment variable, using --password argument instead")
|
||||
elif PASSWD_ENV in os.environ:
|
||||
log.info(f"Using password from {PASSWD_ENV} environment variable")
|
||||
password = os.environ[PASSWD_ENV]
|
||||
else:
|
||||
password = Prompt.ask("Enter backup password", password=True)
|
||||
|
||||
backup.decrypt_with_password(password)
|
||||
backup.get_key()
|
||||
|
||||
if key_file:
|
||||
backup.write_key(key_file)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -66,7 +115,7 @@ def decrypt_backup(destination, password, key_file, backup_path):
|
||||
#==============================================================================
|
||||
@cli.command("check-backup", help="Extract artifacts from an iTunes backup")
|
||||
@click.option("--iocs", "-i", type=click.Path(exists=True), help="Path to indicators file")
|
||||
@click.option("--output", "-o", type=click.Path(exists=True), help=OUTPUT_HELP_MESSAGE)
|
||||
@click.option("--output", "-o", type=click.Path(exists=False), help=OUTPUT_HELP_MESSAGE)
|
||||
@click.option("--fast", "-f", is_flag=True, help="Avoid running time/resource consuming features")
|
||||
@click.option("--list-modules", "-l", is_flag=True, help="Print list of available modules and exit")
|
||||
@click.option("--module", "-m", help="Name of a single module you would like to run instead of all")
|
||||
@@ -81,6 +130,13 @@ def check_backup(iocs, output, fast, backup_path, list_modules, module):
|
||||
|
||||
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)
|
||||
sys.exit(-1)
|
||||
|
||||
if iocs:
|
||||
# Pre-load indicators for performance reasons.
|
||||
log.info("Loading indicators from provided file at: %s", iocs)
|
||||
@@ -116,7 +172,7 @@ def check_backup(iocs, output, fast, backup_path, list_modules, module):
|
||||
#==============================================================================
|
||||
@cli.command("check-fs", help="Extract artifacts from a full filesystem dump")
|
||||
@click.option("--iocs", "-i", type=click.Path(exists=True), help="Path to indicators file")
|
||||
@click.option("--output", "-o", type=click.Path(exists=True), help=OUTPUT_HELP_MESSAGE)
|
||||
@click.option("--output", "-o", type=click.Path(exists=False), help=OUTPUT_HELP_MESSAGE)
|
||||
@click.option("--fast", "-f", is_flag=True, help="Avoid running time/resource consuming features")
|
||||
@click.option("--list-modules", "-l", is_flag=True, help="Print list of available modules and exit")
|
||||
@click.option("--module", "-m", help="Name of a single module you would like to run instead of all")
|
||||
@@ -131,6 +187,13 @@ def check_fs(iocs, output, fast, dump_path, list_modules, module):
|
||||
|
||||
log.info("Checking filesystem dump 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)
|
||||
sys.exit(-1)
|
||||
|
||||
if iocs:
|
||||
# Pre-load indicators for performance reasons.
|
||||
log.info("Loading indicators from provided file at: %s", iocs)
|
||||
|
||||
+45
-19
@@ -1,13 +1,14 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import binascii
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sqlite3
|
||||
import logging
|
||||
import binascii
|
||||
|
||||
from iOSbackup import iOSbackup
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -17,7 +18,7 @@ class DecryptBackup:
|
||||
using either a password or a key file.
|
||||
"""
|
||||
|
||||
def __init__(self, backup_path, dest_path):
|
||||
def __init__(self, backup_path, dest_path=None):
|
||||
"""Decrypts an encrypted iOS backup.
|
||||
:param backup_path: Path to the encrypted backup folder
|
||||
:param dest_path: Path to the folder where to store the decrypted backup
|
||||
@@ -25,8 +26,12 @@ class DecryptBackup:
|
||||
self.backup_path = backup_path
|
||||
self.dest_path = dest_path
|
||||
self._backup = None
|
||||
self._decryption_key = None
|
||||
|
||||
def process_backup(self):
|
||||
if not os.path.exists(self.dest_path):
|
||||
os.makedirs(self.dest_path)
|
||||
|
||||
def _process_backup(self):
|
||||
manifest_path = os.path.join(self.dest_path, "Manifest.db")
|
||||
# We extract a decrypted Manifest.db.
|
||||
self._backup.getManifestDB()
|
||||
@@ -68,19 +73,18 @@ class DecryptBackup:
|
||||
"""
|
||||
log.info("Decrypting iOS backup at path %s with password", self.backup_path)
|
||||
|
||||
if not os.path.exists(self.dest_path):
|
||||
os.makedirs(self.dest_path)
|
||||
|
||||
try:
|
||||
self._backup = iOSbackup(udid=os.path.basename(self.backup_path),
|
||||
cleartextpassword=password,
|
||||
backuproot=os.path.dirname(self.backup_path))
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
log.critical("Failed to decrypt backup. Did you provide the correct password?")
|
||||
return
|
||||
else:
|
||||
self._process_backup()
|
||||
if isinstance(e, KeyError) and len(e.args) > 0 and e.args[0] == b"KEY":
|
||||
log.critical("Failed to decrypt backup. Password is probably wrong.")
|
||||
elif isinstance(e, FileNotFoundError) and os.path.basename(e.filename) == "Manifest.plist":
|
||||
log.critical(f"Failed to find a valid backup at {self.backup_path}. Did you point to the right backup path?")
|
||||
else:
|
||||
log.exception(e)
|
||||
log.critical("Failed to decrypt backup. Did you provide the correct password? Did you point to the right backup path?")
|
||||
|
||||
def decrypt_with_key_file(self, key_file):
|
||||
"""Decrypts an encrypted iOS backup using a key file.
|
||||
@@ -89,9 +93,6 @@ class DecryptBackup:
|
||||
log.info("Decrypting iOS backup at path %s with key file %s",
|
||||
self.backup_path, key_file)
|
||||
|
||||
if not os.path.exists(self.dest_path):
|
||||
os.makedirs(self.dest_path)
|
||||
|
||||
with open(key_file, "rb") as handle:
|
||||
key_bytes = handle.read()
|
||||
|
||||
@@ -108,6 +109,31 @@ class DecryptBackup:
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
log.critical("Failed to decrypt backup. Did you provide the correct key file?")
|
||||
|
||||
def get_key(self):
|
||||
"""Retrieve and prints the encryption key.
|
||||
"""
|
||||
if not self._backup:
|
||||
return
|
||||
|
||||
self._decryption_key = self._backup.getDecryptionKey()
|
||||
log.info("Derived decryption key for backup at path %s is: \"%s\"",
|
||||
self.backup_path, self._decryption_key)
|
||||
|
||||
def write_key(self, key_path):
|
||||
"""Save extracted key to file.
|
||||
:param key_path: Path to the file where to write the derived decryption key.
|
||||
"""
|
||||
if not self._decryption_key:
|
||||
return
|
||||
|
||||
try:
|
||||
with open(key_path, 'w') as handle:
|
||||
handle.write(self._decryption_key)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
log.critical("Failed to write key to file: %s", key_path)
|
||||
return
|
||||
else:
|
||||
self._process_backup()
|
||||
log.info("Wrote decryption key to file: %s. This file is equivalent to a plaintext password. Keep it safe!",
|
||||
key_path)
|
||||
@@ -1,4 +1,4 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
@@ -1,42 +1,44 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .manifest import Manifest
|
||||
from .contacts import Contacts
|
||||
from .net_netusage import Netusage
|
||||
from .net_datausage import Datausage
|
||||
from .safari_history import SafariHistory
|
||||
from .safari_favicon import SafariFavicon
|
||||
from .safari_browserstate import SafariBrowserState
|
||||
from .webkit_indexeddb import WebkitIndexedDB
|
||||
from .webkit_localstorage import WebkitLocalStorage
|
||||
from .webkit_safariviewservice import WebkitSafariViewService
|
||||
from .webkit_session_resource_log import WebkitSessionResourceLog
|
||||
from .chrome_history import ChromeHistory
|
||||
from .cache_files import CacheFiles
|
||||
from .calls import Calls
|
||||
from .chrome_favicon import ChromeFavicon
|
||||
from .firefox_history import FirefoxHistory
|
||||
from .chrome_history import ChromeHistory
|
||||
from .contacts import Contacts
|
||||
from .filesystem import Filesystem
|
||||
from .firefox_favicon import FirefoxFavicon
|
||||
from .version_history import IOSVersionHistory
|
||||
from .firefox_history import FirefoxHistory
|
||||
from .idstatuscache import IDStatusCache
|
||||
from .locationd import LocationdClients
|
||||
from .interactionc import InteractionC
|
||||
from .locationd import LocationdClients
|
||||
from .manifest import Manifest
|
||||
from .net_datausage import Datausage
|
||||
from .net_netusage import Netusage
|
||||
from .safari_browserstate import SafariBrowserState
|
||||
from .safari_favicon import SafariFavicon
|
||||
from .safari_history import SafariHistory
|
||||
from .sms import SMS
|
||||
from .sms_attachments import SMSAttachments
|
||||
from .calls import Calls
|
||||
from .version_history import IOSVersionHistory
|
||||
from .webkit_indexeddb import WebkitIndexedDB
|
||||
from .webkit_localstorage import WebkitLocalStorage
|
||||
from .webkit_resource_load_statistics import WebkitResourceLoadStatistics
|
||||
from .webkit_safariviewservice import WebkitSafariViewService
|
||||
from .webkit_session_resource_log import WebkitSessionResourceLog
|
||||
from .whatsapp import Whatsapp
|
||||
from .cache_files import CacheFiles
|
||||
from .filesystem import Filesystem
|
||||
|
||||
BACKUP_MODULES = [SafariBrowserState, SafariHistory, Datausage, SMS, SMSAttachments,
|
||||
ChromeHistory, ChromeFavicon, WebkitSessionResourceLog,
|
||||
Calls, IDStatusCache, LocationdClients, InteractionC,
|
||||
FirefoxHistory, FirefoxFavicon, Contacts, Manifest, Whatsapp]
|
||||
WebkitResourceLoadStatistics, Calls, IDStatusCache, LocationdClients,
|
||||
InteractionC, FirefoxHistory, FirefoxFavicon, Contacts, Manifest, Whatsapp]
|
||||
|
||||
FS_MODULES = [IOSVersionHistory, SafariHistory, SafariFavicon, SafariBrowserState,
|
||||
WebkitIndexedDB, WebkitLocalStorage, WebkitSafariViewService,
|
||||
WebkitSessionResourceLog, Datausage, Netusage, ChromeHistory,
|
||||
WebkitResourceLoadStatistics, WebkitSessionResourceLog,
|
||||
Datausage, Netusage, ChromeHistory,
|
||||
ChromeFavicon, Calls, IDStatusCache, SMS, SMSAttachments,
|
||||
LocationdClients, InteractionC, FirefoxHistory, FirefoxFavicon,
|
||||
Contacts, CacheFiles, Whatsapp, Filesystem]
|
||||
@@ -1,12 +1,18 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 glob
|
||||
import io
|
||||
import os
|
||||
import shutil
|
||||
import sqlite3
|
||||
import subprocess
|
||||
|
||||
from mvt.common.module import (DatabaseCorruptedError, DatabaseNotFoundError,
|
||||
MVTModule)
|
||||
|
||||
from mvt.common.module import MVTModule
|
||||
|
||||
class IOSExtraction(MVTModule):
|
||||
"""This class provides a base for all iOS filesystem/backup extraction modules."""
|
||||
@@ -15,10 +21,53 @@ class IOSExtraction(MVTModule):
|
||||
is_fs_dump = False
|
||||
is_sysdiagnose = False
|
||||
|
||||
def _is_database_malformed(self, file_path):
|
||||
# Check if the database is malformed.
|
||||
conn = sqlite3.connect(file_path)
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
recover = False
|
||||
cur.execute("SELECT name FROM sqlite_master WHERE type='table';")
|
||||
except sqlite3.DatabaseError as e:
|
||||
if "database disk image is malformed" in str(e):
|
||||
recover = True
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
return recover
|
||||
|
||||
def _recover_database(self, file_path):
|
||||
"""Tries to recover a malformed database by running a .clone command.
|
||||
:param file_path: Path to the malformed database file.
|
||||
"""
|
||||
# TODO: Find a better solution.
|
||||
|
||||
self.log.info("Database at path %s is malformed. Trying to recover...", file_path)
|
||||
|
||||
if not os.path.exists(file_path):
|
||||
return
|
||||
|
||||
if not shutil.which("sqlite3"):
|
||||
raise DatabaseCorruptedError("Unable to recover without sqlite3 binary. Please install sqlite3!")
|
||||
if '"' in file_path:
|
||||
raise DatabaseCorruptedError(f"Database at path '{file_path}' is corrupted. unable to recover because it has a quotation mark (\") in its name.")
|
||||
|
||||
bak_path = f"{file_path}.bak"
|
||||
shutil.move(file_path, bak_path)
|
||||
|
||||
ret = subprocess.call(["sqlite3", bak_path, f".clone \"{file_path}\""],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if ret != 0:
|
||||
raise DatabaseCorruptedError("Recovery of database failed")
|
||||
|
||||
self.log.info("Database at path %s recovered successfully!", file_path)
|
||||
|
||||
def _find_ios_database(self, backup_ids=None, root_paths=[]):
|
||||
"""Try to locate the module's database file from either an iTunes
|
||||
backup or a full filesystem dump.
|
||||
:param backup_id: iTunes backup database file's ID (or hash).
|
||||
:param root_paths: Glob patterns for files to seek in filesystem dump.
|
||||
"""
|
||||
file_path = None
|
||||
# First we check if the was an explicit file path specified.
|
||||
@@ -52,4 +101,7 @@ class IOSExtraction(MVTModule):
|
||||
if file_path:
|
||||
self.file_path = file_path
|
||||
else:
|
||||
raise FileNotFoundError("Unable to find the module's database file")
|
||||
raise DatabaseNotFoundError("Unable to find the module's database file")
|
||||
|
||||
if self._is_database_malformed(self.file_path):
|
||||
self._recover_database(self.file_path)
|
||||
@@ -1,13 +1,14 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 sqlite3
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
class CacheFiles(IOSExtraction):
|
||||
|
||||
def __init__(self, file_path=None, base_folder=None, output_folder=None,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
CALLS_BACKUP_IDS = [
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
from mvt.common.utils import convert_chrometime_to_unix, convert_timestamp_to_iso
|
||||
from mvt.common.utils import (convert_chrometime_to_unix,
|
||||
convert_timestamp_to_iso)
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
from mvt.common.utils import convert_chrometime_to_unix, convert_timestamp_to_iso
|
||||
from mvt.common.utils import (convert_chrometime_to_unix,
|
||||
convert_timestamp_to_iso)
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
@@ -35,6 +36,14 @@ class ChromeHistory(IOSExtraction):
|
||||
"data": f"{record['id']} - {record['url']} (visit ID: {record['visit_id']}, redirect source: {record['redirect_source']})"
|
||||
}
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
if self.indicators.check_domain(result["url"]):
|
||||
self.detected.append(result)
|
||||
|
||||
def run(self):
|
||||
self._find_ios_database(backup_ids=CHROME_HISTORY_BACKUP_IDS, root_paths=CHROME_HISTORY_ROOT_PATHS)
|
||||
self.log.info("Found Chrome history database at path: %s", self.file_path)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 datetime
|
||||
import os
|
||||
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
class Filesystem(IOSExtraction):
|
||||
"""This module extracts creation and modification date of files from a
|
||||
full file-system dump."""
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from mvt.common.url import URL
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from mvt.common.url import URL
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 glob
|
||||
import biplist
|
||||
import collections
|
||||
import glob
|
||||
import os
|
||||
|
||||
import biplist
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
from base64 import b64encode
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 glob
|
||||
import os
|
||||
|
||||
import biplist
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
@@ -43,10 +44,10 @@ class LocationdClients(IOSExtraction):
|
||||
for ts in self.timestamps:
|
||||
if ts in record.keys():
|
||||
records.append({
|
||||
"timestamp": entry[ts],
|
||||
"timestamp": record[ts],
|
||||
"module": self.__class__.__name__,
|
||||
"event": ts,
|
||||
"data": f"{ts} from {entry['package']}"
|
||||
"data": f"{ts} from {record['package']}"
|
||||
})
|
||||
|
||||
return records
|
||||
@@ -62,7 +63,7 @@ class LocationdClients(IOSExtraction):
|
||||
result["package"] = app
|
||||
for ts in self.timestamps:
|
||||
if ts in result.keys():
|
||||
result[ts] = convert_timestamp_to_iso(convert_mactime_to_unix(result[date]))
|
||||
result[ts] = convert_timestamp_to_iso(convert_mactime_to_unix(result[ts]))
|
||||
|
||||
self.results.append(result)
|
||||
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import datetime
|
||||
import io
|
||||
import os
|
||||
import biplist
|
||||
import sqlite3
|
||||
import datetime
|
||||
|
||||
import biplist
|
||||
|
||||
from mvt.common.module import DatabaseNotFoundError
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
class Manifest(IOSExtraction):
|
||||
"""This module extracts information from a backup Manifest.db file."""
|
||||
|
||||
@@ -40,6 +43,8 @@ class Manifest(IOSExtraction):
|
||||
|
||||
def serialize(self, record):
|
||||
records = []
|
||||
if "modified" not in record or "statusChanged" not in record:
|
||||
return
|
||||
for ts in set([record["created"], record["modified"], record["statusChanged"]]):
|
||||
macb = ""
|
||||
macb += "M" if ts == record["modified"] else "-"
|
||||
@@ -63,12 +68,15 @@ class Manifest(IOSExtraction):
|
||||
for result in self.results:
|
||||
if not "relativePath" in result:
|
||||
continue
|
||||
|
||||
if os.path.basename(result["relativePath"]) == "com.apple.CrashReporter.plist" and result["domain"] == "RootDomain":
|
||||
self.log.warning("Found a potentially suspicious \"com.apple.CrashReporter.plist\" file created in RootDomain")
|
||||
self.detected.append(result)
|
||||
if not result["relativePath"]:
|
||||
continue
|
||||
|
||||
if result["domain"]:
|
||||
if os.path.basename(result["relativePath"]) == "com.apple.CrashReporter.plist" and result["domain"] == "RootDomain":
|
||||
self.log.warning("Found a potentially suspicious \"com.apple.CrashReporter.plist\" file created in RootDomain")
|
||||
self.detected.append(result)
|
||||
continue
|
||||
|
||||
if self.indicators.check_file(result["relativePath"]):
|
||||
self.log.warning("Found a known malicious file at path: %s", result["relativePath"])
|
||||
self.detected.append(result)
|
||||
@@ -84,7 +92,7 @@ class Manifest(IOSExtraction):
|
||||
def run(self):
|
||||
manifest_db_path = os.path.join(self.base_folder, "Manifest.db")
|
||||
if not os.path.isfile(manifest_db_path):
|
||||
raise FileNotFoundError("Impossible to find the module's database file")
|
||||
raise DatabaseNotFoundError("Impossible to find the module's database file")
|
||||
|
||||
self.log.info("Found Manifest.db database at path: %s", manifest_db_path)
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
import operator
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
class NetBase(IOSExtraction):
|
||||
"""This class provides a base for DataUsage and NetUsage extraction modules."""
|
||||
|
||||
@@ -167,6 +168,10 @@ class NetBase(IOSExtraction):
|
||||
results_by_proc = {proc["proc_id"]: proc for proc in self.results if proc["proc_id"]}
|
||||
all_proc_id = sorted(results_by_proc.keys())
|
||||
|
||||
# Fix issue #108
|
||||
if not all_proc_id:
|
||||
return
|
||||
|
||||
missing_procs, last_proc_id = {}, None
|
||||
for proc_id in range(min(all_proc_id), max(all_proc_id)):
|
||||
if proc_id not in all_proc_id:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .net_base import NetBase
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .net_base import NetBase
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import io
|
||||
import biplist
|
||||
import sqlite3
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
from mvt.common.utils import keys_bytes_to_string
|
||||
import biplist
|
||||
|
||||
from mvt.common.utils import (convert_mactime_to_unix,
|
||||
convert_timestamp_to_iso, keys_bytes_to_string)
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
from base64 import b64encode
|
||||
|
||||
from mvt.common.utils import check_for_links
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
from mvt.common.utils import (check_for_links, convert_mactime_to_unix,
|
||||
convert_timestamp_to_iso)
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
from base64 import b64encode
|
||||
|
||||
from mvt.common.utils import check_for_links
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
from mvt.common.utils import (check_for_links, convert_mactime_to_unix,
|
||||
convert_timestamp_to_iso)
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import json
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 datetime
|
||||
import os
|
||||
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
|
||||
class WebkitBase(IOSExtraction):
|
||||
"""This class is a base for other WebKit-related modules."""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .webkit_base import WebkitBase
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .webkit_base import WebkitBase
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH = "Library/WebKit/WebsiteData/ResourceLoadStatistics/observations.db"
|
||||
WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS = [
|
||||
"private/var/mobile/Containers/Data/Application/*/Library/WebKit/WebsiteData/ResourceLoadStatistics/observations.db",
|
||||
"private/var/mobile/Containers/Data/Application/*/SystemData/com.apple.SafariViewService/Library/WebKit/WebsiteData/observations.db",
|
||||
]
|
||||
|
||||
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,
|
||||
fast_mode=False, log=None, results=[]):
|
||||
super().__init__(file_path=file_path, base_folder=base_folder,
|
||||
output_folder=output_folder, fast_mode=fast_mode,
|
||||
log=log, results=results)
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
self.detected = {}
|
||||
for key, items in self.results.items():
|
||||
for item in items:
|
||||
if self.indicators.check_domain(item["registrable_domain"]):
|
||||
if key not in self.detected:
|
||||
self.detected[key] = [item,]
|
||||
else:
|
||||
self.detected[key].append(item)
|
||||
|
||||
def _process_observations_db(self, db_path, key):
|
||||
self.log.info("Found WebKit ResourceLoadStatistics observations.db file at path %s", db_path)
|
||||
|
||||
if self._is_database_malformed(db_path):
|
||||
self._recover_database(db_path)
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
cur.execute("SELECT * from ObservedDomains;")
|
||||
except sqlite3.OperationalError:
|
||||
return
|
||||
|
||||
if not key in self.results:
|
||||
self.results[key] = []
|
||||
|
||||
for row in cur:
|
||||
self.results[key].append(dict(
|
||||
domain_id=row[0],
|
||||
registrable_domain=row[1],
|
||||
last_seen=row[2],
|
||||
had_user_interaction=bool(row[3]),
|
||||
# TODO: Fix isodate.
|
||||
last_seen_isodate=convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(int(row[2]))),
|
||||
))
|
||||
|
||||
if len(self.results[key]) > 0:
|
||||
self.log.info("Extracted a total of %d records from %s", len(self.results[key]), db_path)
|
||||
|
||||
def run(self):
|
||||
self.results = {}
|
||||
|
||||
if self.is_backup:
|
||||
manifest_db_path = os.path.join(self.base_folder, "Manifest.db")
|
||||
if not os.path.exists(manifest_db_path):
|
||||
self.log.info("Unable to search for WebKit observations.db files in backup because of missing Manifest.db")
|
||||
return
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(manifest_db_path)
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT fileID, domain FROM Files WHERE relativePath = ?;", (WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH,))
|
||||
except Exception as e:
|
||||
self.log.error("Unable to search for WebKit observations.db files in backup because of failed query to Manifest.db: %s", e)
|
||||
|
||||
for row in cur:
|
||||
file_id = row[0]
|
||||
domain = row[1]
|
||||
db_path = os.path.join(self.base_folder, file_id[0:2], file_id)
|
||||
if os.path.exists(db_path):
|
||||
self._process_observations_db(db_path=db_path, key=f"{domain}/{WEBKIT_RESOURCELOADSTATICS_BACKUP_RELPATH}")
|
||||
elif self.is_fs_dump:
|
||||
for db_path in self._find_paths(WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS):
|
||||
self._process_observations_db(db_path=db_path, key=os.path.relpath(db_path, self.base_folder))
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .webkit_base import WebkitBase
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# 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 glob
|
||||
import os
|
||||
|
||||
import biplist
|
||||
|
||||
from mvt.common.utils import convert_timestamp_to_iso
|
||||
@@ -70,6 +71,9 @@ class WebkitSessionResourceLog(IOSExtraction):
|
||||
return domains
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for key, entries in self.results.items():
|
||||
for entry in entries:
|
||||
source_domains = self._extract_domains(entry["redirect_source"])
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
import sqlite3
|
||||
import logging
|
||||
import sqlite3
|
||||
|
||||
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso, check_for_links
|
||||
from mvt.common.utils import (check_for_links, convert_mactime_to_unix,
|
||||
convert_timestamp_to_iso)
|
||||
|
||||
from .base import IOSExtraction
|
||||
|
||||
@@ -73,7 +74,7 @@ class Whatsapp(IOSExtraction):
|
||||
# Extract links from the WhatsApp message.
|
||||
message_links = check_for_links(new_message["ZTEXT"])
|
||||
|
||||
# If we find mesages, or if there's an empty message we add it to the list.
|
||||
# If we find messages, or if there's an empty message we add it to the list.
|
||||
if new_message["ZTEXT"] and (message_links or new_message["ZTEXT"].strip() == ""):
|
||||
self.results.append(new_message)
|
||||
|
||||
|
||||
+213
-169
@@ -1,190 +1,234 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021 MVT Project Developers.
|
||||
# See the file 'LICENSE' for usage and copying permissions, or find a copy at
|
||||
# https://github.com/mvt-project/mvt/blob/main/LICENSE
|
||||
# Copyright (c) 2021 The MVT Project Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
|
||||
IPHONE_MODELS = [
|
||||
{"description": "iPhone 4S", "identifier": "iPhone4,1"},
|
||||
{"description": "iPhone 5", "identifier": "iPhone5,1"},
|
||||
{"description": "iPhone 5", "identifier": "iPhone5,2"},
|
||||
{"description": "iPhone 5c", "identifier": "iPhone5,3"},
|
||||
{"description": "iPhone 5c", "identifier": "iPhone5,4"},
|
||||
{"description": "iPhone 5s", "identifier": "iPhone6,1"},
|
||||
{"description": "iPhone 5s", "identifier": "iPhone6,2"},
|
||||
{"description": "iPhone 6 Plus", "identifier": "iPhone7,1"},
|
||||
{"description": "iPhone 6", "identifier": "iPhone7,2"},
|
||||
{"description": "iPhone 6s", "identifier": "iPhone8,1"},
|
||||
{"description": "iPhone 6s Plus", "identifier": "iPhone8,2"},
|
||||
{"description": "iPhone SE (1st generation)", "identifier": "iPhone8,4"},
|
||||
{"description": "iPhone 7", "identifier": "iPhone9,1"},
|
||||
{"description": "iPhone 7 Plus", "identifier": "iPhone9,2"},
|
||||
{"description": "iPhone 7", "identifier": "iPhone9,3"},
|
||||
{"description": "iPhone 7 Plus", "identifier": "iPhone9,4"},
|
||||
{"description": "iPhone 8", "identifier": "iPhone10,1"},
|
||||
{"description": "iPhone 8 Plus", "identifier": "iPhone10,2"},
|
||||
{"description": "iPhone X", "identifier": "iPhone10,3"},
|
||||
{"description": "iPhone 8", "identifier": "iPhone10,4"},
|
||||
{"description": "iPhone 8 Plus", "identifier": "iPhone10,5"},
|
||||
{"description": "iPhone X", "identifier": "iPhone10,6"},
|
||||
{"description": "iPhone XS", "identifier": "iPhone11,2"},
|
||||
{"description": "iPhone XS Max", "identifier": "iPhone11,4"},
|
||||
{"description": "iPhone XS Max", "identifier": "iPhone11,6"},
|
||||
{"description": "iPhone XR", "identifier": "iPhone11,8"},
|
||||
{"description": "iPhone 11", "identifier": "iPhone12,1"},
|
||||
{"description": "iPhone 11 Pro", "identifier": "iPhone12,3"},
|
||||
{"description": "iPhone 11 Pro Max", "identifier": "iPhone12,5"},
|
||||
{"description": "iPhone SE (2nd generation)", "identifier": "iPhone12,8"},
|
||||
{"description": "iPhone 12 mini", "identifier": "iPhone13,1"},
|
||||
{"description": "iPhone 12", "identifier": "iPhone13,2"},
|
||||
{"description": "iPhone 12 Pro", "identifier": "iPhone13,3"},
|
||||
{"description": "iPhone 12 Pro Max", "identifier": "iPhone13,4"},
|
||||
]
|
||||
|
||||
IPHONE_IOS_VERSIONS = [
|
||||
{"build": "7E18", "version": "3.1.3"},
|
||||
{"build": "7D11", "version": "3.1.2"},
|
||||
{"build": "7C144", "version": "3.1"},
|
||||
{"build": "7A400", "version": "3.0.1"},
|
||||
{"build": "7A341", "version": "3.0"},
|
||||
{"build": "5H11", "version": "2.2.1"},
|
||||
{"build": "5G77", "version": "2.2"},
|
||||
{"build": "5F136", "version": "2.1"},
|
||||
{"build": "5C1", "version": "2.0.2"},
|
||||
{"build": "5B108", "version": "2.0.1"},
|
||||
{"build": "5A347", "version": "2.0"},
|
||||
{"build": "4A102", "version": "1.1.4"},
|
||||
{"build": "4A93", "version": "1.1.3"},
|
||||
{"build": "3B48b", "version": "1.1.2"},
|
||||
{"build": "3A109a", "version": "1.1.1"},
|
||||
{"build": "1C28", "version": "1.0.2"},
|
||||
{"build": "1C25", "version": "1.0.1"},
|
||||
{"build": "1A543a", "version": "1.0"},
|
||||
{"build": "8C148", "version": "4.2"},
|
||||
{"build": "8B117", "version": "4.1"},
|
||||
{"build": "8A306", "version": "4.0.1"},
|
||||
{"build": "1C25", "version": "1.0.1"},
|
||||
{"build": "1C28", "version": "1.0.2"},
|
||||
{"build": "3A109a", "version": "1.1.1"},
|
||||
{"build": "3B48b", "version": "1.1.2"},
|
||||
{"build": "4A93", "version": "1.1.3"},
|
||||
{"build": "4A102", "version": "1.1.4"},
|
||||
{"build": "5A347", "version": "2.0"},
|
||||
{"build": "5B108", "version": "2.0.1"},
|
||||
{"build": "5C1", "version": "2.0.2"},
|
||||
{"build": "5F136", "version": "2.1"},
|
||||
{"build": "5G77", "version": "2.2"},
|
||||
{"build": "5H11", "version": "2.2.1"},
|
||||
{"build": "7A341", "version": "3.0"},
|
||||
{"build": "7A400", "version": "3.0.1"},
|
||||
{"build": "7C144", "version": "3.1"},
|
||||
{"build": "7D11", "version": "3.1.2"},
|
||||
{"build": "7E18", "version": "3.1.3"},
|
||||
{"build": "8A293", "version": "4.0"},
|
||||
{"build": "10B500", "version": "6.1.6"},
|
||||
{"build": "10B329", "version": "6.1.3"},
|
||||
{"build": "10B146", "version": "6.1.2"},
|
||||
{"build": "10B141", "version": "6.1"},
|
||||
{"build": "10A523", "version": "6.0.1"},
|
||||
{"build": "10A403", "version": "6.0"},
|
||||
{"build": "9B206", "version": "5.1.1"},
|
||||
{"build": "9B176", "version": "5.1"},
|
||||
{"build": "9A405", "version": "5.0.1"},
|
||||
{"build": "9A334", "version": "5.0"},
|
||||
{"build": "8L1", "version": "4.3.5"},
|
||||
{"build": "8K2", "version": "4.3.4"},
|
||||
{"build": "8J2", "version": "4.3.3"},
|
||||
{"build": "8F190", "version": "4.3"},
|
||||
{"build": "8A306", "version": "4.0.1"},
|
||||
{"build": "8B117", "version": "4.1"},
|
||||
{"build": "8C148", "version": "4.2"},
|
||||
{"build": "8C148a", "version": "4.2.1"},
|
||||
{"build": "11D257", "version": "7.1.2"},
|
||||
{"build": "11D201", "version": "7.1.1"},
|
||||
{"build": "11D169", "version": "7.1"},
|
||||
{"build": "11B651", "version": "7.0.6"},
|
||||
{"build": "11B554a", "version": "7.0.4"},
|
||||
{"build": "11B511", "version": "7.0.3"},
|
||||
{"build": "10B144", "version": "6.1"},
|
||||
{"build": "9B208", "version": "5.1.1"},
|
||||
{"build": "8C148", "version": "4.2.1"},
|
||||
{"build": "11D167", "version": "7.1"},
|
||||
{"build": "8E600", "version": "4.2.10"},
|
||||
{"build": "8E501", "version": "4.2.9"},
|
||||
{"build": "8E401", "version": "4.2.8"},
|
||||
{"build": "13G37", "version": "9.3.6"},
|
||||
{"build": "13G36", "version": "9.3.5"},
|
||||
{"build": "13G35", "version": "9.3.4"},
|
||||
{"build": "13G34", "version": "9.3.3"},
|
||||
{"build": "13F69", "version": "9.3.2"},
|
||||
{"build": "13E238", "version": "9.3.1"},
|
||||
{"build": "8E501", "version": "4.2.9"},
|
||||
{"build": "8F190", "version": "4.3"},
|
||||
{"build": "8J2", "version": "4.3.3"},
|
||||
{"build": "8K2", "version": "4.3.4"},
|
||||
{"build": "8L1", "version": "4.3.5"},
|
||||
{"build": "9A334", "version": "5.0"},
|
||||
{"build": "9A405", "version": "5.0.1"},
|
||||
{"build": "9A406", "version": "5.0.1"},
|
||||
{"build": "9B176", "version": "5.1"},
|
||||
{"build": "9B179", "version": "5.1"},
|
||||
{"build": "9B206", "version": "5.1.1"},
|
||||
{"build": "9B208", "version": "5.1.1"},
|
||||
{"build": "10A403", "version": "6.0"},
|
||||
{"build": "10A405", "version": "6.0"},
|
||||
{"build": "10A523", "version": "6.0.1"},
|
||||
{"build": "10A525", "version": "6.0.1"},
|
||||
{"build": "10A551", "version": "6.0.2"},
|
||||
{"build": "10B141", "version": "6.1"},
|
||||
{"build": "10B144", "version": "6.1"},
|
||||
{"build": "10B142", "version": "6.1"},
|
||||
{"build": "10B143", "version": "6.1"},
|
||||
{"build": "10B145", "version": "6.1.1"},
|
||||
{"build": "10B146", "version": "6.1.2"},
|
||||
{"build": "10B329", "version": "6.1.3"},
|
||||
{"build": "10B350", "version": "6.1.4"},
|
||||
{"build": "10B500", "version": "6.1.6"},
|
||||
{"build": "11B511", "version": "7.0.3"},
|
||||
{"build": "11B554a", "version": "7.0.4"},
|
||||
{"build": "11B601", "version": "7.0.5"},
|
||||
{"build": "11B651", "version": "7.0.6"},
|
||||
{"build": "11D169", "version": "7.1"},
|
||||
{"build": "11D167", "version": "7.1"},
|
||||
{"build": "11D201", "version": "7.1.1"},
|
||||
{"build": "11D257", "version": "7.1.2"},
|
||||
{"build": "12A365", "version": "8.0"},
|
||||
{"build": "12A366", "version": "8.0"},
|
||||
{"build": "12A402", "version": "8.0.1"},
|
||||
{"build": "12A405", "version": "8.0.2"},
|
||||
{"build": "12B411", "version": "8.1"},
|
||||
{"build": "12B435", "version": "8.1.1"},
|
||||
{"build": "12B436", "version": "8.1.1"},
|
||||
{"build": "12B440", "version": "8.1.2"},
|
||||
{"build": "12B466", "version": "8.1.3"},
|
||||
{"build": "12D508", "version": "8.2"},
|
||||
{"build": "12F70", "version": "8.3"},
|
||||
{"build": "12H143", "version": "8.4"},
|
||||
{"build": "12H321", "version": "8.4.1"},
|
||||
{"build": "13A344", "version": "9.0"},
|
||||
{"build": "13A342", "version": "9.0"},
|
||||
{"build": "13A343", "version": "9.0"},
|
||||
{"build": "13A404", "version": "9.0.1"},
|
||||
{"build": "13A405", "version": "9.0.1"},
|
||||
{"build": "13A452", "version": "9.0.2"},
|
||||
{"build": "13B143", "version": "9.1"},
|
||||
{"build": "13C75", "version": "9.2"},
|
||||
{"build": "13D15", "version": "9.2.1"},
|
||||
{"build": "13D20", "version": "9.2.1"},
|
||||
{"build": "13E237", "version": "9.3"},
|
||||
{"build": "13E233", "version": "9.3"},
|
||||
{"build": "13D15", "version": "9.2.1"},
|
||||
{"build": "13C75", "version": "9.2"},
|
||||
{"build": "13B143", "version": "9.1"},
|
||||
{"build": "13A452", "version": "9.0.2"},
|
||||
{"build": "13A404", "version": "9.0.1"},
|
||||
{"build": "13A344", "version": "9.0"},
|
||||
{"build": "12H321", "version": "8.4.1"},
|
||||
{"build": "12H143", "version": "8.4"},
|
||||
{"build": "12F70", "version": "8.3"},
|
||||
{"build": "12D508", "version": "8.2"},
|
||||
{"build": "12B466", "version": "8.1.3"},
|
||||
{"build": "12B440", "version": "8.1.2"},
|
||||
{"build": "12B435", "version": "8.1.1"},
|
||||
{"build": "12B411", "version": "8.1"},
|
||||
{"build": "12A405", "version": "8.0.2"},
|
||||
{"build": "12A402", "version": "8.0.1"},
|
||||
{"build": "12A365", "version": "8.0"},
|
||||
{"build": "10B145", "version": "6.1.1"},
|
||||
{"build": "10B142", "version": "6.1"},
|
||||
{"build": "9B179", "version": "5.1"},
|
||||
{"build": "9A406", "version": "5.0.1"},
|
||||
{"build": "14G61", "version": "10.3.4"},
|
||||
{"build": "14G60", "version": "10.3.3"},
|
||||
{"build": "14F89", "version": "10.3.2"},
|
||||
{"build": "14E304", "version": "10.3.1"},
|
||||
{"build": "14E277", "version": "10.3"},
|
||||
{"build": "14D27", "version": "10.2.1"},
|
||||
{"build": "14C92", "version": "10.2"},
|
||||
{"build": "13E234", "version": "9.3"},
|
||||
{"build": "13E238", "version": "9.3.1"},
|
||||
{"build": "13F69", "version": "9.3.2"},
|
||||
{"build": "13G34", "version": "9.3.3"},
|
||||
{"build": "13G35", "version": "9.3.4"},
|
||||
{"build": "13G36", "version": "9.3.5"},
|
||||
{"build": "13G37", "version": "9.3.6"},
|
||||
{"build": "14A403", "version": "10.0.1"},
|
||||
{"build": "14A456", "version": "10.0.2"},
|
||||
{"build": "14A551", "version": "10.0.3"},
|
||||
{"build": "14B72", "version": "10.1"},
|
||||
{"build": "14B72c", "version": "10.1"},
|
||||
{"build": "14B150", "version": "10.1.1"},
|
||||
{"build": "14B100", "version": "10.1.1"},
|
||||
{"build": "14B72", "version": "10.1"},
|
||||
{"build": "14A456", "version": "10.0.2"},
|
||||
{"build": "14A403", "version": "10.0.1"},
|
||||
{"build": "10B350", "version": "6.1.4"},
|
||||
{"build": "10B143", "version": "6.1"},
|
||||
{"build": "10A551", "version": "6.0.2"},
|
||||
{"build": "10A525", "version": "6.0.1"},
|
||||
{"build": "10A405", "version": "6.0"},
|
||||
{"build": "11B601", "version": "7.0.5"},
|
||||
{"build": "18F72", "version": "14.6"},
|
||||
{"build": "18E199", "version": "14.5"},
|
||||
{"build": "18E212", "version": "14.5.1"},
|
||||
{"build": "14C92", "version": "10.2"},
|
||||
{"build": "14D27", "version": "10.2.1"},
|
||||
{"build": "14E277", "version": "10.3"},
|
||||
{"build": "14E304", "version": "10.3.1"},
|
||||
{"build": "14F89", "version": "10.3.2"},
|
||||
{"build": "14G60", "version": "10.3.3"},
|
||||
{"build": "14G61", "version": "10.3.4"},
|
||||
{"build": "15A372", "version": "11.0"},
|
||||
{"build": "15A402", "version": "11.0.1"},
|
||||
{"build": "15A421", "version": "11.0.2"},
|
||||
{"build": "15A432", "version": "11.0.3"},
|
||||
{"build": "15B93", "version": "11.1"},
|
||||
{"build": "15B150", "version": "11.1.1"},
|
||||
{"build": "15B202", "version": "11.1.2"},
|
||||
{"build": "15C114", "version": "11.2"},
|
||||
{"build": "15C153", "version": "11.2.1"},
|
||||
{"build": "15C202", "version": "11.2.2"},
|
||||
{"build": "15D60", "version": "11.2.5"},
|
||||
{"build": "15D100", "version": "11.2.6"},
|
||||
{"build": "15E216", "version": "11.3"},
|
||||
{"build": "15E302", "version": "11.3.1"},
|
||||
{"build": "15F79", "version": "11.4"},
|
||||
{"build": "15G77", "version": "11.4.1"},
|
||||
{"build": "16A366", "version": "12.0"},
|
||||
{"build": "16A404", "version": "12.0.1"},
|
||||
{"build": "16A405", "version": "12.0.1"},
|
||||
{"build": "16B92", "version": "12.1"},
|
||||
{"build": "16B94", "version": "12.1"},
|
||||
{"build": "16B93", "version": "12.1"},
|
||||
{"build": "16C50", "version": "12.1.1"},
|
||||
{"build": "16C104", "version": "12.1.2"},
|
||||
{"build": "16C101", "version": "12.1.2"},
|
||||
{"build": "16D39", "version": "12.1.3"},
|
||||
{"build": "16D40", "version": "12.1.3"},
|
||||
{"build": "16D57", "version": "12.1.4"},
|
||||
{"build": "16E227", "version": "12.2"},
|
||||
{"build": "16F156", "version": "12.3"},
|
||||
{"build": "16F203", "version": "12.3.1"},
|
||||
{"build": "16F250", "version": "12.3.2"},
|
||||
{"build": "16G77", "version": "12.4"},
|
||||
{"build": "16G102", "version": "12.4.1"},
|
||||
{"build": "16G114", "version": "12.4.2"},
|
||||
{"build": "16G130", "version": "12.4.3"},
|
||||
{"build": "16G161", "version": "12.4.5"},
|
||||
{"build": "16G183", "version": "12.4.6"},
|
||||
{"build": "16G192", "version": "12.4.7"},
|
||||
{"build": "16G201", "version": "12.4.8"},
|
||||
{"build": "16H5", "version": "12.4.9"},
|
||||
{"build": "16H20", "version": "12.5"},
|
||||
{"build": "16H22", "version": "12.5.1"},
|
||||
{"build": "17A577", "version": "13.0"},
|
||||
{"build": "17A844", "version": "13.1"},
|
||||
{"build": "17A854", "version": "13.1.1"},
|
||||
{"build": "17A860", "version": "13.1.2"},
|
||||
{"build": "17A861", "version": "13.1.2"},
|
||||
{"build": "17A878", "version": "13.1.3"},
|
||||
{"build": "17B84", "version": "13.2"},
|
||||
{"build": "17B102", "version": "13.2.2"},
|
||||
{"build": "17B111", "version": "13.2.3"},
|
||||
{"build": "17C54", "version": "13.3"},
|
||||
{"build": "17D50", "version": "13.3.1"},
|
||||
{"build": "17E255", "version": "13.4"},
|
||||
{"build": "17E262", "version": "13.4.1"},
|
||||
{"build": "17E8258", "version": "13.4.1"},
|
||||
{"build": "17F75", "version": "13.5"},
|
||||
{"build": "17F80", "version": "13.5.1"},
|
||||
{"build": "17G68", "version": "13.6"},
|
||||
{"build": "17G80", "version": "13.6.1"},
|
||||
{"build": "17H35", "version": "13.7"},
|
||||
{"build": "18A373", "version": "14.0"},
|
||||
{"build": "18A393", "version": "14.0.1"},
|
||||
{"build": "18A8395", "version": "14.1"},
|
||||
{"build": "18B92", "version": "14.2"},
|
||||
{"build": "18C66", "version": "14.3"},
|
||||
{"build": "18D52", "version": "14.4"},
|
||||
{"build": "18D61", "version": "14.4.1"},
|
||||
{"build": "18D70", "version": "14.4.2"},
|
||||
{"build": "18C66", "version": "14.3"},
|
||||
{"build": "18B92", "version": "14.2"},
|
||||
{"build": "18A8395", "version": "14.1"},
|
||||
{"build": "18A393", "version": "14.0.1"},
|
||||
{"build": "18A373", "version": "14.0"},
|
||||
{"build": "17H35", "version": "13.7"},
|
||||
{"build": "17G80", "version": "13.6.1"},
|
||||
{"build": "17G68", "version": "13.6"},
|
||||
{"build": "17F80", "version": "13.5.1"},
|
||||
{"build": "17F75", "version": "13.5"},
|
||||
{"build": "17E262", "version": "13.4.1"},
|
||||
{"build": "17E255", "version": "13.4"},
|
||||
{"build": "17C54", "version": "13.3"},
|
||||
{"build": "17D50", "version": "13.3.1"},
|
||||
{"build": "17B111", "version": "13.2.3"},
|
||||
{"build": "17B102", "version": "13.2.2"},
|
||||
{"build": "17B84", "version": "13.2"},
|
||||
{"build": "17A878", "version": "13.1.3"},
|
||||
{"build": "17A860", "version": "13.1.2"},
|
||||
{"build": "17A854", "version": "13.1.1"},
|
||||
{"build": "17A844", "version": "13.1"},
|
||||
{"build": "17A577", "version": "13.0"},
|
||||
{"build": "16H22", "version": "12.5.1"},
|
||||
{"build": "16H20", "version": "12.5"},
|
||||
{"build": "16H5", "version": "12.4.9"},
|
||||
{"build": "16G201", "version": "12.4.8"},
|
||||
{"build": "16G192", "version": "12.4.7"},
|
||||
{"build": "16G183", "version": "12.4.6"},
|
||||
{"build": "16G161", "version": "12.4.5"},
|
||||
{"build": "16G130", "version": "12.4.3"},
|
||||
{"build": "16G114", "version": "12.4.2"},
|
||||
{"build": "16G102", "version": "12.4.1"},
|
||||
{"build": "16G77", "version": "12.4"},
|
||||
{"build": "16F203", "version": "12.3.1"},
|
||||
{"build": "16F156", "version": "12.3"},
|
||||
{"build": "16E227", "version": "12.2"},
|
||||
{"build": "16D57", "version": "12.1.4"},
|
||||
{"build": "16D39", "version": "12.1.3"},
|
||||
{"build": "16C104", "version": "12.1.2"},
|
||||
{"build": "16C101", "version": "12.1.2"},
|
||||
{"build": "16C50", "version": "12.1.1"},
|
||||
{"build": "16B92", "version": "12.1"},
|
||||
{"build": "16A404", "version": "12.0.1"},
|
||||
{"build": "16A366", "version": "12.0"},
|
||||
{"build": "15G77", "version": "11.4.1"},
|
||||
{"build": "15F79", "version": "11.4"},
|
||||
{"build": "15E302", "version": "11.3.1"},
|
||||
{"build": "15E216", "version": "11.3"},
|
||||
{"build": "15D100", "version": "11.2.6"},
|
||||
{"build": "15D60", "version": "11.2.5"},
|
||||
{"build": "15C202", "version": "11.2.2"},
|
||||
{"build": "15C153", "version": "11.2.1"},
|
||||
{"build": "15C114", "version": "11.2"},
|
||||
{"build": "15B202", "version": "11.1.2"},
|
||||
{"build": "15B150", "version": "11.1.1"},
|
||||
{"build": "15B93", "version": "11.1"},
|
||||
{"build": "15A432", "version": "11.0.3"},
|
||||
{"build": "15A421", "version": "11.0.2"},
|
||||
{"build": "15A402", "version": "11.0.1"},
|
||||
{"build": "15A372", "version": "11.0"},
|
||||
{"build": "13D20", "version": "9.2.1"},
|
||||
{"build": "12B436", "version": "8.1.1"},
|
||||
{"build": "12A366", "version": "8.0"},
|
||||
{"build": "13E234", "version": "9.3"},
|
||||
{"build": "13A405", "version": "9.0.1"},
|
||||
{"build": "13A342", "version": "9.0"},
|
||||
{"build": "13A343", "version": "9.0"},
|
||||
{"build": "14B72c", "version": "10.1"},
|
||||
{"build": "14A551", "version": "10.0.3"},
|
||||
{"build": "16F250", "version": "12.3.2"},
|
||||
{"build": "17A861", "version": "13.1.2"},
|
||||
{"build": "16D40", "version": "12.1.3"},
|
||||
{"build": "16A405", "version": "12.0.1"},
|
||||
{"build": "16B94", "version": "12.1"},
|
||||
{"build": "16B93", "version": "12.1"},
|
||||
{"build": "17E8258", "version": "13.4.1"}
|
||||
{"build": "18E199", "version": "14.5"},
|
||||
{"build": "18E212", "version": "14.5.1"},
|
||||
{"build": "18F72", "version": "14.6"},
|
||||
{"build": "18G69", "version": "14.7"},
|
||||
{"build": "18G82", "version": "14.7.1"},
|
||||
]
|
||||
|
||||
def get_device_desc_from_id(identifier, devices_list=IPHONE_MODELS):
|
||||
for model in IPHONE_MODELS:
|
||||
if identifier == model["identifier"]:
|
||||
return model["description"]
|
||||
|
||||
def find_version_by_build(build):
|
||||
build = build.upper()
|
||||
for version in IPHONE_IOS_VERSIONS:
|
||||
|
||||
Reference in new issue
Block a user