diff --git a/test_apks/dyn_and_ref/AndroidManifest.xml b/test_apks/dyn_and_ref/AndroidManifest.xml
index c5aa54a..2ae2d8f 100644
--- a/test_apks/dyn_and_ref/AndroidManifest.xml
+++ b/test_apks/dyn_and_ref/AndroidManifest.xml
@@ -36,8 +36,9 @@
-
-
+
+
+
diff --git a/test_apks/dyn_and_ref/Makefile b/test_apks/dyn_and_ref/Makefile
index aec1dc7..1c8c2fb 100644
--- a/test_apks/dyn_and_ref/Makefile
+++ b/test_apks/dyn_and_ref/Makefile
@@ -34,10 +34,13 @@ debug: JAVAC_ARGS += -g
debug: D8_ARGS += --debug
debug: all
-test: all grodd-venv
+test: all #grodd-venv
$(ADB) install build/$(APP).apk
- $(ADB) shell am start -n $(PACKAGE)/.$(MAIN_ACTIVITY)
- grodd-venv/bin/grodd-runner -d emulator-5554 -r grodd -t 900 -p $(PACKAGE) -s 0.5
+ $(ADB) logcat -s THESEUS -c
+ python3 tests/test_apk.py
+ $(ADB) logcat -s THESEUS -d
+ #$(ADB) shell am start -n $(PACKAGE)/.$(MAIN_ACTIVITY)
+ #grodd-venv/bin/grodd-runner -d emulator-5554 -r grodd -t 900 -p $(PACKAGE) -s 0.5
build/%.v1signed.apk: ./build/%.unsigned.apk ./ToyKey.keystore
$(JARSIGNER) -verbose -keystore ./ToyKey.keystore -storepass $(pass) -keypass $(pass) -signedjar $@ $< SignKey
@@ -74,9 +77,9 @@ build/%.apk: ./build/%.v2aligned.apk
ToyKey.keystore :
$(KEYTOOL) -genkeypair -validity 1000 -dname "CN=SomeKey,O=SomeOne,C=FR" -keystore $@ -storepass $(pass) -keypass $(pass) -alias SignKey -keyalg RSA -v
-grodd-venv:
- python3 -m venv grodd-venv
- grodd-venv/bin/pip install 'git+ssh://git@gitlab.inria.fr/CIDRE/malware/grodd-runner.git'
+#grodd-venv:
+# python3 -m venv grodd-venv
+# grodd-venv/bin/pip install 'git+ssh://git@gitlab.inria.fr/CIDRE/malware/grodd-runner.git'
clean:
$(RM) -r build/*
diff --git a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/APReflectee.java b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/APReflectee.java
index 4dae25b..cadc028 100644
--- a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/APReflectee.java
+++ b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/APReflectee.java
@@ -1,6 +1,6 @@
package com.example.theseus.dynandref;
-public class APReflectee {
+public class APReflectee extends PCommonParent {
public String extendedTransfer(
boolean bool,
byte by,
diff --git a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/AReflectee.java b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/AReflectee.java
index 13b609d..980091e 100644
--- a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/AReflectee.java
+++ b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/AReflectee.java
@@ -78,4 +78,23 @@ public class AReflectee extends APReflectee implements AIReflectee, ICommonInter
}
return getReflecteeId() + ":" + val + "(" + bool + " " + by + " " + sh + " " + ch + " " + in + " " + lo + " " + fl + " " + dou + " " + str + ")";
}
+
+ public String commonParentTransfer(
+ boolean bool,
+ byte by,
+ short sh,
+ char ch,
+ int in,
+ long lo,
+ float fl,
+ double dou,
+ String str,
+ String... args
+ ) {
+ String val = "";
+ for (String v : args) {
+ val += " " + v;
+ }
+ return getReflecteeId() + ":" + val + "(" + bool + " " + by + " " + sh + " " + ch + " " + in + " " + lo + " " + fl + " " + dou + " " + str + ")";
+ }
}
diff --git a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/Collider.java b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/Collider.java
index 2a895e2..0ae21eb 100644
--- a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/Collider.java
+++ b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/Collider.java
@@ -78,4 +78,23 @@ public class Collider extends PCollider implements ICollider, ICommonInterface {
}
return getColliderId() + ":" + val + "(" + bool + " " + by + " " + sh + " " + ch + " " + in + " " + lo + " " + fl + " " + dou + " " + str + ")";
}
+
+ public String commonParentTransfer(
+ boolean bool,
+ byte by,
+ short sh,
+ char ch,
+ int in,
+ long lo,
+ float fl,
+ double dou,
+ String str,
+ String... args
+ ) {
+ String val = "";
+ for (String v : args) {
+ val += " " + v;
+ }
+ return getColliderId() + ":" + val + "(" + bool + " " + by + " " + sh + " " + ch + " " + in + " " + lo + " " + fl + " " + dou + " " + str + ")";
+ }
}
diff --git a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCollider.java b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCollider.java
index 3f8ab2d..dd0586c 100644
--- a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCollider.java
+++ b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCollider.java
@@ -1,6 +1,6 @@
package com.example.theseus.dynandref;
-public class PCollider {
+public class PCollider extends PCommonParent{
public String extendedTransfer(
boolean bool,
byte by,
diff --git a/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCommonParent.java b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCommonParent.java
new file mode 100644
index 0000000..5ddca17
--- /dev/null
+++ b/test_apks/dyn_and_ref/java/a/com/example/theseus/dynandref/PCommonParent.java
@@ -0,0 +1,16 @@
+package com.example.theseus.dynandref;
+
+public class PCommonParent {
+ public String commonParentTransfer(
+ boolean bool,
+ byte by,
+ short sh,
+ char ch,
+ int in,
+ long lo,
+ float fl,
+ double dou,
+ String str,
+ String... args
+ ) {return "";}
+}
diff --git a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Collider.java b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Collider.java
index 4405fa0..603f83b 100644
--- a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Collider.java
+++ b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Collider.java
@@ -78,4 +78,23 @@ public class Collider extends PCollider implements ICollider, ICommonInterface {
}
return getColliderId() + ":" + val + "(" + bool + " " + by + " " + sh + " " + ch + " " + in + " " + lo + " " + fl + " " + dou + " " + str + ")";
}
+
+ public String commonParentTransfer(
+ boolean bool,
+ byte by,
+ short sh,
+ char ch,
+ int in,
+ long lo,
+ float fl,
+ double dou,
+ String str,
+ String... args
+ ) {
+ String val = "";
+ for (String v : args) {
+ val += " " + v;
+ }
+ return getColliderId() + ":" + val + "(" + bool + " " + by + " " + sh + " " + ch + " " + in + " " + lo + " " + fl + " " + dou + " " + str + ")";
+ }
}
diff --git a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Main.java b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Main.java
index a0ff136..2ab6e38 100644
--- a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Main.java
+++ b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/Main.java
@@ -31,6 +31,7 @@ public class Main {
public static void run(Activity ac, String clname, boolean hasCollision, boolean hasParent, String methodType) {
try {
+ Log.i("THESEUS", "clname: " + clname + ", hasCollision: " + hasCollision + ", hasParent: " + hasParent + ", methodType: " + methodType);
ClassLoader cl;
ClassLoader parent;
if (hasParent) {
@@ -163,8 +164,21 @@ public class Main {
"",
new String[] {"some", "strings"}
);
- } else if (methodType.equals("Factory Pattern")) {
- factory(
+ } else if (methodType.equals("Factory Pattern Interface")) {
+ factoryInterface(
+ ac, clz,
+ true,
+ (byte)42,
+ (short)666,
+ '*',
+ 0xDEAD_BEEF,
+ 0xD1AB011C_5EAF00DL,
+ 0.99f,
+ 3.1415926535897932384626433d,
+ new String[] {"some", "strings"}
+ );
+ } else if (methodType.equals("Factory Pattern Extend")) {
+ factoryExtend(
ac, clz,
true,
(byte)42,
@@ -184,7 +198,7 @@ public class Main {
}
}
- public static void factory(
+ public static void factoryInterface(
Activity ac, Class clz,
boolean bool,
byte by,
@@ -211,6 +225,33 @@ public class Main {
);
Utils.sink(ac, res);
}
+ public static void factoryExtend(
+ Activity ac, Class clz,
+ boolean bool,
+ byte by,
+ short sh,
+ char ch,
+ int in,
+ long lo,
+ float fl,
+ double dou,
+ String... args
+ ) throws Exception {
+ PCommonParent instance = (PCommonParent)clz.getDeclaredConstructor().newInstance();
+ String res = instance.commonParentTransfer(
+ bool,
+ by,
+ sh,
+ ch,
+ in,
+ lo,
+ fl,
+ dou,
+ Utils.source(),
+ args
+ );
+ Utils.sink(ac, res);
+ }
public static void invoke(
Activity ac, boolean instanciate, Class clz, Method mth, Object[] args,
diff --git a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/MethodActivity.java b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/MethodActivity.java
index b0318d9..1e7cb3b 100644
--- a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/MethodActivity.java
+++ b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/MethodActivity.java
@@ -103,6 +103,13 @@ public class MethodActivity extends Activity {
linLayout.addView(b6);
}
+ Button b7 = new Button(this);
+ b7.generateViewId();
+ if (!classLoaderName.equals("DelegateLastClassLoader") && hasParent) {
+ // if no parent or use DelegateLastClassLoader, the type of the Interface is incompatible
+ linLayout.addView(b7);
+ }
+
scrollView.addView(linLayout);
relLayout.addView(scrollView);
setContentView(relLayout);
@@ -149,18 +156,37 @@ public class MethodActivity extends Activity {
}
});
- b6.setText("Factory Pattern");
+ b6.setText("Factory Pattern Interface");
b6.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.setBackgroundTintList(buttonColor);
- Main.run(ac, classLoaderName, hasCollision, hasParent, "Factory Pattern");
+ Main.run(ac, classLoaderName, hasCollision, hasParent, "Factory Pattern Interface");
}
});
+
+ b7.setText("Factory Pattern Extend");
+ b7.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ v.setBackgroundTintList(buttonColor);
+ Main.run(ac, classLoaderName, hasCollision, hasParent, "Factory Pattern Extend");
+ }
+ });
+
+ // Allow to start Main.run from intent for automation
+ String methodType = intent.getStringExtra("methodType");
+ if (methodType != null) {
+ Main.run(ac, classLoaderName, hasCollision, hasParent, methodType);
+ }
}
- public void nextActivity(String classLoaderName) {
- Intent intent = new Intent(this, MethodActivity.class);
- intent.putExtra("classLoaderName", classLoaderName);
- startActivity(intent);
+ @Override
+ protected void onNewIntent(Intent intent) {
+ String classLoaderNameLocal = intent.getStringExtra("classLoaderName");
+ boolean hasCollisionLocal = intent.getBooleanExtra("collision", false);
+ boolean hasParentLocal = intent.getBooleanExtra("parent", false);
+ String methodType = intent.getStringExtra("methodType");
+ if (classLoaderNameLocal != null && methodType != null) {
+ Main.run(this, classLoaderNameLocal, hasCollisionLocal, hasParentLocal, methodType);
+ }
}
}
diff --git a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCollider.java b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCollider.java
index 16a6116..98119fe 100644
--- a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCollider.java
+++ b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCollider.java
@@ -1,6 +1,6 @@
package com.example.theseus.dynandref;
-public class PCollider {
+public class PCollider extends PCommonParent {
public String extendedTransfer(
boolean bool,
byte by,
diff --git a/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCommonParent.java b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCommonParent.java
new file mode 100644
index 0000000..71c3fef
--- /dev/null
+++ b/test_apks/dyn_and_ref/java/classes/com/example/theseus/dynandref/PCommonParent.java
@@ -0,0 +1,16 @@
+package com.example.theseus.dynandref;
+
+public class PCommonParent {
+ public String commonParentTransfer(
+ boolean bool,
+ byte by,
+ short sh,
+ char ch,
+ int in,
+ long lo,
+ float fl,
+ double dou,
+ String str,
+ String... args
+ ) {return "";}
+}
diff --git a/test_apks/dyn_and_ref/tests/expected_result.txt b/test_apks/dyn_and_ref/tests/expected_result.txt
new file mode 100644
index 0000000..2cfdc17
--- /dev/null
+++ b/test_apks/dyn_and_ref/tests/expected_result.txt
@@ -0,0 +1,153 @@
+--------- beginning of main
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: true, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DelegateLastClassLoader, hasCollision: false, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: true, methodType: Factory Pattern Interface
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: true, methodType: Factory Pattern Extend
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: true, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: true, methodType: Factory Pattern Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: true, methodType: Factory Pattern Extend
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: DexClassLoader, hasCollision: false, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: true, methodType: Factory Pattern Interface
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: true, methodType: Factory Pattern Extend
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: true, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: true, methodType: Factory Pattern Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: true, methodType: Factory Pattern Extend
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: InMemoryDexClassLoader, hasCollision: false, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: true, methodType: Factory Pattern Interface
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: true, methodType: Factory Pattern Extend
+POPUP, title: Data leak:, msg: MainAPK: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: true, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: true, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: true, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: true, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: true, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: true, methodType: Factory Pattern Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: true, methodType: Factory Pattern Extend
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: false, methodType: Virtual
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: false, methodType: Static
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: false, methodType: Extended
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
+clname: PathClassLoader, hasCollision: false, hasParent: false, methodType: Interface
+POPUP, title: Data leak:, msg: A: some strings(true 42 666 * -559038737 944260662268981261 0.99 3.141592653589793 Secret)
diff --git a/test_apks/dyn_and_ref/tests/test_apk.py b/test_apks/dyn_and_ref/tests/test_apk.py
new file mode 100644
index 0000000..6c254e1
--- /dev/null
+++ b/test_apks/dyn_and_ref/tests/test_apk.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+
+from pathlib import Path
+import time
+import subprocess
+import os
+
+
+def get_adb() -> str | Path:
+ if "ANDROID_HOME" in os.environ:
+ sdk_path = Path(os.environ["ANDROID_HOME"])
+ else:
+ sdk_path = Path.home() / "Android" / "Sdk"
+ if not sdk_path.exists():
+ return "adb"
+ adb_path = sdk_path / "platform-tools" / "adb"
+ if adb_path.exists():
+ return adb_path
+ else:
+ return "adb"
+
+
+def start_activity(
+ adb: str | Path,
+ activity: str,
+ str_extra: dict[str, str],
+ bool_extra: dict[str, bool],
+):
+ str_extra_args = [
+ c for k, v in str_extra.items() for c in ("--es", k, v.replace(" ", "\\ "))
+ ]
+ bool_extra_args = [
+ c for k, v in bool_extra.items() for c in ("--ez", k, "true" if v else "false")
+ ]
+ print(
+ " ".join(
+ [
+ str(adb),
+ "shell",
+ "am",
+ "start-activity",
+ "-n",
+ activity,
+ *str_extra_args,
+ *bool_extra_args,
+ ]
+ )
+ )
+ subprocess.Popen(
+ [
+ adb,
+ "shell",
+ "am",
+ "start-activity",
+ "-n",
+ activity,
+ *str_extra_args,
+ *bool_extra_args,
+ ]
+ )
+
+
+def kill_app(adb: str | Path, app_id: str):
+ subprocess.Popen([adb, "shell", "am", "force-stop", app_id])
+
+
+def clear_log(adb: str | Path):
+ subprocess.Popen([adb, "logcat", "-c"])
+
+
+def get_log_proc(adb: str | Path, tag: str) -> subprocess.Popen:
+ return subprocess.Popen(
+ [adb, "logcat", "-s", tag, "--format=raw"],
+ encoding="utf-8",
+ stdout=subprocess.PIPE,
+ )
+
+
+def wait_for_tst_log(
+ logs: subprocess.Popen,
+ clname: str,
+ hasCollision: bool,
+ hasParent: bool,
+ methodType: str,
+):
+ hasCollision_p = "true" if hasCollision else "false"
+ hasParent_p = "true" if hasParent else "false"
+ first_line_found = False
+ assert logs.stdout is not None
+ for line in logs.stdout:
+ # print(f"= {line}")
+ # print(f"= {first_line_found=}")
+ if first_line_found and line.startswith("POPUP,"):
+ return
+ if not first_line_found and (
+ f"clname: {clname}," in line
+ and f"hasCollision: {hasCollision_p}," in line
+ and f"hasParent: {hasParent_p},"
+ and f"methodType: {methodType}" in line
+ ):
+ first_line_found = True
+
+
+CLASS_LOADERS = [
+ "DelegateLastClassLoader",
+ "DexClassLoader",
+ "InMemoryDexClassLoader",
+ "PathClassLoader",
+]
+METHOD_TYPES = [
+ "Virtual",
+ "Static",
+ "Extended",
+ "Interface",
+ # "Interface Static",
+ "Factory Pattern Interface",
+ "Factory Pattern Extend",
+]
+COLLISION_OPT = [True, False]
+PARENT_OPT = [True, False]
+
+
+def main():
+ adb = get_adb()
+ clear_log(adb)
+ logs = get_log_proc(adb, "THESEUS")
+ for clname in CLASS_LOADERS:
+ for hasCollision in COLLISION_OPT:
+ for hasParent in PARENT_OPT:
+ for methodType in METHOD_TYPES:
+ if (
+ clname == "DelegateLastClassLoader"
+ and "Factory Pattern" in methodType
+ ):
+ continue
+ if not hasParent and "Factory Pattern" in methodType:
+ continue
+ start_activity(
+ adb,
+ "com.example.theseus.dynandref/.MethodActivity",
+ {
+ "classLoaderName": clname,
+ "methodType": methodType,
+ },
+ {"collision": hasCollision, "parent": hasParent},
+ )
+ wait_for_tst_log(
+ logs,
+ clname,
+ hasCollision,
+ hasParent,
+ methodType,
+ )
+ # kill_app(adb, "com.example.theseus.dynandref")
+ # time.sleep(0.2)
+ # save result afterward:
+ # adb logcat -s THESEUS -d --format=raw > expected_result.txt
+
+
+if __name__ == "__main__":
+ main()