Skip to content

MASTG-DEMO-0115: JDWP Debugging Checks in App Code

Download MASTG-DEMO-0115 APK Open MASTG-DEMO-0115 Folder Build MASTG-DEMO-0115 APK

Sample

This sample detects an attached JDWP debugger at runtime by calling Debug.isDebuggerConnected().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.owasp.mastestapp

// SUMMARY: This demo detects active JDWP debugger attachment at runtime.

import android.content.Context
import android.os.Debug

class MastgTest (private val context: Context){

    fun mastgTest(): String {
        val r = DemoResults("0x40")

        try {
            val debuggerConnected = Debug.isDebuggerConnected()

            if (debuggerConnected) {
                // FAIL: [MASTG-TEST-0352] Debug.isDebuggerConnected reports an attached JDWP debugger.
                r.add(Status.FAIL, "Debug.isDebuggerConnected reports an attached JDWP debugger.")
            } else {
                // PASS: [MASTG-TEST-0352] Debug.isDebuggerConnected reports no attached JDWP debugger.
                r.add(Status.PASS, "Debug.isDebuggerConnected reports no attached JDWP debugger.")
            }

        } catch (e: Exception) {
            r.add(Status.ERROR, "Unexpected error while running anti-debugging checks: ${e.javaClass.simpleName}: ${e.message}")
        }

        return r.toJson()
    }

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package org.owasp.mastestapp;

import android.content.Context;
import android.os.Debug;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;

/* compiled from: MastgTest.kt */
@Metadata(d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\u000f\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0004\b\u0004\u0010\u0005J\u0006\u0010\u0006\u001a\u00020\u0007R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\b"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "<init>", "(Landroid/content/Context;)V", "mastgTest", "", "app_debug"}, k = 1, mv = {2, 0, 0}, xi = 48)
/* loaded from: classes3.dex */
public final class MastgTest {
    public static final int $stable = 8;
    private final Context context;

    public MastgTest(Context context) {
        Intrinsics.checkNotNullParameter(context, "context");
        this.context = context;
    }

    public final String mastgTest() {
        DemoResults r = new DemoResults("0x40");
        try {
            boolean debuggerConnected = Debug.isDebuggerConnected();
            if (debuggerConnected) {
                r.add(Status.FAIL, "Debug.isDebuggerConnected reports an attached JDWP debugger.");
            } else {
                r.add(Status.PASS, "Debug.isDebuggerConnected reports no attached JDWP debugger.");
            }
        } catch (Exception e) {
            r.add(Status.ERROR, "Unexpected error while running anti-debugging checks: " + e.getClass().getSimpleName() + ": " + e.getMessage());
        }
        return r.toJson();
    }
}

Steps

Let's run semgrep with the following rule:

../../../../rules/mastg-android-debugger-checks.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
rules:
  - id: mastg-android-debugger-checks
    severity: WARNING
    languages: [java]
    metadata:
      summary: Detects Android debugger checks in code.
    message: "[MASVS-RESILIENCE-4] debugger checks detected."
    patterns:
      - pattern-either:
          - pattern: Debug.isDebuggerConnected(...)
          - pattern: Debug.isDebuggerConnected()
          - pattern: ApplicationInfo.FLAG_DEBUGGABLE
run.sh
1
2
3
4
#!/usr/bin/env bash
set -euo pipefail

NO_COLOR=true semgrep -c ../../../../rules/mastg-android-debugger-checks.yml ./MastgTest_reversed.java --text > output.txt

Observation

The output lists code locations where runtime debugger checks are performed.

output.txt
1
2
3
4
5
6
7
8
9
┌────────────────┐
 1 Code Finding 
└────────────────┘

    MastgTest_reversed.java
    ❯❱ rules.mastg-android-debugger-checks
          [MASVS-RESILIENCE-4] debugger checks detected.

           23 boolean debuggerConnected = Debug.isDebuggerConnected();

Evaluation

The test passes because the app uses Debug.isDebuggerConnected() API to detect an attached JDWP debugger at line 23.