diff --git a/mvt/android/modules/bugreport/__init__.py b/mvt/android/modules/bugreport/__init__.py index cea3fc6..d7f3943 100644 --- a/mvt/android/modules/bugreport/__init__.py +++ b/mvt/android/modules/bugreport/__init__.py @@ -8,7 +8,8 @@ from .activities import Activities from .battery_daily import BatteryDaily from .battery_history import BatteryHistory from .dbinfo import DBInfo +from .packages import Packages from .receivers import Receivers BUGREPORT_MODULES = [Accessibility, Activities, BatteryDaily, BatteryHistory, - DBInfo, Receivers] + DBInfo, Packages, Receivers] diff --git a/mvt/android/modules/bugreport/accessibility.py b/mvt/android/modules/bugreport/accessibility.py index 909e896..e0a96d0 100644 --- a/mvt/android/modules/bugreport/accessibility.py +++ b/mvt/android/modules/bugreport/accessibility.py @@ -41,8 +41,8 @@ class Accessibility(BugReportModule): if not content: return - in_accessibility = False lines = [] + in_accessibility = False for line in content.decode().split("\n"): if line.strip() == "DUMP OF SERVICE accessibility:": in_accessibility = True diff --git a/mvt/android/modules/bugreport/activities.py b/mvt/android/modules/bugreport/activities.py index 57938e1..e092c65 100644 --- a/mvt/android/modules/bugreport/activities.py +++ b/mvt/android/modules/bugreport/activities.py @@ -44,14 +44,14 @@ class Activities(BugReportModule): if not content: return - in_activities = False lines = [] + in_package = False for line in content.decode().split("\n"): if line.strip() == "DUMP OF SERVICE package:": - in_activities = True + in_package = True continue - if not in_activities: + if not in_package: continue if line.strip() == "------------------------------------------------------------------------------": diff --git a/mvt/android/modules/bugreport/battery_daily.py b/mvt/android/modules/bugreport/battery_daily.py index 9c5d5ab..c330cb2 100644 --- a/mvt/android/modules/bugreport/battery_daily.py +++ b/mvt/android/modules/bugreport/battery_daily.py @@ -49,9 +49,9 @@ class BatteryDaily(BugReportModule): if not content: return + lines = [] in_batterystats = False in_daily = False - lines = [] for line in content.decode().split("\n"): if line.strip() == "DUMP OF SERVICE batterystats:": in_batterystats = True diff --git a/mvt/android/modules/bugreport/battery_history.py b/mvt/android/modules/bugreport/battery_history.py index 04609c3..c0e9697 100644 --- a/mvt/android/modules/bugreport/battery_history.py +++ b/mvt/android/modules/bugreport/battery_history.py @@ -42,9 +42,9 @@ class BatteryHistory(BugReportModule): if not content: return + lines = [] in_batterystats = False in_history = False - lines = [] for line in content.decode().split("\n"): if line.strip() == "********** Print latest newbatterystats **********": in_batterystats = True diff --git a/mvt/android/modules/bugreport/packages.py b/mvt/android/modules/bugreport/packages.py new file mode 100644 index 0000000..7c10942 --- /dev/null +++ b/mvt/android/modules/bugreport/packages.py @@ -0,0 +1,117 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2022 The MVT Project Authors. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging +import re + +from mvt.android.modules.adb.packages import Packages as PCK +from .base import BugReportModule + +log = logging.getLogger(__name__) + + +class Packages(BugReportModule): + """This module extracts details on receivers for risky activities.""" + + def __init__(self, file_path=None, base_folder=None, output_folder=None, + serial=None, fast_mode=False, log=None, results=[]): + super().__init__(file_path=file_path, base_folder=base_folder, + output_folder=output_folder, fast_mode=fast_mode, + log=log, results=results) + + def serialize(self, record): + records = [] + + timestamps = [ + {"event": "package_install", "timestamp": record["timestamp"]}, + {"event": "package_first_install", "timestamp": record["first_install_time"]}, + {"event": "package_last_update", "timestamp": record["last_update_time"]}, + ] + + for ts in timestamps: + records.append({ + "timestamp": ts["timestamp"], + "module": self.__class__.__name__, + "event": ts["event"], + "data": f"Install or update of package {record['package_name']}", + }) + + return records + + def check_indicators(self): + if not self.indicators: + return + + for result in self.results: + ioc = self.indicators.check_app_id(result["package_name"]) + if ioc: + result["matched_indicator"] = ioc + self.detected.append(result) + continue + + @staticmethod + def parse_packages_list(output): + pkg_rxp = re.compile(r" Package \[(.+?)\].*") + + results = [] + package_name = None + package = {} + lines = [] + for line in output.split("\n"): + if line.startswith(" Package ["): + if len(lines) > 0: + details = PCK.parse_package_for_details("\n".join(lines)) + package.update(details) + results.append(package) + package = {} + + matches = pkg_rxp.findall(line) + if not matches: + continue + + package_name = matches[0] + package["package_name"] = package_name + continue + + if not package_name: + continue + + lines.append(line) + + return results + + def run(self): + dumpstate_files = self._get_files_by_pattern("dumpstate-*") + if not dumpstate_files: + return + + content = self._get_file_content(dumpstate_files[0]) + if not content: + return + + in_package = False + in_packages_list = False + lines = [] + for line in content.decode().split("\n"): + if line.strip() == "DUMP OF SERVICE package:": + in_package = True + continue + + if not in_package: + continue + + if line.strip() == "Packages:": + in_packages_list = True + continue + + if not in_packages_list: + continue + + if line.strip() == "": + break + + lines.append(line) + + self.results = self.parse_packages_list("\n".join(lines))