diff --git a/src/mvt/android/artifacts/dumpsys_platform_compat.py b/src/mvt/android/artifacts/dumpsys_platform_compat.py index c01fbfd..08cb46e 100644 --- a/src/mvt/android/artifacts/dumpsys_platform_compat.py +++ b/src/mvt/android/artifacts/dumpsys_platform_compat.py @@ -3,6 +3,8 @@ # Use of this software is governed by the MVT License 1.1 that can be found at # https://license.mvt.re/1.1/ +import re + from .artifact import AndroidArtifact @@ -25,19 +27,37 @@ class DumpsysPlatformCompatArtifact(AndroidArtifact): def parse(self, data: str) -> None: for line in data.splitlines(): - if not line.startswith("ChangeId(168419799; name=DOWNSCALED;"): + match = re.match(r"ChangeId\((\d+);\s*(.*)\)$", line.strip()) + if not match or "rawOverrides={" not in line: continue - - if line.strip() == "": - break - - # Look for rawOverrides field - if "rawOverrides={" in line: - # Extract the content inside the braces for rawOverrides - overrides_field = line.split("rawOverrides={", 1)[1].split("};", 1)[0] - - for entry in overrides_field.split(", "): - # Extract app name - uninstall_app = entry.split("=")[0].strip() - - self.results.append({"package_name": uninstall_app}) + body = match.group(2) + name_match = re.search(r"(?:^|;\s*)name=([^;]+)", body) + state = ( + "enabled" + if re.search(r"(?:^|;\s*)enabled(?:;|$)", body) + else "disabled" + ) + overridable = bool(re.search(r"(?:^|;\s*)overridable(?:;|$)", body)) + overrides_field = body.split("rawOverrides={", 1)[1].split("}", 1)[0] + for entry in overrides_field.split(","): + package_name, separator, raw_value = entry.strip().partition("=") + if not separator: + continue + value: bool | int | str + if raw_value in ("true", "false"): + value = raw_value == "true" + else: + try: + value = int(raw_value) + except ValueError: + value = raw_value + self.results.append( + { + "change_id": int(match.group(1)), + "change_name": name_match.group(1) if name_match else None, + "change_state": state, + "overridable": overridable, + "package_name": package_name, + "override_value": value, + } + ) diff --git a/src/mvt/android/modules/bugreport/dumpsys_platform_compat.py b/src/mvt/android/modules/bugreport/dumpsys_platform_compat.py index 968bc25..dd06b40 100644 --- a/src/mvt/android/modules/bugreport/dumpsys_platform_compat.py +++ b/src/mvt/android/modules/bugreport/dumpsys_platform_compat.py @@ -13,7 +13,7 @@ from mvt.common.module_types import ModuleResults class DumpsysPlatformCompat(DumpsysPlatformCompatArtifact, BugReportModule): - """This module extracts details on uninstalled apps.""" + """This module extracts raw per-package compatibility overrides.""" def __init__( self, @@ -48,4 +48,4 @@ class DumpsysPlatformCompat(DumpsysPlatformCompatArtifact, BugReportModule): ) self.parse(content) - self.log.info("Found %d uninstalled apps", len(self.results)) + self.log.info("Found %d package compatibility overrides", len(self.results)) diff --git a/tests/android/test_artifact_dumpsys_platform_compat.py b/tests/android/test_artifact_dumpsys_platform_compat.py index c8c59b3..c202645 100644 --- a/tests/android/test_artifact_dumpsys_platform_compat.py +++ b/tests/android/test_artifact_dumpsys_platform_compat.py @@ -22,6 +22,9 @@ class TestDumpsysPlatformCompatArtifact: assert len(dbi.results) == 2 assert dbi.results[0]["package_name"] == "org.torproject.torbrowser" assert dbi.results[1]["package_name"] == "org.article19.circulo.next" + assert dbi.results[0]["change_id"] == 168419799 + assert dbi.results[0]["change_name"] == "DOWNSCALED" + assert dbi.results[0]["override_value"] is False def test_ioc_check(self, indicator_file): dbi = DumpsysPlatformCompatArtifact()