From 6bb47757e1d142ed486ded242d2db7edbc5f888b Mon Sep 17 00:00:00 2001 From: Rory Flynn Date: Wed, 17 Apr 2024 00:47:44 +0200 Subject: [PATCH] Fix dumpsys accessibility detections for v14+ --- .../artifacts/dumpsys_accessibility.py | 20 ++++++++ mvt/android/artifacts/settings.py | 5 ++ .../test_artifact_dumpsys_accessibility.py | 12 +++++ .../dumpsys_accessibility_v14_or_later.txt | 46 +++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 tests/artifacts/android_data/dumpsys_accessibility_v14_or_later.txt diff --git a/mvt/android/artifacts/dumpsys_accessibility.py b/mvt/android/artifacts/dumpsys_accessibility.py index f760ade..7e75267 100644 --- a/mvt/android/artifacts/dumpsys_accessibility.py +++ b/mvt/android/artifacts/dumpsys_accessibility.py @@ -4,6 +4,7 @@ # https://license.mvt.re/1.1/ from .artifact import AndroidArtifact +import re class DumpsysAccessibilityArtifact(AndroidArtifact): @@ -25,6 +26,8 @@ class DumpsysAccessibilityArtifact(AndroidArtifact): :param content: content of the accessibility section (string) """ + + # "Old" syntax in_services = False for line in content.splitlines(): if line.strip().startswith("installed services:"): @@ -35,6 +38,7 @@ class DumpsysAccessibilityArtifact(AndroidArtifact): continue if line.strip() == "}": + # At end of installed services break service = line.split(":")[1].strip() @@ -45,3 +49,19 @@ class DumpsysAccessibilityArtifact(AndroidArtifact): "service": service, } ) + + # "New" syntax - AOSP >= 14 (?) + # Looks like: + # Enabled services:{{com.azure.authenticator/com.microsoft.brooklyn.module.accessibility.BrooklynAccessibilityService}, {com.agilebits.onepassword/com.agilebits.onepassword.filling.accessibility.FillingAccessibilityService}} + + for line in content.splitlines(): + if line.strip().startswith("Enabled services:"): + matches = re.finditer(r"{([^{]+?)}", line) + + for match in matches: + # Each match is in format: / + package_name, _, service = match.group(1).partition("/") + + self.results.append( + {"package_name": package_name, "service": service} + ) diff --git a/mvt/android/artifacts/settings.py b/mvt/android/artifacts/settings.py index 44cdf7e..1ce75e8 100644 --- a/mvt/android/artifacts/settings.py +++ b/mvt/android/artifacts/settings.py @@ -51,6 +51,11 @@ ANDROID_DANGEROUS_SETTINGS = [ "key": "install_non_market_apps", "safe_value": "0", }, + { + "description": "enabled accessibility services", + "key": "accessibility_enabled", + "safe_value": "0", + }, ] diff --git a/tests/android/test_artifact_dumpsys_accessibility.py b/tests/android/test_artifact_dumpsys_accessibility.py index 52482c6..2eca8fa 100644 --- a/tests/android/test_artifact_dumpsys_accessibility.py +++ b/tests/android/test_artifact_dumpsys_accessibility.py @@ -26,6 +26,18 @@ class TestDumpsysAccessibilityArtifact: == "com.android.settings/com.samsung.android.settings.development.gpuwatch.GPUWatchInterceptor" ) + def test_parsing_v14_aosp_format(self): + da = DumpsysAccessibilityArtifact() + file = get_artifact("android_data/dumpsys_accessibility_v14_or_later.txt") + with open(file) as f: + data = f.read() + + assert len(da.results) == 0 + da.parse(data) + assert len(da.results) == 1 + assert da.results[0]["package_name"] == "com.malware.accessibility" + assert da.results[0]["service"] == "com.malware.service.malwareservice" + def test_ioc_check(self, indicator_file): da = DumpsysAccessibilityArtifact() file = get_artifact("android_data/dumpsys_accessibility.txt") diff --git a/tests/artifacts/android_data/dumpsys_accessibility_v14_or_later.txt b/tests/artifacts/android_data/dumpsys_accessibility_v14_or_later.txt new file mode 100644 index 0000000..830785c --- /dev/null +++ b/tests/artifacts/android_data/dumpsys_accessibility_v14_or_later.txt @@ -0,0 +1,46 @@ +DUMP OF SERVICE accessibility: +Service host process PID: 633 +Threads in use: 0/14 +Client PIDs: 2445, 2428, 2405, 2235, 2215, 2164, 2148, 2130, 2104, 2062, 1879, 1824, 1736, 1748, 1746, 1617, 1605, 1606, 1582, 1538, 1523, 1474, 1307, 1237, 1118, 1081, 1076, 1023, 997, 978, 882, 187 +ACCESSIBILITY MANAGER (dumpsys accessibility) + +currentUserId=0 +hasWindowMagnificationConnection=false +Magnifier on display#0 + MagnificationConfig[mode: 1, activated: false, scale: 1.0, centerX: 360.0, centerY: 640.0] + Magnification region=SkRegion((3,3,717,1277)) + IdOfLastServiceToMagnify=-1 + SupportWindowMagnification=true + WindowMagnificationConnectionState=DISCONNECTED +User state[ + attributes:{id=0, touchExplorationEnabled=false, serviceHandlesDoubleTap=false, requestMultiFingerGestures=false, requestTwoFingerPassthrough=false, sendMotionEventsEnabledfalse, displayMagnificationEnabled=false, autoclickEnabled=false, nonInteractiveUiTimeout=0, interactiveUiTimeout=0, installedServiceCount=2, magnificationModes={0=1}, magnificationCapabilities=3, audioDescriptionByDefaultEnabled=false, magnificationFollowTypingEnabled=true, alwaysOnMagnificationEnabled=true} + shortcut key:{} + button:{} + button target:{null} + Bound services:{Service[label=Accessibility service, feedbackType[FEEDBACK_SPOKEN, FEEDBACK_HAPTIC, FEEDBACK_AUDIBLE, FEEDBACK_VISUAL, FEEDBACK_GENERIC, FEEDBACK_BRAILLE], capabilities=11, eventTypes=TYPES_ALL_MASK, notificationTimeout=1000, requestA11yBtn=false]} + Enabled services:{{com.malware.accessibility/com.malware.service.malwareservice}} + Binding services:{} + Crashed services:{} + Client list info:{ + Client list callbacks: 6 + Client list killed: false + Client list broadcasts count: -1 + Registered clients:{ +[com.malware.accessibility][com.android.launcher3][com.android.systemui][com.android.launcher3][com.android.settings.intelligence][com.android.inputmethod.latin]}] + +Window attributes:[{1=AccessibilityWindowAttributes{mAccessibilityWindowTitle=nullmLocales=[en_US]}, 2=AccessibilityWindowAttributes{mAccessibilityWindowTitle=nullmLocales=[en_US]}, 3=AccessibilityWindowAttributes{mAccessibilityWindowTitle=nullmLocales=[en_US]}, 4=AccessibilityWindowAttributes{mAccessibilityWindowTitle=nullmLocales=[en_US]}, 5=AccessibilityWindowAttributes{mAccessibilityWindowTitle=nullmLocales=[en_US]}, 6=AccessibilityWindowAttributes{mAccessibilityWindowTitle=nullmLocales=[en_US]}, 7=AccessibilityWindowAttributes{mAccessibilityWindowTitle=HomemLocales=[en_US]}, 9=AccessibilityWindowAttributes{mAccessibilityWindowTitle=SettingsmLocales=[en_US]}, 10=AccessibilityWindowAttributes{mAccessibilityWindowTitle=Settings SuggestionsmLocales=[en_US]}}] +A11yInputFilter Info : +Enabled features of Display [0] = [KeyboardInterceptor] +Global client list info:{ + Client list callbacks: 4 + Client list killed: false + Client list broadcasts count: -1 + Registered clients:{ +[com.android.permissioncontroller][com.android.dynsystem, com.android.server.telecom, com.android.keychain, com.android.settings, com.android.localtransport, com.android.wallpaperbackup, com.android.inputdevices, com.android.providers.settings, android, com.android.emulator.multidisplay, com.android.location.fused][com.android.emulator.multidisplay, com.android.wallpaperbackup, com.android.settings, com.android.keychain, com.android.dynsystem, com.android.inputdevices, com.android.providers.settings, com.android.localtransport, com.android.server.telecom, android, com.android.location.fused][com.android.systemui] + +Proxy manager state: + Number of proxy connections: 0 + Registered proxy connections: +Accessibility Display Listener: + SystemUI uid: 10076 + 1 valid display: 0 \ No newline at end of file