From 49e34f62995e6f6fb02a4dc83ae41172e973f579 Mon Sep 17 00:00:00 2001 From: Nex Date: Sat, 29 Jan 2022 03:50:33 +0100 Subject: [PATCH] Better parsing of dumpsys package and added parsing of Activities too --- mvt/android/modules/adb/__init__.py | 5 +- mvt/android/modules/adb/dumpsys_activities.py | 91 ++++++++++++++++++ mvt/android/modules/adb/dumpsys_receivers.py | 94 ++++++++++--------- 3 files changed, 146 insertions(+), 44 deletions(-) create mode 100644 mvt/android/modules/adb/dumpsys_activities.py diff --git a/mvt/android/modules/adb/__init__.py b/mvt/android/modules/adb/__init__.py index 7f94fcd..aad18b4 100644 --- a/mvt/android/modules/adb/__init__.py +++ b/mvt/android/modules/adb/__init__.py @@ -5,6 +5,7 @@ from .chrome_history import ChromeHistory from .dumpsys_accessibility import DumpsysAccessibility +from .dumpsys_activities import DumpsysActivities from .dumpsys_batterystats import DumpsysBatterystats from .dumpsys_full import DumpsysFull from .dumpsys_packages import DumpsysPackages @@ -22,5 +23,5 @@ from .whatsapp import Whatsapp ADB_MODULES = [ChromeHistory, SMS, Whatsapp, Processes, Getprop, Settings, DumpsysAccessibility, DumpsysBatterystats, DumpsysProcstats, - DumpsysPackages, DumpsysReceivers, DumpsysFull, - Packages, RootBinaries, Logcat, Files] + DumpsysPackages, DumpsysReceivers, DumpsysActivities, + DumpsysFull, Packages, RootBinaries, Logcat, Files] diff --git a/mvt/android/modules/adb/dumpsys_activities.py b/mvt/android/modules/adb/dumpsys_activities.py new file mode 100644 index 0000000..14c092a --- /dev/null +++ b/mvt/android/modules/adb/dumpsys_activities.py @@ -0,0 +1,91 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021 The MVT Project Authors. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import logging + +from .base import AndroidExtraction + +log = logging.getLogger(__name__) + + +class DumpsysActivities(AndroidExtraction): + """This module extracts details on receivers for risky activities.""" + + def __init__(self, file_path=None, base_folder=None, output_folder=None, + 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) + + self.results = results if results else {} + + def parse_activity_resolver_table(self, data): + """Parse output of dumpsys package. + + :param data: Output of dumpsys package command. + :type data: str + + """ + + in_activity_resolver_table = False + in_non_data_actions = False + intent = None + for line in data: + if line.startswith("Activity Resolver Table:"): + in_activity_resolver_table = True + continue + + if not in_activity_resolver_table: + continue + + if line.startswith(" Non-Data Actions:"): + in_non_data_actions = True + continue + + if not in_non_data_actions: + continue + + # If we hit an empty line, the Non-Data Actions section should be + # finished. + if line.strip() == "": + break + + # We detect the action name. + if line.startswith(" " * 6) and not line.startswith(" " * 8) and ":" in line: + intent = line.strip().replace(":", "") + self.results[intent] = [] + continue + + # If we are not in an intent block yet, skip. + if not intent: + continue + + # If we are in a block but the line does not start with 8 spaces + # it means the block ended a new one started, so we reset and + # continue. + if not line.startswith(" " * 8): + intent = None + continue + + # If we got this far, we are processing receivers for the + # activities we are interested in. + activity = line.strip().split(" ")[1] + package_name = activity.split("/")[0] + + self.results[intent].append({ + "package_name": package_name, + "activity": activity, + }) + + def run(self): + self._adb_connect() + + output = self._adb_command("dumpsys package") + if not output: + return + + self.parse_activity_resolver_table(output.split("\n")) + + self._adb_disconnect() diff --git a/mvt/android/modules/adb/dumpsys_receivers.py b/mvt/android/modules/adb/dumpsys_receivers.py index 8b2186b..5d35ce7 100644 --- a/mvt/android/modules/adb/dumpsys_receivers.py +++ b/mvt/android/modules/adb/dumpsys_receivers.py @@ -25,70 +25,80 @@ class DumpsysReceivers(AndroidExtraction): output_folder=output_folder, fast_mode=fast_mode, log=log, results=results) - def check_indicators(self): - for result in self.results: - if result["activity"] == INTENT_NEW_OUTGOING_SMS: - self.log.info("Found a receiver to intercept outgoing SMS messages: \"%s\"", - result["receiver"]) - elif result["activity"] == INTENT_SMS_RECEIVED: - self.log.info("Found a receiver to intercept incoming SMS messages: \"%s\"", - result["receiver"]) - elif result["activity"] == INTENT_DATA_SMS_RECEIVED: - self.log.info("Found a receiver to intercept incoming data SMS message: \"%s\"", - result["receiver"]) - elif result["activity"] == INTENT_PHONE_STATE: - self.log.info("Found a receiver monitoring telephony state/incoming calls: \"%s\"", - result["receiver"]) - elif result["activity"] == INTENT_NEW_OUTGOING_CALL: - self.log.info("Found a receiver monitoring outgoing calls: \"%s\"", - result["receiver"]) + self.results = results if results else {} - def parse_dumpsys_package(self, data): + def check_indicators(self): + for intent, receivers in self.results.items(): + for receiver in receivers: + if intent == INTENT_NEW_OUTGOING_SMS: + self.log.info("Found a receiver to intercept outgoing SMS messages: \"%s\"", + receiver["receiver"]) + elif intent == INTENT_SMS_RECEIVED: + self.log.info("Found a receiver to intercept incoming SMS messages: \"%s\"", + receiver["receiver"]) + elif intent == INTENT_DATA_SMS_RECEIVED: + self.log.info("Found a receiver to intercept incoming data SMS message: \"%s\"", + receiver["receiver"]) + elif intent == INTENT_PHONE_STATE: + self.log.info("Found a receiver monitoring telephony state/incoming calls: \"%s\"", + receiver["receiver"]) + elif intent == INTENT_NEW_OUTGOING_CALL: + self.log.info("Found a receiver monitoring outgoing calls: \"%s\"", + receiver["receiver"]) + + def parse_receiver_resolver_table(self, data): """Parse output of dumpsys package. :param data: Output of dumpsys package command. :type data: str """ - activity = None + in_receiver_resolver_table = False + in_non_data_actions = False + intent = None for line in data: - # Find activity block markers. - if line.strip().startswith(INTENT_NEW_OUTGOING_SMS): - activity = INTENT_NEW_OUTGOING_SMS - continue - elif line.strip().startswith(INTENT_SMS_RECEIVED): - activity = INTENT_SMS_RECEIVED - continue - elif line.strip().startswith(INTENT_PHONE_STATE): - activity = INTENT_PHONE_STATE - continue - elif line.strip().startswith(INTENT_DATA_SMS_RECEIVED): - activity = INTENT_DATA_SMS_RECEIVED - continue - elif line.strip().startswith(INTENT_NEW_OUTGOING_CALL): - activity = INTENT_NEW_OUTGOING_CALL + if line.startswith("Receiver Resolver Table:"): + in_receiver_resolver_table = True continue - # If we are not in an activity block yet, skip. - if not activity: + if not in_receiver_resolver_table: + continue + + if line.startswith(" Non-Data Actions:"): + in_non_data_actions = True + continue + + if not in_non_data_actions: + continue + + # If we hit an empty line, the Non-Data Actions section should be + # finished. + if line.strip() == "": + break + + # We detect the action name. + if line.startswith(" " * 6) and not line.startswith(" " * 8) and ":" in line: + intent = line.strip().replace(":", "") + self.results[intent] = [] + continue + + # If we are not in an intent block yet, skip. + if not intent: continue # If we are in a block but the line does not start with 8 spaces # it means the block ended a new one started, so we reset and # continue. if not line.startswith(" " * 8): - activity = None + intent = None continue # If we got this far, we are processing receivers for the # activities we are interested in. receiver = line.strip().split(" ")[1] package_name = receiver.split("/")[0] - if package_name == "com.google.android.gms": - continue - self.results.append({ - "activity": activity, + self.results[intent].append({ "package_name": package_name, "receiver": receiver, }) @@ -100,6 +110,6 @@ class DumpsysReceivers(AndroidExtraction): if not output: return - self.parse_dumpsys_package(output.split("\n")) + self.parse_receiver_resolver_table(output.split("\n")) self._adb_disconnect()