Merge pull request #282 from mvt-project/cli_refactor

CLI refactor
This commit is contained in:
Nex 2022-06-17 10:27:47 +02:00 committed by GitHub
commit 36a67911b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 681 additions and 607 deletions

View File

@ -3,28 +3,23 @@
# Use of this software is governed by the MVT License 1.1 that can be found at # Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import getpass
import io
import logging import logging
import os import os
import tarfile
from pathlib import Path
from zipfile import ZipFile
import click import click
from rich.logging import RichHandler from rich.logging import RichHandler
from mvt.android.parsers.backup import (AndroidBackupParsingError, from mvt.common.cmd_check_iocs import CmdCheckIOCS
InvalidBackupPassword, parse_ab_header,
parse_backup_file)
from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC,
HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE,
HELP_MSG_OUTPUT, HELP_MSG_SERIAL) HELP_MSG_OUTPUT, HELP_MSG_SERIAL)
from mvt.common.indicators import Indicators, download_indicators_files from mvt.common.indicators import download_indicators_files
from mvt.common.logo import logo from mvt.common.logo import logo
from mvt.common.module import run_module, save_timeline
from .download_apks import DownloadAPKs from .cmd_check_adb import CmdAndroidCheckADB
from .cmd_check_backup import CmdAndroidCheckBackup
from .cmd_check_bugreport import CmdAndroidCheckBugreport
from .cmd_download_apks import DownloadAPKs
from .modules.adb import ADB_MODULES from .modules.adb import ADB_MODULES
from .modules.adb.packages import Packages from .modules.adb.packages import Packages
from .modules.backup import BACKUP_MODULES from .modules.backup import BACKUP_MODULES
@ -122,48 +117,20 @@ def download_apks(ctx, all_apks, virustotal, output, from_file, serial):
@click.option("--module", "-m", help=HELP_MSG_MODULE) @click.option("--module", "-m", help=HELP_MSG_MODULE)
@click.pass_context @click.pass_context
def check_adb(ctx, iocs, output, fast, list_modules, module, serial): def check_adb(ctx, iocs, output, fast, list_modules, module, serial):
if list_modules: cmd = CmdAndroidCheckADB(results_path=output, ioc_files=iocs,
log.info("Following is the list of available check-adb modules:") module_name=module, serial=serial, fast_mode=fast)
for adb_module in ADB_MODULES:
log.info(" - %s", adb_module.__name__)
if list_modules:
cmd.list_modules()
return return
log.info("Checking Android through adb bridge") log.info("Checking Android device over debug bridge")
if output and not os.path.exists(output): cmd.run()
try:
os.makedirs(output)
except Exception as e:
log.critical("Unable to create output folder %s: %s", output, e)
ctx.exit(1)
indicators = Indicators(log=log) if len(cmd.timeline_detected) > 0:
indicators.load_indicators_files(iocs) log.warning("The analysis of the Android device produced %d detections!",
len(cmd.timeline_detected))
timeline = []
timeline_detected = []
for adb_module in ADB_MODULES:
if module and adb_module.__name__ != module:
continue
m = adb_module(output_folder=output, fast_mode=fast,
log=logging.getLogger(adb_module.__module__))
if indicators.total_ioc_count:
m.indicators = indicators
m.indicators.log = m.log
if serial:
m.serial = serial
run_module(m)
timeline.extend(m.timeline)
timeline_detected.extend(m.timeline_detected)
if output:
if len(timeline) > 0:
save_timeline(timeline, os.path.join(output, "timeline.csv"))
if len(timeline_detected) > 0:
save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv"))
#============================================================================== #==============================================================================
@ -178,66 +145,20 @@ def check_adb(ctx, iocs, output, fast, list_modules, module, serial):
@click.argument("BUGREPORT_PATH", type=click.Path(exists=True)) @click.argument("BUGREPORT_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path): def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path):
if list_modules: cmd = CmdAndroidCheckBugreport(target_path=bugreport_path, results_path=output,
log.info("Following is the list of available check-bugreport modules:") ioc_files=iocs, module_name=module)
for adb_module in BUGREPORT_MODULES:
log.info(" - %s", adb_module.__name__)
if list_modules:
cmd.list_modules()
return return
log.info("Checking an Android Bug Report located at: %s", bugreport_path) log.info("Checking Android bug report at path: %s", bugreport_path)
if output and not os.path.exists(output): cmd.run()
try:
os.makedirs(output)
except Exception as e:
log.critical("Unable to create output folder %s: %s", output, e)
ctx.exit(1)
indicators = Indicators(log=log) if len(cmd.timeline_detected) > 0:
indicators.load_indicators_files(iocs) log.warning("The analysis of the Android bug report produced %d detections!",
len(cmd.timeline_detected))
if os.path.isfile(bugreport_path):
bugreport_format = "zip"
zip_archive = ZipFile(bugreport_path)
zip_files = []
for file_name in zip_archive.namelist():
zip_files.append(file_name)
elif os.path.isdir(bugreport_path):
bugreport_format = "dir"
folder_files = []
parent_path = Path(bugreport_path).absolute().as_posix()
for root, subdirs, subfiles in os.walk(os.path.abspath(bugreport_path)):
for file_name in subfiles:
folder_files.append(os.path.relpath(os.path.join(root, file_name), parent_path))
timeline = []
timeline_detected = []
for bugreport_module in BUGREPORT_MODULES:
if module and bugreport_module.__name__ != module:
continue
m = bugreport_module(base_folder=bugreport_path, output_folder=output,
log=logging.getLogger(bugreport_module.__module__))
if bugreport_format == "zip":
m.from_zip(zip_archive, zip_files)
else:
m.from_folder(bugreport_path, folder_files)
if indicators.total_ioc_count:
m.indicators = indicators
m.indicators.log = m.log
run_module(m)
timeline.extend(m.timeline)
timeline_detected.extend(m.timeline_detected)
if output:
if len(timeline) > 0:
save_timeline(timeline, os.path.join(output, "timeline.csv"))
if len(timeline_detected) > 0:
save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv"))
#============================================================================== #==============================================================================
@ -248,74 +169,24 @@ def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path):
@click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True, @click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True,
default=[], help=HELP_MSG_IOC) default=[], help=HELP_MSG_IOC)
@click.option("--output", "-o", type=click.Path(exists=False), help=HELP_MSG_OUTPUT) @click.option("--output", "-o", type=click.Path(exists=False), help=HELP_MSG_OUTPUT)
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.argument("BACKUP_PATH", type=click.Path(exists=True)) @click.argument("BACKUP_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_backup(ctx, iocs, output, backup_path, serial): def check_backup(ctx, iocs, output, list_modules, backup_path, serial):
log.info("Checking ADB backup located at: %s", backup_path) cmd = CmdAndroidCheckBackup(target_path=backup_path, results_path=output,
ioc_files=iocs)
if os.path.isfile(backup_path): if list_modules:
# AB File cmd.list_modules()
backup_type = "ab" return
with open(backup_path, "rb") as handle:
data = handle.read()
header = parse_ab_header(data)
if not header["backup"]:
log.critical("Invalid backup format, file should be in .ab format")
ctx.exit(1)
password = None
if header["encryption"] != "none":
password = getpass.getpass(prompt="Backup Password: ", stream=None)
try:
tardata = parse_backup_file(data, password=password)
except InvalidBackupPassword:
log.critical("Invalid backup password")
ctx.exit(1)
except AndroidBackupParsingError:
log.critical("Impossible to parse this backup file, please use Android Backup Extractor instead")
ctx.exit(1)
dbytes = io.BytesIO(tardata) log.info("Checking Android backup at path: %s", backup_path)
tar = tarfile.open(fileobj=dbytes)
files = []
for member in tar:
files.append(member.name)
elif os.path.isdir(backup_path): cmd.run()
backup_type = "folder"
backup_path = Path(backup_path).absolute().as_posix()
files = []
for root, subdirs, subfiles in os.walk(os.path.abspath(backup_path)):
for fname in subfiles:
files.append(os.path.relpath(os.path.join(root, fname), backup_path))
else:
log.critical("Invalid backup path, path should be a folder or an Android Backup (.ab) file")
ctx.exit(1)
if output and not os.path.exists(output): if len(cmd.timeline_detected) > 0:
try: log.warning("The analysis of the Android backup produced %d detections!",
os.makedirs(output) len(cmd.timeline_detected))
except Exception as e:
log.critical("Unable to create output folder %s: %s", output, e)
ctx.exit(1)
indicators = Indicators(log=log)
indicators.load_indicators_files(iocs)
for module in BACKUP_MODULES:
m = module(base_folder=backup_path, output_folder=output,
log=logging.getLogger(module.__module__))
if indicators.total_ioc_count:
m.indicators = indicators
m.indicators.log = m.log
if serial:
m.serial = serial
if backup_type == "folder":
m.from_folder(backup_path, files)
else:
m.from_ab(backup_path, tar, files)
run_module(m)
#============================================================================== #==============================================================================
@ -329,59 +200,14 @@ def check_backup(ctx, iocs, output, backup_path, serial):
@click.argument("FOLDER", type=click.Path(exists=True)) @click.argument("FOLDER", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_iocs(ctx, iocs, list_modules, module, folder): def check_iocs(ctx, iocs, list_modules, module, folder):
all_modules = [] cmd = CmdCheckIOCS(target_path=folder, ioc_files=iocs, module_name=module)
for entry in BACKUP_MODULES + ADB_MODULES: cmd.modules = BACKUP_MODULES + ADB_MODULES + BUGREPORT_MODULES
if entry not in all_modules:
all_modules.append(entry)
if list_modules: if list_modules:
log.info("Following is the list of available check-iocs modules:") cmd.list_modules()
for iocs_module in all_modules:
log.info(" - %s", iocs_module.__name__)
return return
log.info("Checking stored results against provided indicators...") cmd.run()
indicators = Indicators(log=log)
indicators.load_indicators_files(iocs)
total_detections = 0
for file_name in os.listdir(folder):
name_only, ext = os.path.splitext(file_name)
file_path = os.path.join(folder, file_name)
# TODO: Skipping processing of result files that are not json.
# We might want to revisit this eventually.
if ext != ".json":
continue
for iocs_module in all_modules:
if module and iocs_module.__name__ != module:
continue
if iocs_module().get_slug() != name_only:
continue
log.info("Loading results from \"%s\" with module %s", file_name,
iocs_module.__name__)
m = iocs_module.from_json(file_path,
log=logging.getLogger(iocs_module.__module__))
if indicators.total_ioc_count > 0:
m.indicators = indicators
m.indicators.log = m.log
try:
m.check_indicators()
except NotImplementedError:
continue
else:
total_detections += len(m.detected)
if total_detections > 0:
log.warning("The check of the results produced %d detections!",
total_detections)
#============================================================================== #==============================================================================

View File

@ -0,0 +1,24 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
from mvt.common.command import Command
from .modules.adb import ADB_MODULES
log = logging.getLogger(__name__)
class CmdAndroidCheckADB(Command):
name = "check-adb"
modules = ADB_MODULES
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False):
super().__init__(target_path=target_path, results_path=results_path,
ioc_files=ioc_files, module_name=module_name,
serial=serial, fast_mode=fast_mode, log=log)

View File

@ -0,0 +1,82 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import getpass
import io
import logging
import os
import sys
import tarfile
from pathlib import Path
from mvt.android.parsers.backup import (AndroidBackupParsingError,
InvalidBackupPassword, parse_ab_header,
parse_backup_file)
from mvt.common.command import Command
from .modules.backup import BACKUP_MODULES
log = logging.getLogger(__name__)
class CmdAndroidCheckBackup(Command):
name = "check-backup"
modules = BACKUP_MODULES
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False):
super().__init__(target_path=target_path, results_path=results_path,
ioc_files=ioc_files, module_name=module_name,
serial=serial, fast_mode=fast_mode, log=log)
self.backup_type = None
self.backup_archive = None
self.backup_files = []
def init(self):
if os.path.isfile(self.target_path):
self.backup_type = "ab"
with open(self.target_path, "rb") as handle:
data = handle.read()
header = parse_ab_header(data)
if not header["backup"]:
log.critical("Invalid backup format, file should be in .ab format")
sys.exit(1)
password = None
if header["encryption"] != "none":
password = getpass.getpass(prompt="Backup Password: ", stream=None)
try:
tardata = parse_backup_file(data, password=password)
except InvalidBackupPassword:
log.critical("Invalid backup password")
sys.exit(1)
except AndroidBackupParsingError as e:
log.critical("Impossible to parse this backup file: %s", e)
log.critical("Please use Android Backup Extractor (ABE) instead")
sys.exit(1)
dbytes = io.BytesIO(tardata)
self.backup_archive = tarfile.open(fileobj=dbytes)
for member in self.backup_archive:
self.backup_files.append(member.name)
elif os.path.isdir(self.target_path):
self.backup_type = "folder"
self.target_path = Path(self.target_path).absolute().as_posix()
for root, subdirs, subfiles in os.walk(os.path.abspath(self.target_path)):
for fname in subfiles:
self.backup_files.append(os.path.relpath(os.path.join(root, fname), self.target_path))
else:
log.critical("Invalid backup path, path should be a folder or an Android Backup (.ab) file")
sys.exit(1)
def module_init(self, module):
if self.backup_type == "folder":
module.from_folder(self.target_path, self.backup_files)
else:
module.from_ab(self.target_path, self.backup_archive, self.backup_files)

View File

@ -0,0 +1,50 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
import os
from pathlib import Path
from zipfile import ZipFile
from mvt.common.command import Command
from .modules.bugreport import BUGREPORT_MODULES
log = logging.getLogger(__name__)
class CmdAndroidCheckBugreport(Command):
name = "check-bugreport"
modules = BUGREPORT_MODULES
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False):
super().__init__(target_path=target_path, results_path=results_path,
ioc_files=ioc_files, module_name=module_name,
serial=serial, fast_mode=fast_mode, log=log)
self.bugreport_format = None
self.bugreport_archive = None
self.bugreport_files = []
def init(self):
if os.path.isfile(self.target_path):
self.bugreport_format = "zip"
self.bugreport_archive = ZipFile(self.target_path)
for file_name in self.bugreport_archive.namelist():
self.bugreport_files.append(file_name)
elif os.path.isdir(self.target_path):
self.bugreport_format = "dir"
parent_path = Path(self.target_path).absolute().as_posix()
for root, subdirs, subfiles in os.walk(os.path.abspath(self.target_path)):
for file_name in subfiles:
self.bugreport_files.append(os.path.relpath(os.path.join(root, file_name), parent_path))
def module_init(self, module):
if self.bugreport_format == "zip":
module.from_zip(self.bugreport_archive, self.bugreport_files)
else:
module.from_folder(self.target_path, self.bugreport_files)

View File

@ -33,10 +33,10 @@ ADB_PUB_KEY_PATH = os.path.expanduser("~/.android/adbkey.pub")
class AndroidExtraction(MVTModule): class AndroidExtraction(MVTModule):
"""This class provides a base for all Android extraction modules.""" """This class provides a base for all Android extraction modules."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.device = None self.device = None

View File

@ -20,10 +20,10 @@ CHROME_HISTORY_PATH = "data/data/com.android.chrome/app_chrome/Default/History"
class ChromeHistory(AndroidExtraction): class ChromeHistory(AndroidExtraction):
"""This module extracts records from Android's Chrome browsing history.""" """This module extracts records from Android's Chrome browsing history."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class DumpsysAccessibility(AndroidExtraction): class DumpsysAccessibility(AndroidExtraction):
"""This module extracts stats on accessibility.""" """This module extracts stats on accessibility."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class DumpsysActivities(AndroidExtraction): class DumpsysActivities(AndroidExtraction):
"""This module extracts details on receivers for risky activities.""" """This module extracts details on receivers for risky activities."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = results if results else {} self.results = results if results else {}

View File

@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import re
from mvt.android.parsers.dumpsys import parse_dumpsys_appops from mvt.android.parsers.dumpsys import parse_dumpsys_appops
@ -18,10 +17,10 @@ class DumpsysAppOps(AndroidExtraction):
slug = "dumpsys_appops" slug = "dumpsys_appops"
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class DumpsysBatteryDaily(AndroidExtraction): class DumpsysBatteryDaily(AndroidExtraction):
"""This module extracts records from battery daily updates.""" """This module extracts records from battery daily updates."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class DumpsysBatteryHistory(AndroidExtraction): class DumpsysBatteryHistory(AndroidExtraction):
"""This module extracts records from battery history events.""" """This module extracts records from battery history events."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import re
from mvt.android.parsers import parse_dumpsys_dbinfo from mvt.android.parsers import parse_dumpsys_dbinfo
@ -18,10 +17,10 @@ class DumpsysDBInfo(AndroidExtraction):
slug = "dumpsys_dbinfo" slug = "dumpsys_dbinfo"
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -14,18 +14,18 @@ log = logging.getLogger(__name__)
class DumpsysFull(AndroidExtraction): class DumpsysFull(AndroidExtraction):
"""This module extracts stats on battery consumption by processes.""" """This module extracts stats on battery consumption by processes."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):
self._adb_connect() self._adb_connect()
output = self._adb_command("dumpsys") output = self._adb_command("dumpsys")
if self.output_folder: if self.results_path:
output_path = os.path.join(self.output_folder, "dumpsys.txt") output_path = os.path.join(self.results_path, "dumpsys.txt")
with open(output_path, "w", encoding="utf-8") as handle: with open(output_path, "w", encoding="utf-8") as handle:
handle.write(output) handle.write(output)

View File

@ -21,10 +21,10 @@ INTENT_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL"
class DumpsysReceivers(AndroidExtraction): class DumpsysReceivers(AndroidExtraction):
"""This module extracts details on receivers for risky activities.""" """This module extracts details on receivers for risky activities."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = results if results else {} self.results = results if results else {}

View File

@ -17,10 +17,10 @@ log = logging.getLogger(__name__)
class Files(AndroidExtraction): class Files(AndroidExtraction):
"""This module extracts the list of files on the device.""" """This module extracts the list of files on the device."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.full_find = False self.full_find = False

View File

@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from mvt.android.parsers import parse_getprop from mvt.android.parsers import parse_getprop
@ -17,10 +16,10 @@ log = logging.getLogger(__name__)
class Getprop(AndroidExtraction): class Getprop(AndroidExtraction):
"""This module extracts device properties from getprop command.""" """This module extracts device properties from getprop command."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} if not results else results self.results = {} if not results else results

View File

@ -14,10 +14,10 @@ log = logging.getLogger(__name__)
class Logcat(AndroidExtraction): class Logcat(AndroidExtraction):
"""This module extracts details on installed packages.""" """This module extracts details on installed packages."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):
@ -28,8 +28,8 @@ class Logcat(AndroidExtraction):
# Get the locat prior to last reboot. # Get the locat prior to last reboot.
last_output = self._adb_command("logcat -L") last_output = self._adb_command("logcat -L")
if self.output_folder: if self.results_path:
logcat_path = os.path.join(self.output_folder, logcat_path = os.path.join(self.results_path,
"logcat.txt") "logcat.txt")
with open(logcat_path, "w", encoding="utf-8") as handle: with open(logcat_path, "w", encoding="utf-8") as handle:
handle.write(output) handle.write(output)
@ -37,7 +37,7 @@ class Logcat(AndroidExtraction):
log.info("Current logcat logs stored at %s", log.info("Current logcat logs stored at %s",
logcat_path) logcat_path)
logcat_last_path = os.path.join(self.output_folder, logcat_last_path = os.path.join(self.results_path,
"logcat_last.txt") "logcat_last.txt")
with open(logcat_last_path, "w", encoding="utf-8") as handle: with open(logcat_last_path, "w", encoding="utf-8") as handle:
handle.write(last_output) handle.write(last_output)

View File

@ -4,9 +4,7 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import os
import pkg_resources
from rich.console import Console from rich.console import Console
from rich.progress import track from rich.progress import track
from rich.table import Table from rich.table import Table
@ -74,10 +72,10 @@ ROOT_PACKAGES = [
class Packages(AndroidExtraction): class Packages(AndroidExtraction):
"""This module extracts the list of installed packages.""" """This module extracts the list of installed packages."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):
@ -116,7 +114,7 @@ class Packages(AndroidExtraction):
self.detected.append(result) self.detected.append(result)
continue continue
for package_file in result["files"]: for package_file in result.get("files", []):
ioc = self.indicators.check_file_hash(package_file["sha256"]) ioc = self.indicators.check_file_hash(package_file["sha256"])
if ioc: if ioc:
result["matched_indicator"] = ioc result["matched_indicator"] = ioc

View File

@ -13,10 +13,10 @@ log = logging.getLogger(__name__)
class Processes(AndroidExtraction): class Processes(AndroidExtraction):
"""This module extracts details on running processes.""" """This module extracts details on running processes."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -13,10 +13,10 @@ log = logging.getLogger(__name__)
class RootBinaries(AndroidExtraction): class RootBinaries(AndroidExtraction):
"""This module extracts the list of installed packages.""" """This module extracts the list of installed packages."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):

View File

@ -4,9 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import os
import pkg_resources
from .base import AndroidExtraction from .base import AndroidExtraction
@ -18,10 +15,10 @@ class SELinuxStatus(AndroidExtraction):
slug = "selinux_status" slug = "selinux_status"
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} if not results else results self.results = {} if not results else results

View File

@ -57,10 +57,10 @@ ANDROID_DANGEROUS_SETTINGS = [
class Settings(AndroidExtraction): class Settings(AndroidExtraction):
"""This module extracts Android system settings.""" """This module extracts Android system settings."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} if not results else results self.results = {} if not results else results

View File

@ -3,8 +3,6 @@
# Use of this software is governed by the MVT License 1.1 that can be found at # Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import base64
import getpass
import logging import logging
import os import os
import sqlite3 import sqlite3
@ -48,10 +46,10 @@ FROM sms;
class SMS(AndroidExtraction): class SMS(AndroidExtraction):
"""This module extracts all SMS messages containing links.""" """This module extracts all SMS messages containing links."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -20,10 +20,10 @@ WHATSAPP_PATH = "data/data/com.whatsapp/databases/msgstore.db"
class Whatsapp(AndroidExtraction): class Whatsapp(AndroidExtraction):
"""This module extracts all WhatsApp messages containing links.""" """This module extracts all WhatsApp messages containing links."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -5,14 +5,13 @@
from mvt.android.modules.backup.base import BackupExtraction from mvt.android.modules.backup.base import BackupExtraction
from mvt.android.parsers.backup import parse_sms_file from mvt.android.parsers.backup import parse_sms_file
from mvt.common.utils import check_for_links
class SMS(BackupExtraction): class SMS(BackupExtraction):
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = [] self.results = []

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class Accessibility(BugReportModule): class Accessibility(BugReportModule):
"""This module extracts stats on accessibility.""" """This module extracts stats on accessibility."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class Activities(BugReportModule): class Activities(BugReportModule):
"""This module extracts details on receivers for risky activities.""" """This module extracts details on receivers for risky activities."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = results if results else {} self.results = results if results else {}

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class Appops(BugReportModule): class Appops(BugReportModule):
"""This module extracts information on package from App-Ops Manager.""" """This module extracts information on package from App-Ops Manager."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class BatteryDaily(BugReportModule): class BatteryDaily(BugReportModule):
"""This module extracts records from battery daily updates.""" """This module extracts records from battery daily updates."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ log = logging.getLogger(__name__)
class BatteryHistory(BugReportModule): class BatteryHistory(BugReportModule):
"""This module extracts records from battery daily updates.""" """This module extracts records from battery daily updates."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -17,10 +17,10 @@ class DBInfo(BugReportModule):
slug = "dbinfo" slug = "dbinfo"
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def check_indicators(self): def check_indicators(self):

View File

@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from mvt.android.parsers import parse_getprop from mvt.android.parsers import parse_getprop
@ -17,10 +16,10 @@ log = logging.getLogger(__name__)
class Getprop(BugReportModule): class Getprop(BugReportModule):
"""This module extracts device properties from getprop command.""" """This module extracts device properties from getprop command."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} if not results else results self.results = {} if not results else results

View File

@ -14,10 +14,10 @@ log = logging.getLogger(__name__)
class Packages(BugReportModule): class Packages(BugReportModule):
"""This module extracts details on receivers for risky activities.""" """This module extracts details on receivers for risky activities."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -21,10 +21,10 @@ INTENT_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL"
class Receivers(BugReportModule): class Receivers(BugReportModule):
"""This module extracts details on receivers for risky activities.""" """This module extracts details on receivers for risky activities."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
serial=None, fast_mode=False, log=None, results=[]): serial=None, fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = results if results else {} self.results = results if results else {}

View File

@ -70,11 +70,11 @@ def decrypt_master_key(password, user_salt, user_iv, pbkdf2_rounds, master_key_b
The backup master key is extracted from the master key blog after decryption. The backup master key is extracted from the master key blog after decryption.
""" """
# Derive key from password using PBKDF2 # Derive key from password using PBKDF2.
kdf = PBKDF2HMAC(algorithm=hashes.SHA1(), length=32, salt=user_salt, iterations=pbkdf2_rounds) kdf = PBKDF2HMAC(algorithm=hashes.SHA1(), length=32, salt=user_salt, iterations=pbkdf2_rounds)
key = kdf.derive(password.encode("utf-8")) key = kdf.derive(password.encode("utf-8"))
# Decrypt master key blob # Decrypt master key blob.
cipher = Cipher(algorithms.AES(key), modes.CBC(user_iv)) cipher = Cipher(algorithms.AES(key), modes.CBC(user_iv))
decryptor = cipher.decryptor() decryptor = cipher.decryptor()
try: try:
@ -93,7 +93,7 @@ def decrypt_master_key(password, user_salt, user_iv, pbkdf2_rounds, master_key_b
except TypeError: except TypeError:
raise InvalidBackupPassword() raise InvalidBackupPassword()
# Handle quirky encoding of master key bytes in Android original Java crypto code # Handle quirky encoding of master key bytes in Android original Java crypto code.
if format_version > 1: if format_version > 1:
hmac_mk = to_utf8_bytes(master_key) hmac_mk = to_utf8_bytes(master_key)
else: else:
@ -112,6 +112,7 @@ def decrypt_master_key(password, user_salt, user_iv, pbkdf2_rounds, master_key_b
def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_version): def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_version):
""" """
Generate encryption keyffrom password and do decryption Generate encryption keyffrom password and do decryption
""" """
if encryption_algo != b"AES-256": if encryption_algo != b"AES-256":
raise AndroidBackupNotImplemented("Encryption Algorithm not implemented") raise AndroidBackupNotImplemented("Encryption Algorithm not implemented")
@ -126,12 +127,12 @@ def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_vers
user_iv = bytes.fromhex(user_iv.decode("utf-8")) user_iv = bytes.fromhex(user_iv.decode("utf-8"))
master_key_blob = bytes.fromhex(master_key_blob.decode("utf-8")) master_key_blob = bytes.fromhex(master_key_blob.decode("utf-8"))
# Derive decryption master key from password # Derive decryption master key from password.
master_key, master_iv = decrypt_master_key(password=password, user_salt=user_salt, user_iv=user_iv, master_key, master_iv = decrypt_master_key(password=password, user_salt=user_salt, user_iv=user_iv,
pbkdf2_rounds=pbkdf2_rounds, master_key_blob=master_key_blob, pbkdf2_rounds=pbkdf2_rounds, master_key_blob=master_key_blob,
format_version=format_version, checksum_salt=checksum_salt) format_version=format_version, checksum_salt=checksum_salt)
# Decrypt and unpad backup data using derivied key # Decrypt and unpad backup data using derivied key.
cipher = Cipher(algorithms.AES(master_key), modes.CBC(master_iv)) cipher = Cipher(algorithms.AES(master_key), modes.CBC(master_iv))
decryptor = cipher.decryptor() decryptor = cipher.decryptor()
decrypted_tar = decryptor.update(encrypted_data) + decryptor.finalize() decrypted_tar = decryptor.update(encrypted_data) + decryptor.finalize()
@ -143,6 +144,7 @@ def decrypt_backup_data(encrypted_backup, password, encryption_algo, format_vers
def parse_backup_file(data, password=None): def parse_backup_file(data, password=None):
""" """
Parse an ab file, returns a tar file Parse an ab file, returns a tar file
""" """
if not data.startswith(b"ANDROID BACKUP"): if not data.startswith(b"ANDROID BACKUP"):
raise AndroidBackupParsingError("Invalid file header") raise AndroidBackupParsingError("Invalid file header")

View File

@ -0,0 +1,63 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
import os
from mvt.common.command import Command
log = logging.getLogger(__name__)
class CmdCheckIOCS(Command):
name = "check-iocs"
modules = []
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False):
super().__init__(target_path=target_path, results_path=results_path,
ioc_files=ioc_files, module_name=module_name,
serial=serial, fast_mode=fast_mode, log=log)
def run(self):
all_modules = []
for entry in self.modules:
if entry not in all_modules:
all_modules.append(entry)
log.info("Checking stored results against provided indicators...")
total_detections = 0
for file_name in os.listdir(self.target_path):
name_only, ext = os.path.splitext(file_name)
file_path = os.path.join(self.target_path, file_name)
for iocs_module in all_modules:
if self.module_name and iocs_module.__name__ != self.module_name:
continue
if iocs_module().get_slug() != name_only:
continue
log.info("Loading results from \"%s\" with module %s", file_name,
iocs_module.__name__)
m = iocs_module.from_json(file_path,
log=logging.getLogger(iocs_module.__module__))
if self.iocs.total_ioc_count > 0:
m.indicators = self.iocs
m.indicators.log = m.log
try:
m.check_indicators()
except NotImplementedError:
continue
else:
total_detections += len(m.detected)
if total_detections > 0:
log.warning("The check of the results produced %d detections!",
total_detections)

95
mvt/common/command.py Normal file
View File

@ -0,0 +1,95 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
import os
import sys
from mvt.common.indicators import Indicators
from mvt.common.module import run_module, save_timeline
class Command(object):
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False,
log=logging.getLogger(__name__)):
self.target_path = target_path
self.results_path = results_path
self.ioc_files = ioc_files
self.module_name = module_name
self.serial = serial
self.fast_mode = fast_mode
self.log = log
self.iocs = Indicators(log=log)
self.iocs.load_indicators_files(ioc_files)
self.timeline = []
self.timeline_detected = []
def list_modules(self):
self.log.info("Following is the list of available %s modules:", self.name)
for module in self.modules:
self.log.info(" - %s", module.__name__)
def _create_storage(self):
if self.results_path and not os.path.exists(self.results_path):
try:
os.makedirs(self.results_path)
except Exception as e:
self.log.critical("Unable to create output folder %s: %s",
self.results_path, e)
sys.exit(1)
def _store_timeline(self):
if self.results_path:
if len(self.timeline) > 0:
save_timeline(self.timeline,
os.path.join(self.results_path, "timeline.csv"))
if len(self.timeline_detected) > 0:
save_timeline(self.timeline_detected,
os.path.join(self.results_path, "timeline_detected.csv"))
def init(self):
raise NotImplementedError
def module_init(self, module):
raise NotImplementedError
def run(self):
self._create_storage()
try:
self.init()
except NotImplementedError:
pass
for module in self.modules:
if self.module_name and module.__name__ != self.module_name:
continue
m = module(target_path=self.target_path, results_path=self.results_path, fast_mode=self.fast_mode,
log=logging.getLogger(module.__module__))
if self.iocs.total_ioc_count:
m.indicators = self.iocs
m.indicators.log = m.log
if self.serial:
m.serial = self.serial
try:
self.module_init(m)
except NotImplementedError:
pass
run_module(m)
self.timeline.extend(m.timeline)
self.timeline_detected.extend(m.timeline_detected)
self._store_timeline()

View File

@ -28,16 +28,16 @@ class MVTModule(object):
enabled = True enabled = True
slug = None slug = None
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=None): fast_mode=False, log=None, results=None):
"""Initialize module. """Initialize module.
:param file_path: Path to the module's database file, if there is any :param file_path: Path to the module's database file, if there is any
:type file_path: str :type file_path: str
:param base_folder: Path to the base folder (backup or filesystem dump) :param target_path: Path to the target folder (backup or filesystem dump)
:type file_path: str :type file_path: str
:param output_folder: Folder where results will be stored :param results_path: Folder where results will be stored
:type output_folder: str :type results_path: str
:param fast_mode: Flag to enable or disable slow modules :param fast_mode: Flag to enable or disable slow modules
:type fast_mode: bool :type fast_mode: bool
:param log: Handle to logger :param log: Handle to logger
@ -45,8 +45,8 @@ class MVTModule(object):
:type results: list :type results: list
""" """
self.file_path = file_path self.file_path = file_path
self.base_folder = base_folder self.target_path = target_path
self.output_folder = output_folder self.results_path = results_path
self.fast_mode = fast_mode self.fast_mode = fast_mode
self.log = log self.log = log
self.indicators = None self.indicators = None
@ -82,14 +82,14 @@ class MVTModule(object):
def save_to_json(self): def save_to_json(self):
"""Save the collected results to a json file.""" """Save the collected results to a json file."""
if not self.output_folder: if not self.results_path:
return return
name = self.get_slug() name = self.get_slug()
if self.results: if self.results:
results_file_name = f"{name}.json" results_file_name = f"{name}.json"
results_json_path = os.path.join(self.output_folder, results_file_name) results_json_path = os.path.join(self.results_path, results_file_name)
with open(results_json_path, "w", encoding="utf-8") as handle: with open(results_json_path, "w", encoding="utf-8") as handle:
try: try:
json.dump(self.results, handle, indent=4, default=str) json.dump(self.results, handle, indent=4, default=str)
@ -99,7 +99,7 @@ class MVTModule(object):
if self.detected: if self.detected:
detected_file_name = f"{name}_detected.json" detected_file_name = f"{name}_detected.json"
detected_json_path = os.path.join(self.output_folder, detected_file_name) detected_json_path = os.path.join(self.results_path, detected_file_name)
with open(detected_json_path, "w", encoding="utf-8") as handle: with open(detected_json_path, "w", encoding="utf-8") as handle:
json.dump(self.detected, handle, indent=4, default=str) json.dump(self.detected, handle, indent=4, default=str)

View File

@ -10,14 +10,16 @@ import click
from rich.logging import RichHandler from rich.logging import RichHandler
from rich.prompt import Prompt from rich.prompt import Prompt
from mvt.common.cmd_check_iocs import CmdCheckIOCS
from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC, from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC,
HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE,
HELP_MSG_OUTPUT) HELP_MSG_OUTPUT)
from mvt.common.indicators import Indicators, download_indicators_files from mvt.common.indicators import download_indicators_files
from mvt.common.logo import logo from mvt.common.logo import logo
from mvt.common.module import run_module, save_timeline
from mvt.common.options import MutuallyExclusiveOption from mvt.common.options import MutuallyExclusiveOption
from .cmd_check_backup import CmdIOSCheckBackup
from .cmd_check_fs import CmdIOSCheckFS
from .decrypt import DecryptBackup from .decrypt import DecryptBackup
from .modules.backup import BACKUP_MODULES from .modules.backup import BACKUP_MODULES
from .modules.fs import FS_MODULES from .modules.fs import FS_MODULES
@ -140,51 +142,20 @@ def extract_key(password, backup_path, key_file):
@click.argument("BACKUP_PATH", type=click.Path(exists=True)) @click.argument("BACKUP_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_backup(ctx, iocs, output, fast, backup_path, list_modules, module): def check_backup(ctx, iocs, output, fast, backup_path, list_modules, module):
if list_modules: cmd = CmdIOSCheckBackup(target_path=backup_path, results_path=output,
log.info("Following is the list of available check-backup modules:") ioc_files=iocs, module_name=module, fast_mode=fast)
for backup_module in BACKUP_MODULES + MIXED_MODULES:
log.info(" - %s", backup_module.__name__)
if list_modules:
cmd.list_modules()
return return
log.info("Checking iTunes backup located at: %s", backup_path) log.info("Checking iTunes backup located at: %s", backup_path)
if output and not os.path.exists(output): cmd.run()
try:
os.makedirs(output)
except Exception as e:
log.critical("Unable to create output folder %s: %s", output, e)
ctx.exit(1)
indicators = Indicators(log=log) if len(cmd.timeline_detected) > 0:
indicators.load_indicators_files(iocs)
timeline = []
timeline_detected = []
for backup_module in BACKUP_MODULES + MIXED_MODULES:
if module and backup_module.__name__ != module:
continue
m = backup_module(base_folder=backup_path, output_folder=output, fast_mode=fast,
log=logging.getLogger(backup_module.__module__))
m.is_backup = True
if indicators.total_ioc_count > 0:
m.indicators = indicators
m.indicators.log = m.log
run_module(m)
timeline.extend(m.timeline)
timeline_detected.extend(m.timeline_detected)
if output:
if len(timeline) > 0:
save_timeline(timeline, os.path.join(output, "timeline.csv"))
if len(timeline_detected) > 0:
save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv"))
if len(timeline_detected) > 0:
log.warning("The analysis of the backup produced %d detections!", log.warning("The analysis of the backup produced %d detections!",
len(timeline_detected)) len(cmd.timeline_detected))
#============================================================================== #==============================================================================
@ -200,52 +171,20 @@ def check_backup(ctx, iocs, output, fast, backup_path, list_modules, module):
@click.argument("DUMP_PATH", type=click.Path(exists=True)) @click.argument("DUMP_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_fs(ctx, iocs, output, fast, dump_path, list_modules, module): def check_fs(ctx, iocs, output, fast, dump_path, list_modules, module):
if list_modules: cmd = CmdIOSCheckFS(target_path=dump_path, results_path=output,
log.info("Following is the list of available check-fs modules:") ioc_files=iocs, module_name=module, fast_mode=fast)
for fs_module in FS_MODULES + MIXED_MODULES:
log.info(" - %s", fs_module.__name__)
if list_modules:
cmd.list_modules()
return return
log.info("Checking filesystem dump located at: %s", dump_path) log.info("Checking iOS filesystem located at: %s", dump_path)
if output and not os.path.exists(output): cmd.run()
try:
os.makedirs(output)
except Exception as e:
log.critical("Unable to create output folder %s: %s", output, e)
ctx.exit(1)
indicators = Indicators(log=log) if len(cmd.timeline_detected) > 0:
indicators.load_indicators_files(iocs) log.warning("The analysis of the iOS filesystem produced %d detections!",
len(cmd.timeline_detected))
timeline = []
timeline_detected = []
for fs_module in FS_MODULES + MIXED_MODULES:
if module and fs_module.__name__ != module:
continue
m = fs_module(base_folder=dump_path, output_folder=output, fast_mode=fast,
log=logging.getLogger(fs_module.__module__))
m.is_fs_dump = True
if indicators.total_ioc_count > 0:
m.indicators = indicators
m.indicators.log = m.log
run_module(m)
timeline.extend(m.timeline)
timeline_detected.extend(m.timeline_detected)
if output:
if len(timeline) > 0:
save_timeline(timeline, os.path.join(output, "timeline.csv"))
if len(timeline_detected) > 0:
save_timeline(timeline_detected, os.path.join(output, "timeline_detected.csv"))
if len(timeline_detected) > 0:
log.warning("The analysis of the filesystem produced %d detections!",
len(timeline_detected))
#============================================================================== #==============================================================================
@ -259,54 +198,14 @@ def check_fs(ctx, iocs, output, fast, dump_path, list_modules, module):
@click.argument("FOLDER", type=click.Path(exists=True)) @click.argument("FOLDER", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_iocs(ctx, iocs, list_modules, module, folder): def check_iocs(ctx, iocs, list_modules, module, folder):
all_modules = [] cmd = CmdCheckIOCS(target_path=folder, ioc_files=iocs, module_name=module)
for entry in BACKUP_MODULES + FS_MODULES + MIXED_MODULES: cmd.modules = BACKUP_MODULES + FS_MODULES + MIXED_MODULES
if entry not in all_modules:
all_modules.append(entry)
if list_modules: if list_modules:
log.info("Following is the list of available check-iocs modules:") cmd.list_modules()
for iocs_module in all_modules:
log.info(" - %s", iocs_module.__name__)
return return
log.info("Checking stored results against provided indicators...") cmd.run()
indicators = Indicators(log=log)
indicators.load_indicators_files(iocs)
total_detections = 0
for file_name in os.listdir(folder):
name_only, ext = os.path.splitext(file_name)
file_path = os.path.join(folder, file_name)
for iocs_module in all_modules:
if module and iocs_module.__name__ != module:
continue
if iocs_module().get_slug() != name_only:
continue
log.info("Loading results from \"%s\" with module %s", file_name,
iocs_module.__name__)
m = iocs_module.from_json(file_path,
log=logging.getLogger(iocs_module.__module__))
if indicators.total_ioc_count > 0:
m.indicators = indicators
m.indicators.log = m.log
try:
m.check_indicators()
except NotImplementedError:
continue
else:
total_detections += len(m.detected)
if total_detections > 0:
log.warning("The check of the results produced %d detections!",
total_detections)
#============================================================================== #==============================================================================

View File

@ -0,0 +1,25 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
from mvt.common.command import Command
from .modules.backup import BACKUP_MODULES
from .modules.mixed import MIXED_MODULES
log = logging.getLogger(__name__)
class CmdIOSCheckBackup(Command):
name = "check-backup"
modules = BACKUP_MODULES + MIXED_MODULES
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False):
super().__init__(target_path=target_path, results_path=results_path,
ioc_files=ioc_files, module_name=module_name,
serial=serial, fast_mode=fast_mode, log=log)

25
mvt/ios/cmd_check_fs.py Normal file
View File

@ -0,0 +1,25 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2022 Claudio Guarnieri.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
from mvt.common.command import Command
from .modules.fs import FS_MODULES
from .modules.mixed import MIXED_MODULES
log = logging.getLogger(__name__)
class CmdIOSCheckFS(Command):
name = "check-fs"
modules = FS_MODULES + MIXED_MODULES
def __init__(self, target_path=None, results_path=None, ioc_files=[],
module_name=None, serial=None, fast_mode=False):
super().__init__(target_path=target_path, results_path=results_path,
ioc_files=ioc_files, module_name=module_name,
serial=serial, fast_mode=fast_mode, log=log)

View File

@ -15,16 +15,16 @@ from ..base import IOSExtraction
class BackupInfo(IOSExtraction): class BackupInfo(IOSExtraction):
"""This module extracts information about the device and the backup.""" """This module extracts information about the device and the backup."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} self.results = {}
def run(self): def run(self):
info_path = os.path.join(self.base_folder, "Info.plist") info_path = os.path.join(self.target_path, "Info.plist")
if not os.path.exists(info_path): if not os.path.exists(info_path):
raise DatabaseNotFoundError("No Info.plist at backup path, unable to extract device information") raise DatabaseNotFoundError("No Info.plist at backup path, unable to extract device information")

View File

@ -17,10 +17,10 @@ CONF_PROFILES_DOMAIN = "SysSharedContainerDomain-systemgroup.com.apple.configura
class ConfigurationProfiles(IOSExtraction): class ConfigurationProfiles(IOSExtraction):
"""This module extracts the full plist data from configuration profiles.""" """This module extracts the full plist data from configuration profiles."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -18,10 +18,10 @@ from ..base import IOSExtraction
class Manifest(IOSExtraction): class Manifest(IOSExtraction):
"""This module extracts information from a backup Manifest.db file.""" """This module extracts information from a backup Manifest.db file."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def _get_key(self, dictionary, key): def _get_key(self, dictionary, key):
@ -93,7 +93,7 @@ class Manifest(IOSExtraction):
self.detected.append(result) self.detected.append(result)
def run(self): def run(self):
manifest_db_path = os.path.join(self.base_folder, "Manifest.db") manifest_db_path = os.path.join(self.target_path, "Manifest.db")
if not os.path.isfile(manifest_db_path): if not os.path.isfile(manifest_db_path):
raise DatabaseNotFoundError("unable to find backup's Manifest.db") raise DatabaseNotFoundError("unable to find backup's Manifest.db")

View File

@ -19,10 +19,10 @@ class ProfileEvents(IOSExtraction):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -16,10 +16,10 @@ from mvt.common.module import (DatabaseCorruptedError, DatabaseNotFoundError,
class IOSExtraction(MVTModule): class IOSExtraction(MVTModule):
"""This class provides a base for all iOS filesystem/backup extraction modules.""" """This class provides a base for all iOS filesystem/backup extraction modules."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.is_backup = False self.is_backup = False
@ -73,7 +73,7 @@ class IOSExtraction(MVTModule):
:param domain: Domain to use as filter from Manifest.db. (Default value = None) :param domain: Domain to use as filter from Manifest.db. (Default value = None)
""" """
manifest_db_path = os.path.join(self.base_folder, "Manifest.db") manifest_db_path = os.path.join(self.target_path, "Manifest.db")
if not os.path.exists(manifest_db_path): if not os.path.exists(manifest_db_path):
raise DatabaseNotFoundError("unable to find backup's Manifest.db") raise DatabaseNotFoundError("unable to find backup's Manifest.db")
@ -101,7 +101,7 @@ class IOSExtraction(MVTModule):
} }
def _get_backup_file_from_id(self, file_id): def _get_backup_file_from_id(self, file_id):
file_path = os.path.join(self.base_folder, file_id[0:2], file_id) file_path = os.path.join(self.target_path, file_id[0:2], file_id)
if os.path.exists(file_path): if os.path.exists(file_path):
return file_path return file_path
@ -109,7 +109,7 @@ class IOSExtraction(MVTModule):
def _get_fs_files_from_patterns(self, root_paths): def _get_fs_files_from_patterns(self, root_paths):
for root_path in root_paths: for root_path in root_paths:
for found_path in glob.glob(os.path.join(self.base_folder, root_path)): for found_path in glob.glob(os.path.join(self.target_path, root_path)):
if not os.path.exists(found_path): if not os.path.exists(found_path):
continue continue

View File

@ -18,10 +18,10 @@ ANALYTICS_DB_PATH = [
class Analytics(IOSExtraction): class Analytics(IOSExtraction):
"""This module extracts information from the private/var/Keychains/Analytics/*.db files.""" """This module extracts information from the private/var/Keychains/Analytics/*.db files."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -11,10 +11,10 @@ from ..base import IOSExtraction
class CacheFiles(IOSExtraction): class CacheFiles(IOSExtraction):
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):
@ -55,7 +55,7 @@ class CacheFiles(IOSExtraction):
except sqlite3.OperationalError: except sqlite3.OperationalError:
return return
key_name = os.path.relpath(file_path, self.base_folder) key_name = os.path.relpath(file_path, self.target_path)
if key_name not in self.results: if key_name not in self.results:
self.results[key_name] = [] self.results[key_name] = []
@ -71,7 +71,7 @@ class CacheFiles(IOSExtraction):
def run(self): def run(self):
self.results = {} self.results = {}
for root, dirs, files in os.walk(self.base_folder): for root, dirs, files in os.walk(self.target_path):
for file_name in files: for file_name in files:
if file_name != "Cache.db": if file_name != "Cache.db":
continue continue

View File

@ -18,10 +18,10 @@ class Filesystem(IOSExtraction):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):
@ -58,12 +58,12 @@ class Filesystem(IOSExtraction):
self.detected.append(result) self.detected.append(result)
def run(self): def run(self):
for root, dirs, files in os.walk(self.base_folder): for root, dirs, files in os.walk(self.target_path):
for dir_name in dirs: for dir_name in dirs:
try: try:
dir_path = os.path.join(root, dir_name) dir_path = os.path.join(root, dir_name)
result = { result = {
"path": os.path.relpath(dir_path, self.base_folder), "path": os.path.relpath(dir_path, self.target_path),
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(dir_path).st_mtime)), "modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(dir_path).st_mtime)),
} }
except Exception: except Exception:
@ -75,7 +75,7 @@ class Filesystem(IOSExtraction):
try: try:
file_path = os.path.join(root, file_name) file_path = os.path.join(root, file_name)
result = { result = {
"path": os.path.relpath(file_path, self.base_folder), "path": os.path.relpath(file_path, self.target_path),
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(file_path).st_mtime)), "modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(file_path).st_mtime)),
} }
except Exception: except Exception:

View File

@ -20,10 +20,10 @@ class Netusage(NetBase):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):

View File

@ -18,10 +18,10 @@ SAFARI_FAVICON_ROOT_PATHS = [
class SafariFavicon(IOSExtraction): class SafariFavicon(IOSExtraction):
"""This module extracts all Safari favicon records.""" """This module extracts all Safari favicon records."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ SHUTDOWN_LOG_PATH = [
class ShutdownLog(IOSExtraction): class ShutdownLog(IOSExtraction):
"""This module extracts processes information from the shutdown log file.""" """This module extracts processes information from the shutdown log file."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -18,10 +18,10 @@ IOS_ANALYTICS_JOURNAL_PATHS = [
class IOSVersionHistory(IOSExtraction): class IOSVersionHistory(IOSExtraction):
"""This module extracts iOS update history from Analytics Journal log files.""" """This module extracts iOS update history from Analytics Journal log files."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -26,7 +26,7 @@ class WebkitBase(IOSExtraction):
def _process_webkit_folder(self, root_paths): def _process_webkit_folder(self, root_paths):
for found_path in self._get_fs_files_from_patterns(root_paths): for found_path in self._get_fs_files_from_patterns(root_paths):
key = os.path.relpath(found_path, self.base_folder) key = os.path.relpath(found_path, self.target_path)
for name in os.listdir(found_path): for name in os.listdir(found_path):
if not name.startswith("http"): if not name.startswith("http"):

View File

@ -19,10 +19,10 @@ class WebkitIndexedDB(WebkitBase):
slug = "webkit_indexeddb" slug = "webkit_indexeddb"
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -17,10 +17,10 @@ class WebkitLocalStorage(WebkitBase):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -17,10 +17,10 @@ class WebkitSafariViewService(WebkitBase):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):

View File

@ -20,10 +20,10 @@ CALLS_ROOT_PATHS = [
class Calls(IOSExtraction): class Calls(IOSExtraction):
"""This module extracts phone calls details""" """This module extracts phone calls details"""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -23,10 +23,10 @@ CHROME_FAVICON_ROOT_PATHS = [
class ChromeFavicon(IOSExtraction): class ChromeFavicon(IOSExtraction):
"""This module extracts all Chrome favicon records.""" """This module extracts all Chrome favicon records."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -22,10 +22,10 @@ CHROME_HISTORY_ROOT_PATHS = [
class ChromeHistory(IOSExtraction): class ChromeHistory(IOSExtraction):
"""This module extracts all Chome visits.""" """This module extracts all Chome visits."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -18,10 +18,10 @@ CONTACTS_ROOT_PATHS = [
class Contacts(IOSExtraction): class Contacts(IOSExtraction):
"""This module extracts all contact details from the phone's address book.""" """This module extracts all contact details from the phone's address book."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):

View File

@ -21,10 +21,10 @@ FIREFOX_HISTORY_ROOT_PATHS = [
class FirefoxFavicon(IOSExtraction): class FirefoxFavicon(IOSExtraction):
"""This module extracts all Firefox favicon""" """This module extracts all Firefox favicon"""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -25,10 +25,10 @@ class FirefoxHistory(IOSExtraction):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -22,10 +22,10 @@ IDSTATUSCACHE_ROOT_PATHS = [
class IDStatusCache(IOSExtraction): class IDStatusCache(IOSExtraction):
"""Extracts Apple Authentication information from idstatuscache.plist""" """Extracts Apple Authentication information from idstatuscache.plist"""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -20,10 +20,10 @@ INTERACTIONC_ROOT_PATHS = [
class InteractionC(IOSExtraction): class InteractionC(IOSExtraction):
"""This module extracts data from InteractionC db.""" """This module extracts data from InteractionC db."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.timestamps = [ self.timestamps = [

View File

@ -21,10 +21,10 @@ LOCATIOND_ROOT_PATHS = [
class LocationdClients(IOSExtraction): class LocationdClients(IOSExtraction):
"""Extract information from apps who used geolocation.""" """Extract information from apps who used geolocation."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.timestamps = [ self.timestamps = [

View File

@ -20,10 +20,10 @@ class Datausage(NetBase):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def run(self): def run(self):

View File

@ -20,10 +20,10 @@ OSANALYTICS_ADDAILY_ROOT_PATHS = [
class OSAnalyticsADDaily(IOSExtraction): class OSAnalyticsADDaily(IOSExtraction):
"""Extract network usage information by process, from com.apple.osanalytics.addaily.plist""" """Extract network usage information by process, from com.apple.osanalytics.addaily.plist"""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -23,10 +23,10 @@ SAFARI_BROWSER_STATE_ROOT_PATHS = [
class SafariBrowserState(IOSExtraction): class SafariBrowserState(IOSExtraction):
"""This module extracts all Safari browser state records.""" """This module extracts all Safari browser state records."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self._session_history_count = 0 self._session_history_count = 0
@ -115,7 +115,7 @@ class SafariBrowserState(IOSExtraction):
"tab_visible_url": row[2], "tab_visible_url": row[2],
"last_viewed_timestamp": convert_timestamp_to_iso(convert_mactime_to_unix(row[3])), "last_viewed_timestamp": convert_timestamp_to_iso(convert_mactime_to_unix(row[3])),
"session_data": session_entries, "session_data": session_entries,
"safari_browser_state_db": os.path.relpath(db_path, self.base_folder), "safari_browser_state_db": os.path.relpath(db_path, self.target_path),
}) })
def run(self): def run(self):

View File

@ -25,10 +25,10 @@ class SafariHistory(IOSExtraction):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):
@ -111,7 +111,7 @@ class SafariHistory(IOSExtraction):
"isodate": convert_timestamp_to_iso(convert_mactime_to_unix(row[3])), "isodate": convert_timestamp_to_iso(convert_mactime_to_unix(row[3])),
"redirect_source": row[4], "redirect_source": row[4],
"redirect_destination": row[5], "redirect_destination": row[5],
"safari_history_db": os.path.relpath(history_path, self.base_folder), "safari_history_db": os.path.relpath(history_path, self.target_path),
}) })
cur.close() cur.close()

View File

@ -24,10 +24,10 @@ SHORTCUT_ROOT_PATHS = [
class Shortcuts(IOSExtraction): class Shortcuts(IOSExtraction):
"""This module extracts all info about SMS/iMessage attachments.""" """This module extracts all info about SMS/iMessage attachments."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -22,10 +22,10 @@ SMS_ROOT_PATHS = [
class SMS(IOSExtraction): class SMS(IOSExtraction):
"""This module extracts all SMS messages containing links.""" """This module extracts all SMS messages containing links."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -21,10 +21,10 @@ SMS_ROOT_PATHS = [
class SMSAttachments(IOSExtraction): class SMSAttachments(IOSExtraction):
"""This module extracts all info about SMS/iMessage attachments.""" """This module extracts all info about SMS/iMessage attachments."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -47,10 +47,10 @@ AUTH_REASONS = {
class TCC(IOSExtraction): class TCC(IOSExtraction):
"""This module extracts records from the TCC.db SQLite database.""" """This module extracts records from the TCC.db SQLite database."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -22,10 +22,10 @@ class WebkitResourceLoadStatistics(IOSExtraction):
"""This module extracts records from WebKit ResourceLoadStatistics observations.db.""" """This module extracts records from WebKit ResourceLoadStatistics observations.db."""
# TODO: Add serialize(). # TODO: Add serialize().
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} if not results else results self.results = {} if not results else results
@ -85,4 +85,4 @@ class WebkitResourceLoadStatistics(IOSExtraction):
self.log.info("Unable to search for WebKit observations.db: %s", e) self.log.info("Unable to search for WebKit observations.db: %s", e)
elif self.is_fs_dump: elif self.is_fs_dump:
for db_path in self._get_fs_files_from_patterns(WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS): for db_path in self._get_fs_files_from_patterns(WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS):
self._process_observations_db(db_path=db_path, key=os.path.relpath(db_path, self.base_folder)) self._process_observations_db(db_path=db_path, key=os.path.relpath(db_path, self.target_path))

View File

@ -29,10 +29,10 @@ class WebkitSessionResourceLog(IOSExtraction):
""" """
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
self.results = {} if not results else results self.results = {} if not results else results
@ -128,7 +128,7 @@ class WebkitSessionResourceLog(IOSExtraction):
elif self.is_fs_dump: elif self.is_fs_dump:
for log_path in self._get_fs_files_from_patterns(WEBKIT_SESSION_RESOURCE_LOG_ROOT_PATHS): for log_path in self._get_fs_files_from_patterns(WEBKIT_SESSION_RESOURCE_LOG_ROOT_PATHS):
self.log.info("Found Safari browsing session resource log at path: %s", log_path) self.log.info("Found Safari browsing session resource log at path: %s", log_path)
key = os.path.relpath(log_path, self.base_folder) key = os.path.relpath(log_path, self.target_path)
self.results[key] = self._extract_browsing_stats(log_path) self.results[key] = self._extract_browsing_stats(log_path)
self.log.info("Extracted records from %d Safari browsing session resource logs", self.log.info("Extracted records from %d Safari browsing session resource logs",

View File

@ -24,10 +24,10 @@ WHATSAPP_ROOT_PATHS = [
class Whatsapp(IOSExtraction): class Whatsapp(IOSExtraction):
"""This module extracts all WhatsApp messages containing links.""" """This module extracts all WhatsApp messages containing links."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def serialize(self, record): def serialize(self, record):

View File

@ -15,10 +15,10 @@ from .base import IOSExtraction
class NetBase(IOSExtraction): class NetBase(IOSExtraction):
"""This class provides a base for DataUsage and NetUsage extraction modules.""" """This class provides a base for DataUsage and NetUsage extraction modules."""
def __init__(self, file_path=None, base_folder=None, output_folder=None, def __init__(self, file_path=None, target_path=None, results_path=None,
fast_mode=False, log=None, results=[]): fast_mode=False, log=None, results=[]):
super().__init__(file_path=file_path, base_folder=base_folder, super().__init__(file_path=file_path, target_path=target_path,
output_folder=output_folder, fast_mode=fast_mode, results_path=results_path, fast_mode=fast_mode,
log=log, results=results) log=log, results=results)
def _extract_net_data(self): def _extract_net_data(self):
@ -124,7 +124,7 @@ class NetBase(IOSExtraction):
self.log.info("Extended search for suspicious processes ...") self.log.info("Extended search for suspicious processes ...")
files = [] files = []
for posix_path in Path(self.base_folder).rglob("*"): for posix_path in Path(self.target_path).rglob("*"):
try: try:
if not posix_path.is_file(): if not posix_path.is_file():
continue continue

View File

@ -48,7 +48,7 @@ max-line-length = 1000
ignore = ignore =
C901, C901,
E265, E265,
E127,
F401, F401,
E127,
W503, W503,
E226 E226

View File

@ -18,7 +18,7 @@ from ..utils import get_android_backup_folder
class TestBackupModule: class TestBackupModule:
def test_module_folder(self): def test_module_folder(self):
backup_path = get_android_backup_folder() backup_path = get_android_backup_folder()
mod = SMS(base_folder=backup_path, log=logging) mod = SMS(target_path=backup_path, log=logging)
files = [] files = []
for root, subdirs, subfiles in os.walk(os.path.abspath(backup_path)): for root, subdirs, subfiles in os.walk(os.path.abspath(backup_path)):
for fname in subfiles: for fname in subfiles:
@ -31,7 +31,7 @@ class TestBackupModule:
def test_module_file(self): def test_module_file(self):
fpath = os.path.join(get_android_backup_folder(), "backup.ab") fpath = os.path.join(get_android_backup_folder(), "backup.ab")
mod = SMS(base_folder=fpath, log=logging) mod = SMS(target_path=fpath, log=logging)
with open(fpath, "rb") as f: with open(fpath, "rb") as f:
data = f.read() data = f.read()
tardata = parse_backup_file(data) tardata = parse_backup_file(data)
@ -47,7 +47,7 @@ class TestBackupModule:
def test_module_file2(self): def test_module_file2(self):
fpath = os.path.join(get_android_backup_folder(), "backup2.ab") fpath = os.path.join(get_android_backup_folder(), "backup2.ab")
mod = SMS(base_folder=fpath, log=logging) mod = SMS(target_path=fpath, log=logging)
with open(fpath, "rb") as f: with open(fpath, "rb") as f:
data = f.read() data = f.read()
tardata = parse_backup_file(data, password="123456") tardata = parse_backup_file(data, password="123456")
@ -63,7 +63,7 @@ class TestBackupModule:
def test_module_file3(self): def test_module_file3(self):
fpath = os.path.join(get_android_backup_folder(), "backup3.ab") fpath = os.path.join(get_android_backup_folder(), "backup3.ab")
mod = SMS(base_folder=fpath, log=logging) mod = SMS(target_path=fpath, log=logging)
with open(fpath, "rb") as f: with open(fpath, "rb") as f:
data = f.read() data = f.read()
tardata = parse_backup_file(data) tardata = parse_backup_file(data)

View File

@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import hashlib import hashlib
import logging
from mvt.android.parsers.backup import parse_backup_file, parse_tar_for_sms from mvt.android.parsers.backup import parse_backup_file, parse_tar_for_sms

View File

@ -8,7 +8,6 @@ import os
from pathlib import Path from pathlib import Path
from mvt.android.modules.bugreport.appops import Appops from mvt.android.modules.bugreport.appops import Appops
from mvt.common.indicators import Indicators
from mvt.common.module import run_module from mvt.common.module import run_module
from ..utils import get_artifact_folder from ..utils import get_artifact_folder
@ -17,7 +16,7 @@ from ..utils import get_artifact_folder
class TestAppopsModule: class TestAppopsModule:
def test_appops_parsing(self): def test_appops_parsing(self):
fpath = os.path.join(get_artifact_folder(), "android_data/bugreport/") fpath = os.path.join(get_artifact_folder(), "android_data/bugreport/")
m = Appops(base_folder=fpath, log=logging, results=[]) m = Appops(target_path=fpath, log=logging, results=[])
folder_files = [] folder_files = []
parent_path = Path(fpath).absolute().as_posix() parent_path = Path(fpath).absolute().as_posix()
for root, subdirs, subfiles in os.walk(os.path.abspath(fpath)): for root, subdirs, subfiles in os.walk(os.path.abspath(fpath)):

View File

@ -3,9 +3,6 @@
# Use of this software is governed by the MVT License 1.1 that can be found at # Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import hashlib
import logging
from mvt.android.parsers.dumpsys import parse_dumpsys_appops from mvt.android.parsers.dumpsys import parse_dumpsys_appops
from ..utils import get_artifact from ..utils import get_artifact

View File

@ -13,7 +13,7 @@ from ..utils import get_ios_backup_folder
class TestBackupInfoModule: class TestBackupInfoModule:
def test_manifest(self): def test_manifest(self):
m = BackupInfo(base_folder=get_ios_backup_folder(), log=logging) m = BackupInfo(target_path=get_ios_backup_folder(), log=logging)
run_module(m) run_module(m)
assert m.results["Build Version"] == "18C66" assert m.results["Build Version"] == "18C66"
assert m.results["IMEI"] == "42" assert m.results["IMEI"] == "42"

View File

@ -14,14 +14,14 @@ from ..utils import get_ios_backup_folder
class TestDatausageModule: class TestDatausageModule:
def test_datausage(self): def test_datausage(self):
m = Datausage(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = Datausage(target_path=get_ios_backup_folder(), log=logging, results=[])
run_module(m) run_module(m)
assert len(m.results) == 42 assert len(m.results) == 42
assert len(m.timeline) == 60 assert len(m.timeline) == 60
assert len(m.detected) == 0 assert len(m.detected) == 0
def test_detection(self, indicator_file): def test_detection(self, indicator_file):
m = Datausage(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = Datausage(target_path=get_ios_backup_folder(), log=logging, results=[])
ind = Indicators(log=logging) ind = Indicators(log=logging)
ind.parse_stix2(indicator_file) ind.parse_stix2(indicator_file)
# Adds a file that exists in the manifest. # Adds a file that exists in the manifest.

View File

@ -14,14 +14,14 @@ from ..utils import get_ios_backup_folder
class TestManifestModule: class TestManifestModule:
def test_manifest(self): def test_manifest(self):
m = Manifest(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = Manifest(target_path=get_ios_backup_folder(), log=logging, results=[])
run_module(m) run_module(m)
assert len(m.results) == 3721 assert len(m.results) == 3721
assert len(m.timeline) == 5881 assert len(m.timeline) == 5881
assert len(m.detected) == 0 assert len(m.detected) == 0
def test_detection(self, indicator_file): def test_detection(self, indicator_file):
m = Manifest(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = Manifest(target_path=get_ios_backup_folder(), log=logging, results=[])
ind = Indicators(log=logging) ind = Indicators(log=logging)
ind.parse_stix2(indicator_file) ind.parse_stix2(indicator_file)
ind.ioc_collections[0]["file_names"].append("com.apple.CoreBrightness.plist") ind.ioc_collections[0]["file_names"].append("com.apple.CoreBrightness.plist")

View File

@ -14,7 +14,7 @@ from ..utils import get_ios_backup_folder
class TestSafariBrowserStateModule: class TestSafariBrowserStateModule:
def test_parsing(self): def test_parsing(self):
m = SafariBrowserState(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = SafariBrowserState(target_path=get_ios_backup_folder(), log=logging, results=[])
m.is_backup = True m.is_backup = True
run_module(m) run_module(m)
assert m.file_path is not None assert m.file_path is not None
@ -23,7 +23,7 @@ class TestSafariBrowserStateModule:
assert len(m.detected) == 0 assert len(m.detected) == 0
def test_detection(self, indicator_file): def test_detection(self, indicator_file):
m = SafariBrowserState(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = SafariBrowserState(target_path=get_ios_backup_folder(), log=logging, results=[])
m.is_backup = True m.is_backup = True
ind = Indicators(log=logging) ind = Indicators(log=logging)
ind.parse_stix2(indicator_file) ind.parse_stix2(indicator_file)

View File

@ -14,14 +14,14 @@ from ..utils import get_ios_backup_folder
class TestSMSModule: class TestSMSModule:
def test_sms(self): def test_sms(self):
m = SMS(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = SMS(target_path=get_ios_backup_folder(), log=logging, results=[])
run_module(m) run_module(m)
assert len(m.results) == 1 assert len(m.results) == 1
assert len(m.timeline) == 1 assert len(m.timeline) == 1
assert len(m.detected) == 0 assert len(m.detected) == 0
def test_detection(self, indicator_file): def test_detection(self, indicator_file):
m = SMS(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = SMS(target_path=get_ios_backup_folder(), log=logging, results=[])
ind = Indicators(log=logging) ind = Indicators(log=logging)
ind.parse_stix2(indicator_file) ind.parse_stix2(indicator_file)
# Adds a file that exists in the manifest. # Adds a file that exists in the manifest.

View File

@ -14,7 +14,7 @@ from ..utils import get_ios_backup_folder
class TestTCCtModule: class TestTCCtModule:
def test_tcc(self): def test_tcc(self):
m = TCC(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = TCC(target_path=get_ios_backup_folder(), log=logging, results=[])
run_module(m) run_module(m)
assert len(m.results) == 11 assert len(m.results) == 11
assert len(m.timeline) == 11 assert len(m.timeline) == 11
@ -24,7 +24,7 @@ class TestTCCtModule:
assert m.results[0]["auth_value"] == "allowed" assert m.results[0]["auth_value"] == "allowed"
def test_tcc_detection(self, indicator_file): def test_tcc_detection(self, indicator_file):
m = TCC(base_folder=get_ios_backup_folder(), log=logging, results=[]) m = TCC(target_path=get_ios_backup_folder(), log=logging, results=[])
ind = Indicators(log=logging) ind = Indicators(log=logging)
ind.parse_stix2(indicator_file) ind.parse_stix2(indicator_file)
m.indicators = ind m.indicators = ind