mirror of
https://github.com/mvt-project/mvt.git
synced 2026-08-28 13:50:24 +02:00
Merge pull request #587 from mvt-project/feature/uninstalled-apps
Add a module to parse uninstalled apps from dumpsys data
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT Authors.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
|
from .artifact import AndroidArtifact
|
||||||
|
|
||||||
|
|
||||||
|
class DumpsysPlatformCompatArtifact(AndroidArtifact):
|
||||||
|
"""
|
||||||
|
Parser for uninstalled apps listed in platform_compat section.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def check_indicators(self) -> None:
|
||||||
|
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
|
||||||
|
|
||||||
|
def parse(self, data: str) -> None:
|
||||||
|
for line in data.splitlines():
|
||||||
|
if not line.startswith("ChangeId(168419799; name=DOWNSCALED;"):
|
||||||
|
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})
|
||||||
@@ -14,6 +14,7 @@ from .dumpsys_receivers import DumpsysReceivers
|
|||||||
from .dumpsys_adb import DumpsysADBState
|
from .dumpsys_adb import DumpsysADBState
|
||||||
from .getprop import Getprop
|
from .getprop import Getprop
|
||||||
from .packages import Packages
|
from .packages import Packages
|
||||||
|
from .dumpsys_platform_compat import DumpsysPlatformCompat
|
||||||
from .processes import Processes
|
from .processes import Processes
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
from .sms import SMS
|
from .sms import SMS
|
||||||
@@ -29,6 +30,7 @@ ANDROIDQF_MODULES = [
|
|||||||
DumpsysBatteryHistory,
|
DumpsysBatteryHistory,
|
||||||
DumpsysADBState,
|
DumpsysADBState,
|
||||||
Packages,
|
Packages,
|
||||||
|
DumpsysPlatformCompat,
|
||||||
Processes,
|
Processes,
|
||||||
Getprop,
|
Getprop,
|
||||||
Settings,
|
Settings,
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT 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 typing import Optional
|
||||||
|
|
||||||
|
from mvt.android.artifacts.dumpsys_platform_compat import DumpsysPlatformCompatArtifact
|
||||||
|
|
||||||
|
from .base import AndroidQFModule
|
||||||
|
|
||||||
|
|
||||||
|
class DumpsysPlatformCompat(DumpsysPlatformCompatArtifact, AndroidQFModule):
|
||||||
|
"""This module extracts details on uninstalled apps."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file_path: Optional[str] = None,
|
||||||
|
target_path: Optional[str] = None,
|
||||||
|
results_path: Optional[str] = None,
|
||||||
|
module_options: Optional[dict] = None,
|
||||||
|
log: logging.Logger = logging.getLogger(__name__),
|
||||||
|
results: Optional[list] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
file_path=file_path,
|
||||||
|
target_path=target_path,
|
||||||
|
results_path=results_path,
|
||||||
|
module_options=module_options,
|
||||||
|
log=log,
|
||||||
|
results=results,
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
dumpsys_file = self._get_files_by_pattern("*/dumpsys.txt")
|
||||||
|
if not dumpsys_file:
|
||||||
|
return
|
||||||
|
|
||||||
|
data = self._get_file_content(dumpsys_file[0]).decode("utf-8", errors="replace")
|
||||||
|
content = self.extract_dumpsys_section(data, "DUMP OF SERVICE platform_compat:")
|
||||||
|
self.parse(content)
|
||||||
|
|
||||||
|
self.log.info("Found %d uninstalled apps", len(self.results))
|
||||||
@@ -11,6 +11,7 @@ from .battery_history import BatteryHistory
|
|||||||
from .dbinfo import DBInfo
|
from .dbinfo import DBInfo
|
||||||
from .getprop import Getprop
|
from .getprop import Getprop
|
||||||
from .packages import Packages
|
from .packages import Packages
|
||||||
|
from .platform_compat import PlatformCompat
|
||||||
from .receivers import Receivers
|
from .receivers import Receivers
|
||||||
from .adb_state import DumpsysADBState
|
from .adb_state import DumpsysADBState
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ BUGREPORT_MODULES = [
|
|||||||
DBInfo,
|
DBInfo,
|
||||||
Getprop,
|
Getprop,
|
||||||
Packages,
|
Packages,
|
||||||
|
PlatformCompat,
|
||||||
Receivers,
|
Receivers,
|
||||||
DumpsysADBState,
|
DumpsysADBState,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT 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 typing import Optional
|
||||||
|
|
||||||
|
from mvt.android.artifacts.dumpsys_platform_compat import DumpsysPlatformCompatArtifact
|
||||||
|
|
||||||
|
from mvt.android.modules.bugreport.base import BugReportModule
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformCompat(DumpsysPlatformCompatArtifact, BugReportModule):
|
||||||
|
"""This module extracts details on uninstalled apps."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file_path: Optional[str] = None,
|
||||||
|
target_path: Optional[str] = None,
|
||||||
|
results_path: Optional[str] = None,
|
||||||
|
module_options: Optional[dict] = None,
|
||||||
|
log: logging.Logger = logging.getLogger(__name__),
|
||||||
|
results: Optional[list] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
file_path=file_path,
|
||||||
|
target_path=target_path,
|
||||||
|
results_path=results_path,
|
||||||
|
module_options=module_options,
|
||||||
|
log=log,
|
||||||
|
results=results,
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
data = self._get_dumpstate_file()
|
||||||
|
if not data:
|
||||||
|
self.log.error(
|
||||||
|
"Unable to find dumpstate file. "
|
||||||
|
"Did you provide a valid bug report archive?"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
data = data.decode("utf-8", errors="replace")
|
||||||
|
content = self.extract_dumpsys_section(data, "DUMP OF SERVICE platform_compat:")
|
||||||
|
self.parse(content)
|
||||||
|
|
||||||
|
self.log.info("Found %d uninstalled apps", len(self.results))
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT 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 mvt.android.artifacts.dumpsys_platform_compat import DumpsysPlatformCompatArtifact
|
||||||
|
from mvt.common.indicators import Indicators
|
||||||
|
|
||||||
|
from ..utils import get_artifact
|
||||||
|
|
||||||
|
|
||||||
|
class TestDumpsysPlatformCompatArtifact:
|
||||||
|
def test_parsing(self):
|
||||||
|
dbi = DumpsysPlatformCompatArtifact()
|
||||||
|
file = get_artifact("android_data/dumpsys_platform_compat.txt")
|
||||||
|
with open(file) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
assert len(dbi.results) == 0
|
||||||
|
dbi.parse(data)
|
||||||
|
assert len(dbi.results) == 2
|
||||||
|
assert dbi.results[0]["package_name"] == "org.torproject.torbrowser"
|
||||||
|
assert dbi.results[1]["package_name"] == "org.article19.circulo.next"
|
||||||
|
|
||||||
|
def test_ioc_check(self, indicator_file):
|
||||||
|
dbi = DumpsysPlatformCompatArtifact()
|
||||||
|
file = get_artifact("android_data/dumpsys_platform_compat.txt")
|
||||||
|
with open(file) as f:
|
||||||
|
data = f.read()
|
||||||
|
dbi.parse(data)
|
||||||
|
|
||||||
|
ind = Indicators(log=logging.getLogger())
|
||||||
|
ind.parse_stix2(indicator_file)
|
||||||
|
ind.ioc_collections[0]["app_ids"].append("org.torproject.torbrowser")
|
||||||
|
ind.ioc_collections[0]["app_ids"].append("org.article19.circulo.next")
|
||||||
|
dbi.indicators = ind
|
||||||
|
assert len(dbi.detected) == 0
|
||||||
|
dbi.check_indicators()
|
||||||
|
assert len(dbi.detected) == 2
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT Authors.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from mvt.android.modules.androidqf.dumpsys_platform_compat import DumpsysPlatformCompat
|
||||||
|
from mvt.common.module import run_module
|
||||||
|
|
||||||
|
from ..utils import get_android_androidqf, list_files
|
||||||
|
|
||||||
|
|
||||||
|
class TestDumpsysPlatformCompatModule:
|
||||||
|
def test_parsing(self):
|
||||||
|
data_path = get_android_androidqf()
|
||||||
|
m = DumpsysPlatformCompat(target_path=data_path)
|
||||||
|
files = list_files(data_path)
|
||||||
|
parent_path = Path(data_path).absolute().parent.as_posix()
|
||||||
|
m.from_folder(parent_path, files)
|
||||||
|
run_module(m)
|
||||||
|
assert len(m.results) == 2
|
||||||
|
assert len(m.detected) == 0
|
||||||
@@ -246,6 +246,23 @@ Packages:
|
|||||||
com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivity
|
com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivity
|
||||||
com.instagram.share.handleractivity.ClipsShareHandlerActivity
|
com.instagram.share.handleractivity.ClipsShareHandlerActivity
|
||||||
com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivityInterop
|
com.instagram.direct.share.handler.DirectMultipleExternalMediaShareActivityInterop
|
||||||
|
--------- 0.053s was the duration of dumpsys appops, ending at: 2022-03-29 23:14:27
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
DUMP OF SERVICE platform_compat:
|
||||||
|
ChangeId(180326845; name=OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; disabled; overridable)
|
||||||
|
ChangeId(189969744; name=DOWNSCALE_65; disabled; overridable)
|
||||||
|
ChangeId(183372781; name=ENABLE_RAW_SYSTEM_GALLERY_ACCESS; enableSinceTargetSdk=30)
|
||||||
|
ChangeId(150939131; name=ADD_CONTENT_OBSERVER_FLAGS; enableSinceTargetSdk=30)
|
||||||
|
ChangeId(226439802; name=SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; disabled)
|
||||||
|
ChangeId(270674727; name=ENABLE_STRICT_FORMATTER_VALIDATION; enableSinceTargetSdk=35)
|
||||||
|
ChangeId(183155436; name=ALWAYS_USE_CONTEXT_USER; enableSinceTargetSdk=33)
|
||||||
|
ChangeId(303742236; name=ROLE_MANAGER_USER_HANDLE_AWARE; enableSinceTargetSdk=35)
|
||||||
|
ChangeId(203800354; name=MEDIA_CONTROL_SESSION_ACTIONS; enableSinceTargetSdk=33)
|
||||||
|
ChangeId(144027538; name=BLOCK_GPS_STATUS_USAGE; enableSinceTargetSdk=31)
|
||||||
|
ChangeId(189969749; name=DOWNSCALE_35; disabled; overridable)
|
||||||
|
ChangeId(143539591; name=SELINUX_LATEST_CHANGES; disabled)
|
||||||
|
ChangeId(247079863; name=DISALLOW_INVALID_GROUP_REFERENCE; enableSinceTargetSdk=34)
|
||||||
|
ChangeId(174227820; name=FORCE_DISABLE_HEVC_SUPPORT; disabled)
|
||||||
|
ChangeId(168419799; name=DOWNSCALED; disabled; packageOverrides={com.google.android.apps.tachyon=false, org.torproject.torbrowser=false}; rawOverrides={org.torproject.torbrowser=false, org.article19.circulo.next=false}; overridable)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
DUMP OF SERVICE platform_compat:
|
||||||
|
ChangeId(180326845; name=OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; disabled; overridable)
|
||||||
|
ChangeId(189969744; name=DOWNSCALE_65; disabled; overridable)
|
||||||
|
ChangeId(183372781; name=ENABLE_RAW_SYSTEM_GALLERY_ACCESS; enableSinceTargetSdk=30)
|
||||||
|
ChangeId(150939131; name=ADD_CONTENT_OBSERVER_FLAGS; enableSinceTargetSdk=30)
|
||||||
|
ChangeId(226439802; name=SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; disabled)
|
||||||
|
ChangeId(270674727; name=ENABLE_STRICT_FORMATTER_VALIDATION; enableSinceTargetSdk=35)
|
||||||
|
ChangeId(183155436; name=ALWAYS_USE_CONTEXT_USER; enableSinceTargetSdk=33)
|
||||||
|
ChangeId(303742236; name=ROLE_MANAGER_USER_HANDLE_AWARE; enableSinceTargetSdk=35)
|
||||||
|
ChangeId(203800354; name=MEDIA_CONTROL_SESSION_ACTIONS; enableSinceTargetSdk=33)
|
||||||
|
ChangeId(144027538; name=BLOCK_GPS_STATUS_USAGE; enableSinceTargetSdk=31)
|
||||||
|
ChangeId(189969749; name=DOWNSCALE_35; disabled; overridable)
|
||||||
|
ChangeId(143539591; name=SELINUX_LATEST_CHANGES; disabled)
|
||||||
|
ChangeId(247079863; name=DISALLOW_INVALID_GROUP_REFERENCE; enableSinceTargetSdk=34)
|
||||||
|
ChangeId(174227820; name=FORCE_DISABLE_HEVC_SUPPORT; disabled)
|
||||||
|
ChangeId(168419799; name=DOWNSCALED; disabled; packageOverrides={com.google.android.apps.tachyon=false, org.torproject.torbrowser=false}; rawOverrides={org.torproject.torbrowser=false, org.article19.circulo.next=false}; overridable)
|
||||||
@@ -379,4 +379,22 @@ Daily stats:
|
|||||||
Update com.google.android.projection.gearhead vers=99632623
|
Update com.google.android.projection.gearhead vers=99632623
|
||||||
Update com.google.android.projection.gearhead vers=99632623
|
Update com.google.android.projection.gearhead vers=99632623
|
||||||
Update com.google.android.projection.gearhead vers=99632623
|
Update com.google.android.projection.gearhead vers=99632623
|
||||||
|
--------- 0.053s was the duration of dumpsys batterystats, ending at: 2024-03-21 11:07:22
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
DUMP OF SERVICE platform_compat:
|
||||||
|
ChangeId(180326845; name=OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; disabled; overridable)
|
||||||
|
ChangeId(189969744; name=DOWNSCALE_65; disabled; overridable)
|
||||||
|
ChangeId(183372781; name=ENABLE_RAW_SYSTEM_GALLERY_ACCESS; enableSinceTargetSdk=30)
|
||||||
|
ChangeId(150939131; name=ADD_CONTENT_OBSERVER_FLAGS; enableSinceTargetSdk=30)
|
||||||
|
ChangeId(226439802; name=SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; disabled)
|
||||||
|
ChangeId(270674727; name=ENABLE_STRICT_FORMATTER_VALIDATION; enableSinceTargetSdk=35)
|
||||||
|
ChangeId(183155436; name=ALWAYS_USE_CONTEXT_USER; enableSinceTargetSdk=33)
|
||||||
|
ChangeId(303742236; name=ROLE_MANAGER_USER_HANDLE_AWARE; enableSinceTargetSdk=35)
|
||||||
|
ChangeId(203800354; name=MEDIA_CONTROL_SESSION_ACTIONS; enableSinceTargetSdk=33)
|
||||||
|
ChangeId(144027538; name=BLOCK_GPS_STATUS_USAGE; enableSinceTargetSdk=31)
|
||||||
|
ChangeId(189969749; name=DOWNSCALE_35; disabled; overridable)
|
||||||
|
ChangeId(143539591; name=SELINUX_LATEST_CHANGES; disabled)
|
||||||
|
ChangeId(247079863; name=DISALLOW_INVALID_GROUP_REFERENCE; enableSinceTargetSdk=34)
|
||||||
|
ChangeId(174227820; name=FORCE_DISABLE_HEVC_SUPPORT; disabled)
|
||||||
|
ChangeId(168419799; name=DOWNSCALED; disabled; packageOverrides={com.google.android.apps.tachyon=false, org.torproject.torbrowser=false}; rawOverrides={org.torproject.torbrowser=false, org.article19.circulo.next=false}; overridable)
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class TestHashes:
|
|||||||
# This needs to be updated when we add or edit files in AndroidQF folder
|
# This needs to be updated when we add or edit files in AndroidQF folder
|
||||||
assert (
|
assert (
|
||||||
hashes[1]["sha256"]
|
hashes[1]["sha256"]
|
||||||
== "1bd255f656a7f9d5647a730f0f0cc47053115576f11532d41bf28c16635b193d"
|
== "9fb6396b64cfff30e2a459a64496d3c1386926d09edd68be2d878de45fa7b3a9"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user