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 |
|---|
| #!/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 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.