mirror of https://github.com/mvt-project/mvt.git
Refactor dumpsys accessibility in an artifact
This commit is contained in:
parent
ecf75447aa
commit
4c175530a8
|
@ -6,4 +6,30 @@ from mvt.common.artifact import Artifact
|
|||
|
||||
|
||||
class AndroidArtifact(Artifact):
|
||||
pass
|
||||
@staticmethod
|
||||
def extract_dumpsys_section(dumpsys: str, separator: str) -> str:
|
||||
"""
|
||||
Extract a section from a full dumpsys file.
|
||||
|
||||
:param dumpsys: content of the full dumpsys file (string)
|
||||
:param separator: content of the first line separator (string)
|
||||
:return: section extracted (string)
|
||||
"""
|
||||
lines = []
|
||||
in_section = False
|
||||
for line in dumpsys.splitlines():
|
||||
if line.strip() == separator:
|
||||
in_section = True
|
||||
continue
|
||||
|
||||
if not in_section:
|
||||
continue
|
||||
|
||||
if line.strip().startswith(
|
||||
"------------------------------------------------------------------------------"
|
||||
):
|
||||
break
|
||||
|
||||
lines.append(line)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 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/
|
||||
from .artifact import AndroidArtifact
|
||||
|
||||
|
||||
class DumpsysAccessibility(AndroidArtifact):
|
||||
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, content: str):
|
||||
"""
|
||||
Parse the Dumpsys Accessibility section/
|
||||
Adds results to self.results (List[Dict[str, str]])
|
||||
|
||||
:param content: content of the accessibility section (string)
|
||||
"""
|
||||
in_services = False
|
||||
for line in content.splitlines():
|
||||
if line.strip().startswith("installed services:"):
|
||||
in_services = True
|
||||
continue
|
||||
|
||||
if not in_services:
|
||||
continue
|
||||
|
||||
if line.strip() == "}":
|
||||
break
|
||||
|
||||
service = line.split(":")[1].strip()
|
||||
|
||||
self.results.append(
|
||||
{
|
||||
"package_name": service.split("/")[0],
|
||||
"service": service,
|
||||
}
|
||||
)
|
|
@ -6,12 +6,12 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from mvt.android.parsers import parse_dumpsys_accessibility
|
||||
from mvt.android.artifacts.dumpsys_accessibility import DumpsysAccessibility as DAA
|
||||
|
||||
from .base import AndroidExtraction
|
||||
|
||||
|
||||
class DumpsysAccessibility(AndroidExtraction):
|
||||
class DumpsysAccessibility(DAA, AndroidExtraction):
|
||||
"""This module extracts stats on accessibility."""
|
||||
|
||||
def __init__(
|
||||
|
@ -32,23 +32,12 @@ class DumpsysAccessibility(AndroidExtraction):
|
|||
results=results,
|
||||
)
|
||||
|
||||
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 run(self) -> None:
|
||||
self._adb_connect()
|
||||
output = self._adb_command("dumpsys accessibility")
|
||||
self._adb_disconnect()
|
||||
|
||||
self.results = parse_dumpsys_accessibility(output)
|
||||
self.parse(output)
|
||||
|
||||
for result in self.results:
|
||||
self.log.info(
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from mvt.android.parsers import parse_dumpsys_accessibility
|
||||
from mvt.android.artifacts.dumpsys_accessibility import DumpsysAccessibility as DAA
|
||||
|
||||
from .base import AndroidQFModule
|
||||
|
||||
|
||||
class DumpsysAccessibility(AndroidQFModule):
|
||||
class DumpsysAccessibility(DAA, AndroidQFModule):
|
||||
"""This module analyse dumpsys accessbility"""
|
||||
|
||||
def __init__(
|
||||
|
@ -32,40 +32,14 @@ class DumpsysAccessibility(AndroidQFModule):
|
|||
results=results,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
def run(self) -> None:
|
||||
dumpsys_file = self._get_files_by_pattern("*/dumpsys.txt")
|
||||
if not dumpsys_file:
|
||||
return
|
||||
|
||||
lines = []
|
||||
in_accessibility = False
|
||||
data = self._get_file_content(dumpsys_file[0])
|
||||
for line in data.decode("utf-8").split("\n"):
|
||||
if line.strip().startswith("DUMP OF SERVICE accessibility:"):
|
||||
in_accessibility = True
|
||||
continue
|
||||
|
||||
if not in_accessibility:
|
||||
continue
|
||||
|
||||
if line.strip().startswith(
|
||||
"-------------------------------------------------------------------------------"
|
||||
): # pylint: disable=line-too-long
|
||||
break
|
||||
|
||||
lines.append(line.rstrip())
|
||||
|
||||
self.results = parse_dumpsys_accessibility("\n".join(lines))
|
||||
data = self._get_file_content(dumpsys_file[0]).decode("utf-8", errors="replace")
|
||||
content = self.extract_dumpsys_section(data, "DUMP OF SERVICE accessibility:")
|
||||
self.parse(content)
|
||||
|
||||
for result in self.results:
|
||||
self.log.info(
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from mvt.android.parsers import parse_dumpsys_accessibility
|
||||
from mvt.android.artifacts.dumpsys_accessibility import DumpsysAccessibility as DAA
|
||||
|
||||
from .base import BugReportModule
|
||||
|
||||
|
||||
class Accessibility(BugReportModule):
|
||||
class Accessibility(DAA, BugReportModule):
|
||||
"""This module extracts stats on accessibility."""
|
||||
|
||||
def __init__(
|
||||
|
@ -32,44 +32,21 @@ class Accessibility(BugReportModule):
|
|||
results=results,
|
||||
)
|
||||
|
||||
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 run(self) -> None:
|
||||
content = self._get_dumpstate_file()
|
||||
if not content:
|
||||
full_dumpsys = self._get_dumpstate_file()
|
||||
if not full_dumpsys:
|
||||
self.log.error(
|
||||
"Unable to find dumpstate file. "
|
||||
"Did you provide a valid bug report archive?"
|
||||
)
|
||||
return
|
||||
|
||||
lines = []
|
||||
in_accessibility = False
|
||||
for line in content.decode(errors="ignore").splitlines():
|
||||
if line.strip() == "DUMP OF SERVICE accessibility:":
|
||||
in_accessibility = True
|
||||
continue
|
||||
content = self.extract_dumpsys_section(
|
||||
full_dumpsys.decode("utf-8", errors="ignore"),
|
||||
"DUMP OF SERVICE accessibility:",
|
||||
)
|
||||
self.parse(content)
|
||||
|
||||
if not in_accessibility:
|
||||
continue
|
||||
|
||||
if line.strip().startswith(
|
||||
"------------------------------------------------------------------------------"
|
||||
): # pylint: disable=line-too-long
|
||||
break
|
||||
|
||||
lines.append(line)
|
||||
|
||||
self.results = parse_dumpsys_accessibility("\n".join(lines))
|
||||
for result in self.results:
|
||||
self.log.info(
|
||||
'Found installed accessibility service "%s"', result.get("service")
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# https://license.mvt.re/1.1/
|
||||
|
||||
from .dumpsys import (
|
||||
parse_dumpsys_accessibility,
|
||||
parse_dumpsys_activity_resolver_table,
|
||||
parse_dumpsys_appops,
|
||||
parse_dumpsys_battery_daily,
|
||||
|
|
|
@ -10,33 +10,6 @@ from typing import Any, Dict, List
|
|||
from mvt.common.utils import convert_datetime_to_iso
|
||||
|
||||
|
||||
def parse_dumpsys_accessibility(output: str) -> List[Dict[str, str]]:
|
||||
results = []
|
||||
|
||||
in_services = False
|
||||
for line in output.splitlines():
|
||||
if line.strip().startswith("installed services:"):
|
||||
in_services = True
|
||||
continue
|
||||
|
||||
if not in_services:
|
||||
continue
|
||||
|
||||
if line.strip() == "}":
|
||||
break
|
||||
|
||||
service = line.split(":")[1].strip()
|
||||
|
||||
results.append(
|
||||
{
|
||||
"package_name": service.split("/")[0],
|
||||
"service": service,
|
||||
}
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def parse_dumpsys_activity_resolver_table(output: str) -> Dict[str, Any]:
|
||||
results = {}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 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/
|
||||
from mvt.android.artifacts.artifact import AndroidArtifact
|
||||
|
||||
from ..utils import get_artifact
|
||||
|
||||
|
||||
class TestAndroidArtifact:
|
||||
def test_extract_dumpsys_section(self):
|
||||
file = get_artifact("androidqf/dumpsys.txt")
|
||||
with open(file) as f:
|
||||
data = f.read()
|
||||
|
||||
section = AndroidArtifact.extract_dumpsys_section(
|
||||
data, "DUMP OF SERVICE package:"
|
||||
)
|
||||
assert isinstance(section, str)
|
||||
assert len(section) == 3907
|
|
@ -0,0 +1,42 @@
|
|||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2023 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.android.artifacts.dumpsys_accessibility import DumpsysAccessibility
|
||||
from mvt.common.indicators import Indicators
|
||||
|
||||
from ..utils import get_artifact
|
||||
|
||||
|
||||
class TestDumpsysAccessibilityArtifact:
|
||||
def test_parsing(self):
|
||||
da = DumpsysAccessibility()
|
||||
file = get_artifact("android_data/dumpsys_accessibility.txt")
|
||||
with open(file) as f:
|
||||
data = f.read()
|
||||
|
||||
assert len(da.results) == 0
|
||||
da.parse(data)
|
||||
assert len(da.results) == 4
|
||||
assert da.results[0]["package_name"] == "com.android.settings"
|
||||
assert (
|
||||
da.results[0]["service"]
|
||||
== "com.android.settings/com.samsung.android.settings.development.gpuwatch.GPUWatchInterceptor"
|
||||
)
|
||||
|
||||
def test_ioc_check(self, indicator_file):
|
||||
da = DumpsysAccessibility()
|
||||
file = get_artifact("android_data/dumpsys_accessibility.txt")
|
||||
with open(file) as f:
|
||||
data = f.read()
|
||||
da.parse(data)
|
||||
|
||||
ind = Indicators(log=logging.getLogger())
|
||||
ind.parse_stix2(indicator_file)
|
||||
ind.ioc_collections[0]["app_ids"].append("com.sec.android.app.camera")
|
||||
da.indicators = ind
|
||||
assert len(da.detected) == 0
|
||||
da.check_indicators()
|
||||
assert len(da.detected) == 1
|
|
@ -0,0 +1,40 @@
|
|||
ACCESSIBILITY MANAGER (dumpsys accessibility)
|
||||
|
||||
User state[attributes:{id=0, currentUser=true
|
||||
mIsNavBarMagnificationAssignedToAccessibilityButton = false
|
||||
|
||||
mIsNavBarMagnifierWindowAssignedToAccessibilityButton = false
|
||||
mIsNavBarAmplifyAmbientSoundAssignedToAccessibilityButton = false
|
||||
mIsAmplifyAmbientSoundEnabled = false
|
||||
mIsBixbyRunning = false
|
||||
mIsMagniferWindowEnabled = false
|
||||
mIsFollowTypingFocusEnabled = false
|
||||
mIsTapDurationEnabled = false
|
||||
mIsTouchBlockingEnabled = false
|
||||
mIsTextHighContrastEnabled = false
|
||||
mIsDisplayMagnificationEnabled = false
|
||||
mIsNavBarMagnificationEnabled = false
|
||||
mIsAutoclickEnabled = false
|
||||
mIsPerformGesturesEnabled = false
|
||||
mIsFilterKeyEventsEnabled = false
|
||||
mAccessibilityFocusOnlyInActiveWindow = true
|
||||
mUserNonInteractiveUiTimeout = 0
|
||||
mUserInteractiveUiTimeout = 0
|
||||
mBindInstantServiceAllowed = false
|
||||
mIsGestureNaviBar = false
|
||||
}
|
||||
installed services: {
|
||||
0 : com.android.settings/com.samsung.android.settings.development.gpuwatch.GPUWatchInterceptor
|
||||
1 : com.samsung.accessibility/.universalswitch.UniversalSwitchService
|
||||
2 : com.samsung.accessibility/com.samsung.android.app.talkback.TalkBackService
|
||||
3 : com.sec.android.app.camera/com.samsung.android.glview.AccessibilityGestureHandler
|
||||
}
|
||||
enabled services: {
|
||||
}
|
||||
binding services: {
|
||||
}
|
||||
bound services:{
|
||||
}
|
||||
AccessibilityInputFilter:{
|
||||
}]
|
||||
|
Loading…
Reference in New Issue