mirror of
https://github.com/mvt-project/mvt.git
synced 2026-04-21 03:06:41 +02:00
Compare commits
1 Commits
main
...
accessibil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bcbaac3a2 |
@@ -22,13 +22,13 @@ class DumpsysAccessibilityArtifact(AndroidArtifact):
|
|||||||
|
|
||||||
def parse(self, content: str) -> None:
|
def parse(self, content: str) -> None:
|
||||||
"""
|
"""
|
||||||
Parse the Dumpsys Accessibility section/
|
Parse the Dumpsys Accessibility section.
|
||||||
Adds results to self.results (List[Dict[str, str]])
|
Adds results to self.results (List[Dict[str, Any]])
|
||||||
|
|
||||||
:param content: content of the accessibility section (string)
|
:param content: content of the accessibility section (string)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# "Old" syntax
|
# Parse installed services
|
||||||
in_services = False
|
in_services = False
|
||||||
for line in content.splitlines():
|
for line in content.splitlines():
|
||||||
if line.strip().startswith("installed services:"):
|
if line.strip().startswith("installed services:"):
|
||||||
@@ -39,7 +39,6 @@ class DumpsysAccessibilityArtifact(AndroidArtifact):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if line.strip() == "}":
|
if line.strip() == "}":
|
||||||
# At end of installed services
|
|
||||||
break
|
break
|
||||||
|
|
||||||
service = line.split(":")[1].strip()
|
service = line.split(":")[1].strip()
|
||||||
@@ -48,21 +47,66 @@ class DumpsysAccessibilityArtifact(AndroidArtifact):
|
|||||||
{
|
{
|
||||||
"package_name": service.split("/")[0],
|
"package_name": service.split("/")[0],
|
||||||
"service": service,
|
"service": service,
|
||||||
|
"enabled": False,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# "New" syntax - AOSP >= 14 (?)
|
# Parse enabled services from both old and new formats.
|
||||||
# Looks like:
|
#
|
||||||
# Enabled services:{{com.azure.authenticator/com.microsoft.brooklyn.module.accessibility.BrooklynAccessibilityService}, {com.agilebits.onepassword/com.agilebits.onepassword.filling.accessibility.FillingAccessibilityService}}
|
# Old format (multi-line block):
|
||||||
|
# enabled services: {
|
||||||
|
# 0 : com.example/.MyService
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# New format (single line, AOSP >= 14):
|
||||||
|
# Enabled services:{{com.example/com.example.MyService}, {com.other/com.other.Svc}}
|
||||||
|
enabled_services = set()
|
||||||
|
|
||||||
|
in_enabled = False
|
||||||
for line in content.splitlines():
|
for line in content.splitlines():
|
||||||
if line.strip().startswith("Enabled services:"):
|
stripped = line.strip()
|
||||||
matches = re.finditer(r"{([^{]+?)}", line)
|
|
||||||
|
|
||||||
|
if in_enabled:
|
||||||
|
if stripped == "}":
|
||||||
|
in_enabled = False
|
||||||
|
continue
|
||||||
|
service = line.split(":")[1].strip()
|
||||||
|
enabled_services.add(service)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if re.match(r"enabled services:\s*\{\s*$", stripped, re.IGNORECASE):
|
||||||
|
# Old multi-line format: "enabled services: {"
|
||||||
|
in_enabled = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if re.match(r"enabled services:\s*\{", stripped, re.IGNORECASE):
|
||||||
|
# New single-line format: "Enabled services:{{pkg/svc}, {pkg2/svc2}}"
|
||||||
|
matches = re.finditer(r"\{([^{}]+)\}", stripped)
|
||||||
for match in matches:
|
for match in matches:
|
||||||
# Each match is in format: <package_name>/<service>
|
enabled_services.add(match.group(1).strip())
|
||||||
package_name, _, service = match.group(1).partition("/")
|
|
||||||
|
|
||||||
self.results.append(
|
# Mark installed services that are enabled.
|
||||||
{"package_name": package_name, "service": service}
|
# Installed service names may include trailing annotations like
|
||||||
)
|
# "(A11yTool)" that are absent from the enabled services list,
|
||||||
|
# so strip annotations before comparing.
|
||||||
|
def _strip_annotation(s: str) -> str:
|
||||||
|
return re.sub(r"\s+\(.*?\)\s*$", "", s)
|
||||||
|
|
||||||
|
installed_stripped = {
|
||||||
|
_strip_annotation(r["service"]): r for r in self.results
|
||||||
|
}
|
||||||
|
for enabled in enabled_services:
|
||||||
|
if enabled in installed_stripped:
|
||||||
|
installed_stripped[enabled]["enabled"] = True
|
||||||
|
|
||||||
|
# Add enabled services not found in the installed list
|
||||||
|
for service in enabled_services:
|
||||||
|
if service not in installed_stripped:
|
||||||
|
package_name, _, _ = service.partition("/")
|
||||||
|
self.results.append(
|
||||||
|
{
|
||||||
|
"package_name": package_name,
|
||||||
|
"service": service,
|
||||||
|
"enabled": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -49,9 +49,14 @@ class DumpsysAccessibility(DumpsysAccessibilityArtifact, BugReportModule):
|
|||||||
|
|
||||||
for result in self.results:
|
for result in self.results:
|
||||||
self.log.info(
|
self.log.info(
|
||||||
'Found installed accessibility service "%s"', result.get("service")
|
'Found installed accessibility service "%s" (enabled: %s)',
|
||||||
|
result.get("service"),
|
||||||
|
result.get("enabled", False),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enabled_count = sum(1 for r in self.results if r.get("enabled"))
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Identified a total of %d accessibility services", len(self.results)
|
"Identified a total of %d accessibility services, %d enabled",
|
||||||
|
len(self.results),
|
||||||
|
enabled_count,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ class TestDumpsysAccessibilityArtifact:
|
|||||||
da.results[0]["service"]
|
da.results[0]["service"]
|
||||||
== "com.android.settings/com.samsung.android.settings.development.gpuwatch.GPUWatchInterceptor"
|
== "com.android.settings/com.samsung.android.settings.development.gpuwatch.GPUWatchInterceptor"
|
||||||
)
|
)
|
||||||
|
# All services are installed but none enabled in this fixture
|
||||||
|
for result in da.results:
|
||||||
|
assert result["enabled"] is False
|
||||||
|
|
||||||
def test_parsing_v14_aosp_format(self):
|
def test_parsing_v14_aosp_format(self):
|
||||||
da = DumpsysAccessibilityArtifact()
|
da = DumpsysAccessibilityArtifact()
|
||||||
@@ -36,7 +39,32 @@ class TestDumpsysAccessibilityArtifact:
|
|||||||
da.parse(data)
|
da.parse(data)
|
||||||
assert len(da.results) == 1
|
assert len(da.results) == 1
|
||||||
assert da.results[0]["package_name"] == "com.malware.accessibility"
|
assert da.results[0]["package_name"] == "com.malware.accessibility"
|
||||||
assert da.results[0]["service"] == "com.malware.service.malwareservice"
|
assert (
|
||||||
|
da.results[0]["service"]
|
||||||
|
== "com.malware.accessibility/com.malware.service.malwareservice"
|
||||||
|
)
|
||||||
|
assert da.results[0]["enabled"] is True
|
||||||
|
|
||||||
|
def test_parsing_installed_and_enabled(self):
|
||||||
|
da = DumpsysAccessibilityArtifact()
|
||||||
|
file = get_artifact("android_data/dumpsys_accessibility_enabled.txt")
|
||||||
|
with open(file) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
assert len(da.results) == 0
|
||||||
|
da.parse(data)
|
||||||
|
assert len(da.results) == 5
|
||||||
|
|
||||||
|
enabled = [r for r in da.results if r["enabled"]]
|
||||||
|
assert len(enabled) == 1
|
||||||
|
assert enabled[0]["package_name"] == "com.samsung.accessibility"
|
||||||
|
assert (
|
||||||
|
enabled[0]["service"]
|
||||||
|
== "com.samsung.accessibility/.universalswitch.UniversalSwitchService (A11yTool)"
|
||||||
|
)
|
||||||
|
|
||||||
|
not_enabled = [r for r in da.results if not r["enabled"]]
|
||||||
|
assert len(not_enabled) == 4
|
||||||
|
|
||||||
def test_ioc_check(self, indicator_file):
|
def test_ioc_check(self, indicator_file):
|
||||||
da = DumpsysAccessibilityArtifact()
|
da = DumpsysAccessibilityArtifact()
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
ACCESSIBILITY MANAGER (dumpsys accessibility)
|
||||||
|
|
||||||
|
currentUserId=0
|
||||||
|
User state[
|
||||||
|
attributes:{id=0, touchExplorationEnabled=false, installedServiceCount=5}
|
||||||
|
installed services: {
|
||||||
|
0 : com.google.android.apps.accessibility.voiceaccess/.JustSpeakService (A11yTool)
|
||||||
|
1 : com.microsoft.appmanager/com.microsoft.mmx.screenmirroringsrc.accessibility.ScreenMirroringAccessibilityService
|
||||||
|
2 : com.samsung.accessibility/.assistantmenu.serviceframework.AssistantMenuService (A11yTool)
|
||||||
|
3 : com.samsung.accessibility/.universalswitch.UniversalSwitchService (A11yTool)
|
||||||
|
4 : com.samsung.android.accessibility.talkback/com.samsung.android.marvin.talkback.TalkBackService (A11yTool)
|
||||||
|
}
|
||||||
|
Bound services:{}
|
||||||
|
Enabled services:{{com.samsung.accessibility/.universalswitch.UniversalSwitchService}}
|
||||||
|
Binding services:{}
|
||||||
|
Crashed services:{}
|
||||||
Reference in New Issue
Block a user