From 5140bfc6a7ad6840f7b0027befbd141c6fb0cecb Mon Sep 17 00:00:00 2001
From: Mahdi Karzari <76250959+QM4RS@users.noreply.github.com>
Date: Sun, 19 Jul 2026 23:33:52 +0330
Subject: [PATCH] feat: deliver first successful FridaBox MVP
Integrate Frida Gadget into BlackBox guest startup, add the host workflow and controller tooling, and validate the complete sample hook flow on ARM64 Android 16.
---
.gitignore | 5 +
ARCHITECTURE.md | 57 +
Bcore/build.gradle | 13 +-
Bcore/consumer-rules.pro | 2 +
.../blackbox/app/BActivityThread.java | 19 +
.../instrumentation/FridaGadgetLoader.java | 50 +
.../instrumentation/GuestRuntimeRegistry.java | 88 +
.../InstrumentationSettings.java | 54 +
.../InstrumentationStatusStore.java | 40 +
.../GuestRuntimeRegistryTest.java | 44 +
README.md | 110 +-
THIRD_PARTY_NOTICES.md | 41 +
app/build.gradle | 95 +-
app/proguard-rules.pro | 4 +-
app/src/main/AndroidManifest.xml | 10 +-
.../blackboxa/fridabox/ApkInspector.java | 53 +
.../blackboxa/fridabox/ApkIntegrity.java | 33 +
.../blackboxa/fridabox/FridaBoxActivity.kt | 423 ++++
.../InstrumentationPreferenceParser.java | 23 +
.../blackboxa/view/main/BlackBoxLoader.kt | 9 +-
.../blackboxa/view/main/WelcomeActivity.kt | 5 +-
.../arm64-v8a/libfrida-gadget.config.so | 11 +
.../main/jniLibs/arm64-v8a/libfrida-gadget.so | Bin 0 -> 25212656 bytes
app/src/main/res/values/strings.xml | 2 +-
.../blackboxa/fridabox/ApkInspectorTest.java | 48 +
.../blackboxa/fridabox/ApkIntegrityTest.java | 15 +
.../InstrumentationPreferenceParserTest.java | 20 +
docs/BASELINE.md | 40 +
docs/BUILDING.md | 54 +
docs/DETECTION_SURFACES.md | 20 +
docs/FRIDA_CONNECTION.md | 38 +
docs/LIMITATIONS.md | 25 +
docs/TEST_RESULTS.md | 70 +
docs/USAGE.md | 27 +
docs/device-validation.log | 163 ++
package-lock.json | 589 +++++
package.json | 10 +
sample-guest/build.gradle | 21 +
sample-guest/src/main/AndroidManifest.xml | 15 +
.../qm4rs/fridabox/sample/MainActivity.java | 28 +
.../fridabox/sample/SampleApplication.java | 21 +
.../com/qm4rs/fridabox/sample/Target.java | 10 +
scripts/dist/guest-bootstrap.js | 1887 +++++++++++++++++
scripts/dist/registry-probe.js | 1887 +++++++++++++++++
scripts/dist/sample-hook.js | 1887 +++++++++++++++++
scripts/guest-bootstrap.js | 75 +
scripts/native-load-monitor.js | 26 +
scripts/registry-probe.js | 28 +
scripts/sample-hook.js | 33 +
settings.gradle | 11 +
tools/attach_guest.py | 258 +++
tools/build_frida_agents.py | 39 +
tools/fetch_frida_gadget.py | 85 +
tools/forward_frida_ports.py | 54 +
tools/frida-gadget-17.16.0.sha256 | 1 +
tools/requirements.txt | 1 +
56 files changed, 8573 insertions(+), 104 deletions(-)
create mode 100644 ARCHITECTURE.md
create mode 100644 Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/FridaGadgetLoader.java
create mode 100644 Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistry.java
create mode 100644 Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationSettings.java
create mode 100644 Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationStatusStore.java
create mode 100644 Bcore/src/test/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistryTest.java
create mode 100644 THIRD_PARTY_NOTICES.md
create mode 100644 app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java
create mode 100644 app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java
create mode 100644 app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt
create mode 100644 app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java
create mode 100644 app/src/main/jniLibs/arm64-v8a/libfrida-gadget.config.so
create mode 100644 app/src/main/jniLibs/arm64-v8a/libfrida-gadget.so
create mode 100644 app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkInspectorTest.java
create mode 100644 app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkIntegrityTest.java
create mode 100644 app/src/test/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParserTest.java
create mode 100644 docs/BASELINE.md
create mode 100644 docs/BUILDING.md
create mode 100644 docs/DETECTION_SURFACES.md
create mode 100644 docs/FRIDA_CONNECTION.md
create mode 100644 docs/LIMITATIONS.md
create mode 100644 docs/TEST_RESULTS.md
create mode 100644 docs/USAGE.md
create mode 100644 docs/device-validation.log
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 sample-guest/build.gradle
create mode 100644 sample-guest/src/main/AndroidManifest.xml
create mode 100644 sample-guest/src/main/java/com/qm4rs/fridabox/sample/MainActivity.java
create mode 100644 sample-guest/src/main/java/com/qm4rs/fridabox/sample/SampleApplication.java
create mode 100644 sample-guest/src/main/java/com/qm4rs/fridabox/sample/Target.java
create mode 100644 scripts/dist/guest-bootstrap.js
create mode 100644 scripts/dist/registry-probe.js
create mode 100644 scripts/dist/sample-hook.js
create mode 100644 scripts/guest-bootstrap.js
create mode 100644 scripts/native-load-monitor.js
create mode 100644 scripts/registry-probe.js
create mode 100644 scripts/sample-hook.js
create mode 100644 tools/attach_guest.py
create mode 100644 tools/build_frida_agents.py
create mode 100644 tools/fetch_frida_gadget.py
create mode 100644 tools/forward_frida_ports.py
create mode 100644 tools/frida-gadget-17.16.0.sha256
create mode 100644 tools/requirements.txt
diff --git a/.gitignore b/.gitignore
index 0d8cd69..286cd3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,8 +17,13 @@
*.logcat
.vscode
/build
+**/build/
/captures
.externalNativeBuild
.cxx
local.properties
/app/release/
+__pycache__/
+*.pyc
+node_modules/
+.npm-cache/
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000..609c379
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,57 @@
+# Architecture
+
+FridaBox extends the existing BlackBox virtual package, process, Binder, file,
+identity, signature, and lifecycle implementation. It does not introduce a
+second plugin framework and never creates a replacement `DexClassLoader` for a
+guest.
+
+```text
+Host launcher process
+ |
+ | import original APK
+ v
+BlackBox virtual package manager
+ |
+ | allocate :pN virtual process
+ v
+BActivityThread.handleBindApplication()
+ |
+ | create guest Context / LoadedApk / ClassLoader
+ | initialize virtual runtime and IO redirection
+ | populate GuestRuntimeRegistry
+ | load Frida Gadget and wait
+ v
+Frida controller attaches
+ |
+ | select guest ClassLoader
+ | install Java/native hooks
+ v
+Guest makeApplication()
+ |
+ v
+Guest Application.onCreate()
+ |
+ v
+Guest Activity
+```
+
+## Runtime boundary
+
+`GuestRuntimeRegistry` is volatile, process-local state. Each normal BlackBox
+virtual process populates it after `VirtualRuntime.setupRuntime`, `NativeCore.init`,
+and IO redirection, using the `LoadedApk` ClassLoader. `FridaGadgetLoader` then
+performs one synchronized `System.loadLibrary("frida-gadget")` attempt in that
+Linux process. The static Gadget configuration pauses that call until a
+controller connects. Only afterward does BlackBox call `makeApplication`.
+
+The host status screen uses a small SharedPreferences snapshot because the host
+launcher cannot directly read another process's static registry. The Frida
+controller reads the authoritative process-local registry through Java.
+
+## Import boundary
+
+The host copies a document-provider stream once into `files/imported-apks`,
+computes SHA-256 while copying, inspects the ZIP ABI entries, parses package
+metadata, verifies the stored hash, marks the file read-only, and passes the path
+only to BlackBox's virtual package manager. No real package installer Intent or
+PackageInstaller session is used.
diff --git a/Bcore/build.gradle b/Bcore/build.gradle
index 857d57e..7eb4117 100644
--- a/Bcore/build.gradle
+++ b/Bcore/build.gradle
@@ -1,9 +1,15 @@
apply plugin: 'com.android.library'
+def fridaBoxNdkProjectDir = System.getenv('FRIDABOX_NDK_PROJECT_DIR') ?: project.projectDir.absolutePath
+if (System.getenv('FRIDABOX_NDK_PROJECT_DIR')) {
+ layout.buildDirectory.set(file("${fridaBoxNdkProjectDir}/build"))
+}
+
android {
namespace 'top.niunaijun.blackbox'
compileSdk rootProject.ext.compileSdkVersion
+ ndkVersion = "29.0.14206865"
aidlPackagedList "android/app/IServiceConnection.aidl"
@@ -19,8 +25,7 @@ android {
consumerProguardFiles "consumer-rules.pro"
ndk {
-
- abiFilters 'arm64-v8a' , 'armeabi-v7a'
+ abiFilters 'arm64-v8a'
}
}
@@ -33,9 +38,8 @@ android {
externalNativeBuild {
ndkBuild {
- path 'src/main/cpp/Android.mk'
+ path file("${fridaBoxNdkProjectDir}/src/main/cpp/Android.mk")
}
- ndkVersion = "29.0.13846066"
}
compileOptions {
@@ -106,6 +110,7 @@ dependencies {
implementation 'com.moandjiezana.toml:toml4j:0.7.2'
implementation 'com.github.tiann:FreeReflection:3.2.2'
+ testImplementation libs.junit
diff --git a/Bcore/consumer-rules.pro b/Bcore/consumer-rules.pro
index 0d7cb9b..c3aba30 100644
--- a/Bcore/consumer-rules.pro
+++ b/Bcore/consumer-rules.pro
@@ -26,3 +26,5 @@
-keep class android.** {*; }
-keep class com.android.** {*; }
+-keep class top.niunaijun.blackbox.instrumentation.GuestRuntimeRegistry { public static *; }
+-keep class top.niunaijun.blackbox.instrumentation.FridaGadgetLoader { public static *; }
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
index 61b9d7f..13d7a2b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
@@ -85,6 +85,10 @@ import top.niunaijun.blackbox.utils.compat.BuildCompat;
import top.niunaijun.blackbox.utils.compat.ContextCompat;
import top.niunaijun.blackbox.utils.compat.StrictModeCompat;
import top.niunaijun.blackbox.core.system.JarManager;
+import top.niunaijun.blackbox.instrumentation.FridaGadgetLoader;
+import top.niunaijun.blackbox.instrumentation.GuestRuntimeRegistry;
+import top.niunaijun.blackbox.instrumentation.InstrumentationSettings;
+import top.niunaijun.blackbox.instrumentation.InstrumentationStatusStore;
public class BActivityThread extends IBActivityThread.Stub {
@@ -403,6 +407,21 @@ public class BActivityThread extends IBActivityThread.Stub {
assert packageContext != null;
IOCore.get().enableRedirect(packageContext);
+ ClassLoader guestClassLoader = BRLoadedApk.get(loadedApk).getClassLoader();
+ boolean instrumentationEnabled = InstrumentationSettings.isEnabledForPackage(packageName);
+ GuestRuntimeRegistry.initialize(packageName, processName, getUserId(), getAppPid(),
+ applicationInfo, guestClassLoader, instrumentationEnabled);
+ InstrumentationStatusStore.recordBinding();
+ if (guestClassLoader != null) {
+ try {
+ Thread.currentThread().setContextClassLoader(guestClassLoader);
+ } catch (SecurityException error) {
+ GuestRuntimeRegistry.setLastError(error);
+ Slog.w(TAG, "Unable to set guest context ClassLoader: " + error.getMessage());
+ }
+ }
+ FridaGadgetLoader.loadIfEnabled();
+
AppBindData bindData = new AppBindData();
bindData.appInfo = applicationInfo;
bindData.processName = processName;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/FridaGadgetLoader.java b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/FridaGadgetLoader.java
new file mode 100644
index 0000000..68cb9f7
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/FridaGadgetLoader.java
@@ -0,0 +1,50 @@
+package top.niunaijun.blackbox.instrumentation;
+
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/** Loads Frida Gadget at most once in the current Linux process. */
+public final class FridaGadgetLoader {
+ private static final String TAG = "FridaBox.Gadget";
+ private static final AtomicBoolean ATTEMPTED = new AtomicBoolean(false);
+ private static final Object LOAD_LOCK = new Object();
+ private static volatile boolean loaded;
+
+ private FridaGadgetLoader() {
+ }
+
+ public static boolean loadIfEnabled() {
+ if (!GuestRuntimeRegistry.isInstrumentationEnabled()) {
+ Log.i(TAG, "Instrumentation disabled for this guest process");
+ return false;
+ }
+ if (loaded) return true;
+ synchronized (LOAD_LOCK) {
+ if (loaded) return true;
+ if (!ATTEMPTED.compareAndSet(false, true)) return false;
+ try {
+ InstrumentationStatusStore.recordBinding();
+ Log.i(TAG, "Loading Frida Gadget for " + GuestRuntimeRegistry.getGuestProcessName());
+ System.loadLibrary("frida-gadget");
+ loaded = true;
+ InstrumentationStatusStore.recordLoaded();
+ Log.i(TAG, "Frida Gadget loaded");
+ return true;
+ } catch (UnsatisfiedLinkError | SecurityException error) {
+ GuestRuntimeRegistry.setLastError(error);
+ InstrumentationStatusStore.recordError(GuestRuntimeRegistry.getLastError());
+ Log.e(TAG, "Frida Gadget load failed; guest will continue", error);
+ } catch (Throwable error) {
+ GuestRuntimeRegistry.setLastError(error);
+ InstrumentationStatusStore.recordError(GuestRuntimeRegistry.getLastError());
+ Log.e(TAG, "Unexpected Frida Gadget initialization failure; guest will continue", error);
+ }
+ return false;
+ }
+ }
+
+ public static boolean isLoaded() {
+ return loaded;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistry.java b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistry.java
new file mode 100644
index 0000000..ae78306
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistry.java
@@ -0,0 +1,88 @@
+package top.niunaijun.blackbox.instrumentation;
+
+import android.content.pm.ApplicationInfo;
+
+/** Process-local guest metadata exposed to Frida scripts. */
+public final class GuestRuntimeRegistry {
+ private static volatile String guestPackageName;
+ private static volatile String guestProcessName;
+ private static volatile int guestUserId = -1;
+ private static volatile int virtualProcessId = -1;
+ private static volatile ApplicationInfo guestApplicationInfo;
+ private static volatile ClassLoader guestClassLoader;
+ private static volatile String guestSourceDir;
+ private static volatile boolean instrumentationEnabled;
+ private static volatile String lastError;
+ private static volatile long initializationTimestamp;
+
+ private GuestRuntimeRegistry() {
+ }
+
+ public static synchronized void initialize(String packageName, String processName,
+ int userId, int processId,
+ ApplicationInfo applicationInfo,
+ ClassLoader classLoader,
+ boolean enabled) {
+ guestPackageName = packageName;
+ guestProcessName = processName;
+ guestUserId = userId;
+ virtualProcessId = processId;
+ guestApplicationInfo = applicationInfo;
+ guestClassLoader = classLoader;
+ guestSourceDir = applicationInfo == null ? null : applicationInfo.sourceDir;
+ instrumentationEnabled = enabled;
+ lastError = null;
+ initializationTimestamp = System.currentTimeMillis();
+ }
+
+ public static synchronized void clear() {
+ guestPackageName = null;
+ guestProcessName = null;
+ guestUserId = -1;
+ virtualProcessId = -1;
+ guestApplicationInfo = null;
+ guestClassLoader = null;
+ guestSourceDir = null;
+ instrumentationEnabled = false;
+ lastError = null;
+ initializationTimestamp = 0L;
+ }
+
+ public static String getGuestPackageName() { return guestPackageName; }
+ public static String getGuestProcessName() { return guestProcessName; }
+ public static int getGuestUserId() { return guestUserId; }
+ public static int getVirtualProcessId() { return virtualProcessId; }
+ public static ApplicationInfo getGuestApplicationInfo() { return guestApplicationInfo; }
+ public static ClassLoader getGuestClassLoader() { return guestClassLoader; }
+ public static String getGuestSourceDir() { return guestSourceDir; }
+ public static boolean isInstrumentationEnabled() { return instrumentationEnabled; }
+ public static String getLastError() { return lastError; }
+ public static long getInitializationTimestamp() { return initializationTimestamp; }
+
+ public static void setLastError(Throwable error) {
+ lastError = error == null ? null : error.getClass().getSimpleName() + ": " + error.getMessage();
+ }
+
+ public static void setLastError(String error) {
+ lastError = error;
+ }
+
+ private static String quote(String value) {
+ if (value == null) return "null";
+ return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"")
+ .replace("\n", "\\n").replace("\r", "\\r") + "\"";
+ }
+
+ public static String describe() {
+ return "{" +
+ "\"package\":" + quote(guestPackageName) + ',' +
+ "\"process\":" + quote(guestProcessName) + ',' +
+ "\"userId\":" + guestUserId + ',' +
+ "\"virtualProcessId\":" + virtualProcessId + ',' +
+ "\"sourceDir\":" + quote(guestSourceDir) + ',' +
+ "\"instrumentationEnabled\":" + instrumentationEnabled + ',' +
+ "\"lastError\":" + quote(lastError) + ',' +
+ "\"initializedAt\":" + initializationTimestamp +
+ '}';
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationSettings.java b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationSettings.java
new file mode 100644
index 0000000..be9ae63
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationSettings.java
@@ -0,0 +1,54 @@
+package top.niunaijun.blackbox.instrumentation;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+
+/** Shared host preferences read independently by each virtual process. */
+public final class InstrumentationSettings {
+ public static final String PREFERENCES = "fridabox_instrumentation";
+ public static final String KEY_ENABLED = "instrumentation_enabled";
+ public static final String KEY_BASE_PORT = "frida_base_port";
+ public static final String KEY_SCAN_COUNT = "frida_port_scan_count";
+ public static final String KEY_ADVANCED_LOGS = "show_advanced_logs";
+ private static final String PACKAGE_PREFIX = "package_enabled_";
+
+ private InstrumentationSettings() {
+ }
+
+ private static SharedPreferences preferences() {
+ Context context = BlackBoxCore.getContext();
+ return context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
+ }
+
+ public static boolean isGloballyEnabled() {
+ return preferences().getBoolean(KEY_ENABLED, true);
+ }
+
+ public static boolean isEnabledForPackage(String packageName) {
+ SharedPreferences preferences = preferences();
+ return preferences.getBoolean(KEY_ENABLED, true)
+ && preferences.getBoolean(PACKAGE_PREFIX + packageName, true);
+ }
+
+ public static void setEnabledForPackage(String packageName, boolean enabled) {
+ preferences().edit().putBoolean(PACKAGE_PREFIX + packageName, enabled).commit();
+ }
+
+ public static int getBasePort() {
+ return clamp(preferences().getInt(KEY_BASE_PORT, 27042), 1024, 65535, 27042);
+ }
+
+ public static int getPortScanCount() {
+ return clamp(preferences().getInt(KEY_SCAN_COUNT, 32), 1, 128, 32);
+ }
+
+ public static boolean showAdvancedLogs() {
+ return preferences().getBoolean(KEY_ADVANCED_LOGS, false);
+ }
+
+ static int clamp(int value, int minimum, int maximum, int fallback) {
+ return value < minimum || value > maximum ? fallback : value;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationStatusStore.java b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationStatusStore.java
new file mode 100644
index 0000000..1ae046e
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/instrumentation/InstrumentationStatusStore.java
@@ -0,0 +1,40 @@
+package top.niunaijun.blackbox.instrumentation;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+
+/** Small cross-process status snapshot for the host runtime screen. */
+public final class InstrumentationStatusStore {
+ private InstrumentationStatusStore() {
+ }
+
+ private static SharedPreferences preferences() {
+ return BlackBoxCore.getContext().getSharedPreferences(
+ InstrumentationSettings.PREFERENCES, Context.MODE_PRIVATE);
+ }
+
+ public static void recordBinding() {
+ String packageName = GuestRuntimeRegistry.getGuestPackageName();
+ preferences().edit()
+ .putString("runtime_package", packageName)
+ .putString("runtime_process", GuestRuntimeRegistry.getGuestProcessName())
+ .putInt("runtime_vpid", GuestRuntimeRegistry.getVirtualProcessId())
+ .putString("runtime_source", GuestRuntimeRegistry.getGuestSourceDir())
+ .putBoolean("runtime_enabled", GuestRuntimeRegistry.isInstrumentationEnabled())
+ .putString("runtime_state", GuestRuntimeRegistry.isInstrumentationEnabled()
+ ? "waiting_for_attach" : "disabled")
+ .putString("runtime_error", null)
+ .putLong("runtime_timestamp", GuestRuntimeRegistry.getInitializationTimestamp())
+ .commit();
+ }
+
+ public static void recordLoaded() {
+ preferences().edit().putString("runtime_state", "loaded").putString("runtime_error", null).commit();
+ }
+
+ public static void recordError(String error) {
+ preferences().edit().putString("runtime_state", "failed").putString("runtime_error", error).commit();
+ }
+}
diff --git a/Bcore/src/test/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistryTest.java b/Bcore/src/test/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistryTest.java
new file mode 100644
index 0000000..63d950d
--- /dev/null
+++ b/Bcore/src/test/java/top/niunaijun/blackbox/instrumentation/GuestRuntimeRegistryTest.java
@@ -0,0 +1,44 @@
+package top.niunaijun.blackbox.instrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.content.pm.ApplicationInfo;
+
+import org.junit.After;
+import org.junit.Test;
+
+public class GuestRuntimeRegistryTest {
+ @After
+ public void clearRegistry() {
+ GuestRuntimeRegistry.clear();
+ }
+
+ @Test
+ public void initializeReplacesProcessLocalSnapshot() {
+ ApplicationInfo info = new ApplicationInfo();
+ info.sourceDir = "/private/original.apk";
+ ClassLoader loader = getClass().getClassLoader();
+ GuestRuntimeRegistry.initialize("sample.one", "sample.one:remote", 3, 7, info, loader, true);
+
+ assertEquals("sample.one", GuestRuntimeRegistry.getGuestPackageName());
+ assertEquals("sample.one:remote", GuestRuntimeRegistry.getGuestProcessName());
+ assertEquals(3, GuestRuntimeRegistry.getGuestUserId());
+ assertEquals(7, GuestRuntimeRegistry.getVirtualProcessId());
+ assertSame(loader, GuestRuntimeRegistry.getGuestClassLoader());
+ assertEquals("/private/original.apk", GuestRuntimeRegistry.getGuestSourceDir());
+ assertTrue(GuestRuntimeRegistry.isInstrumentationEnabled());
+ assertTrue(GuestRuntimeRegistry.describe().contains("\"package\":\"sample.one\""));
+ }
+
+ @Test
+ public void clearRemovesPriorGuest() {
+ GuestRuntimeRegistry.initialize("sample", "sample", 0, 1, null, null, true);
+ GuestRuntimeRegistry.clear();
+ assertEquals(null, GuestRuntimeRegistry.getGuestPackageName());
+ assertEquals(-1, GuestRuntimeRegistry.getGuestUserId());
+ assertFalse(GuestRuntimeRegistry.isInstrumentationEnabled());
+ }
+}
diff --git a/README.md b/README.md
index 72cbedd..d4ac61d 100644
--- a/README.md
+++ b/README.md
@@ -1,89 +1,35 @@
-# BlackBox - Virtual Engine
+# FridaBox
-
-
-
+FridaBox is an authorized mobile-security research MVP that runs an original,
+unmodified APK inside BlackBox virtual processes and loads Frida Gadget before
+the guest `Application` is created. It requires no root, frida-server, Magisk,
+Zygisk, system-image changes, real PackageManager installation, APK patching,
+repacking, or resigning.
-BlackBox is a virtual engine that allows you to clone and run virtual applications on Android devices without installing APKs. This project works on Android 5.0 to 14.0+ and supports multiple architectures (ARM64, ARMv7, x86).
+The foundation is `ALEX5402/NewBlackbox` commit
+`89b59836c66f173756a4ae258cf379a957649820`. The host application ID is
+`com.qm4rs.fridabox`; existing engine namespaces remain unchanged.
-## Overview
+## MVP capabilities
-This enhanced edition includes bug fixes, stability improvements, and Android 14+ compatibility tailored for modern devices.
+- SAF import of one base APK into app-private, read-only storage.
+- SHA-256 verification before and after BlackBox virtual installation.
+- ARM64 native-library inspection; pure Java/Kotlin guests are accepted and
+ native guests without `arm64-v8a` are rejected.
+- Per-guest instrumented or non-instrumented launches with virtual process stop
+ before mode changes.
+- Frida Gadget 17.16.0 bound to loopback, default port 27042, with conflict
+ fallback and `on_load=wait` for pre-`Application.onCreate()` hooks.
+- Process-local guest registry and controller-side ClassLoader selection.
+- Debug sample guest proving `Target.add(2, 3)` can be replaced with `1337`.
+- Reproducibly bundled Frida 17 Java agents using pinned `frida-java-bridge`
+ 7.0.13 and `frida-compile` 19.0.5.
-### Key Features
+Start with [docs/BUILDING.md](docs/BUILDING.md), [docs/USAGE.md](docs/USAGE.md),
+and [docs/FRIDA_CONNECTION.md](docs/FRIDA_CONNECTION.md).
-* **Virtual App Cloning**: Run multiple instances of applications.
-* **Sandboxed Environment**: Isolated process execution.
-* **No Root Required**: Runs entirely in userspace.
-* **Multi-Architecture**: Support for 32-bit and 64-bit apps.
-* **Device Spoofing**: Modify device information for virtual apps.
-* **Fake Location**: Spoof GPS coordinates.
+FridaBox is not undetectable. See [docs/DETECTION_SURFACES.md](docs/DETECTION_SURFACES.md)
+and [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
-## Requirements
-
-* **Android Version**: Android 5.0 (API 21) or higher.
-* **RAM**: 2GB minimum recommended.
-* **Architecture**: ARMv7a, ARM64-v8a, x86.
-
-## Build Instructions
-
-### Prerequisites
-* Android Studio (Arctic Fox or newer)
-* JDK 17
-* Android SDK 34+
-* NDK (Version 29.0.13846066)
-
-### Building from Source
-
-```bash
-# Clone the repository
-git clone https://github.com/your-repo/NewBlackbox.git
-cd NewBlackbox
-
-# Build Debug APK
-./gradlew assembleDebug
-
-# Build Release APK
-./gradlew assembleRelease
-```
-
-## Integration
-
-To use BlackBox Core in your own project, add the AAR dependency:
-
-```gradle
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.aar"])
-}
-```
-
-Refer to `Docs.md` for detailed API documentation.
-
-## Troubleshooting
-
-* **App Crashes**: Check logcat for UID mismatches or permission errors.
-* **Installation Failures**: Verify potential architecture mismatches or storage permissions.
-* **Android 15**: Ensure you are using the latest build which handles stricter security policies.
-
-## Credits
-
-* **Main Developer**: ALEX502
-* **Original Framework**: VirtualApp, VirtualAPK
-* **Native Hooks**: Dobby, xDL
-* **Reflection**: BlackReflection, FreeReflection
-
-## License
-
-Copyright 2022 BlackBox
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+The complete Android 16 device transcript is in
+[docs/device-validation.log](docs/device-validation.log).
diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md
new file mode 100644
index 0000000..fb3cf91
--- /dev/null
+++ b/THIRD_PARTY_NOTICES.md
@@ -0,0 +1,41 @@
+# Third-party notices
+
+## NewBlackbox / BlackBox
+
+FridaBox is based on `ALEX5402/NewBlackbox` commit
+`89b59836c66f173756a4ae258cf379a957649820`. The foundation repository includes
+an Apache License 2.0 notice; see the repository root `LICENSE` file.
+
+## Frida Gadget 17.16.0
+
+- Origin: `https://github.com/frida/frida/releases/tag/17.16.0`
+- Asset: `frida-gadget-17.16.0-android-arm64.so.xz`
+- Installed filename: `libfrida-gadget.so`
+- SHA-256 after XZ decompression:
+ `6bf149e5d1c5ec701e7b822cab57bb243f1c2a03318fa974fe373ee711a9ed9e`
+- License: wxWindows Library Licence, Version 3.1, as stated by the official
+ Frida 17.16.0 `COPYING` file.
+
+The wxWindows licence permits redistribution/modification under GNU Library
+General Public Licence version 2 or later and includes an exception permitting
+binary object code versions of works based on the library to be used, copied,
+linked, modified, and distributed under the distributor's own terms. The full
+authoritative text is available at
+`https://github.com/frida/frida/blob/17.16.0/COPYING`.
+
+Frida is copyright its respective contributors. FridaBox makes no claim of
+ownership over Frida Gadget.
+
+## Frida Java bridge and agent compiler
+
+The compiled JavaScript agents under `scripts/dist/` include
+`frida-java-bridge` 7.0.13. They are built with `frida-compile` 19.0.5.
+
+- Java bridge origin: `https://github.com/frida/frida-java-bridge`
+- Compiler origin: `https://github.com/frida/frida-compile`
+- License: LGPL-2.0 with the wxWindows Library Licence 3.1 exception, as
+ declared by the respective official packages.
+
+The authoritative licence text and exception are the same wxWindows Library
+Licence described above. Exact package versions and dependency integrity hashes
+are preserved in `package-lock.json`.
diff --git a/app/build.gradle b/app/build.gradle
index a5ce1ad..fb8fb77 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,9 +7,9 @@ android {
namespace 'top.niunaijun.blackboxa'
compileSdk rootProject.ext.compileSdkVersion
- ndkVersion = "29.0.13846066"
+ ndkVersion = "29.0.14206865"
defaultConfig {
- applicationId "top.niunaijun.blackbox"
+ applicationId "com.qm4rs.fridabox"
minSdk rootProject.ext.minSdk
targetSdk rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
@@ -22,8 +22,8 @@ android {
enable true
reset()
- include 'armeabi-v7a', "arm64-v8a"
- universalApk true
+ include "arm64-v8a"
+ universalApk false
}
}
}
@@ -41,6 +41,10 @@ android {
}
buildFeatures {
viewBinding true
+ buildConfig true
+ }
+ sourceSets {
+ debug.assets.srcDir("$buildDir/generated/demoGuestAssets")
}
kotlinOptions {
jvmTarget = '21'
@@ -48,6 +52,8 @@ android {
packaging {
jniLibs {
excludes.add("**/libandroidx.graphics.path.so")
+ useLegacyPackaging true
+ keepDebugSymbols.add("**/libfrida-gadget.config.so")
}
resources {
excludes.add("**/libandroidx.graphics.path.so")
@@ -55,9 +61,88 @@ android {
}
applicationVariants.configureEach { variant ->
variant.outputs.configureEach { output ->
- output.outputFileName = "BlackBox_${variant.versionName}_${output.baseName}.apk"
+ output.outputFileName = "FridaBox_${variant.versionName}_${output.baseName}.apk"
}
}
+ lint {
+ abortOnError false
+ checkReleaseBuilds false
+ }
+}
+
+tasks.register("copyDemoGuestDebug", Copy) {
+ dependsOn(":sample-guest:assembleDebug")
+ from(project(":sample-guest").layout.buildDirectory.file("outputs/apk/debug/sample-guest-debug.apk"))
+ into(layout.buildDirectory.dir("generated/demoGuestAssets/demo"))
+ rename { "sample-guest.apk" }
+}
+tasks.matching { it.name == "mergeDebugAssets" }.configureEach { dependsOn("copyDemoGuestDebug") }
+tasks.matching { it.name.toLowerCase().contains("debug") && it.name.toLowerCase().contains("lint") }
+ .configureEach { dependsOn("copyDemoGuestDebug") }
+
+def fridaGadget = file("src/main/jniLibs/arm64-v8a/libfrida-gadget.so")
+def fridaGadgetConfig = file("src/main/jniLibs/arm64-v8a/libfrida-gadget.config.so")
+tasks.register("verifyFridaGadget") {
+ inputs.files(fridaGadget, fridaGadgetConfig)
+ doLast {
+ if (!fridaGadget.isFile()) {
+ throw new GradleException("Frida Gadget 17.16.0 is missing. Run: python tools/fetch_frida_gadget.py")
+ }
+ if (!fridaGadgetConfig.isFile()) {
+ throw new GradleException("Frida Gadget configuration is missing: ${fridaGadgetConfig}")
+ }
+ def digest = java.security.MessageDigest.getInstance("SHA-256")
+ .digest(fridaGadget.bytes).collect { String.format("%02x", it & 0xff) }.join()
+ if (digest != "6bf149e5d1c5ec701e7b822cab57bb243f1c2a03318fa974fe373ee711a9ed9e") {
+ throw new GradleException("Frida Gadget 17.16.0 SHA-256 mismatch: ${digest}")
+ }
+ def config = new groovy.json.JsonSlurper().parse(fridaGadgetConfig)
+ if (config.interaction?.address != "127.0.0.1" || config.interaction?.on_load != "wait") {
+ throw new GradleException("Unsafe or invalid Frida Gadget configuration")
+ }
+ }
+}
+tasks.matching { it.name == "preBuild" }.configureEach { dependsOn("verifyFridaGadget") }
+
+tasks.register("verifyDebugApkFridaPackaging") {
+ dependsOn("assembleDebug")
+ doLast {
+ def apk = fileTree("$buildDir/outputs/apk/debug").matching { include("*.apk") }.singleFile
+ def entries = zipTree(apk).matching {
+ include("lib/arm64-v8a/libfrida-gadget.so")
+ include("lib/arm64-v8a/libfrida-gadget.config.so")
+ }.files.collect { it.name }.toSet()
+ if (!entries.contains("libfrida-gadget.so") || !entries.contains("libfrida-gadget.config.so")) {
+ throw new GradleException("Debug APK does not contain both Frida Gadget files")
+ }
+ }
+}
+
+tasks.register("verifyInstrumentationOrdering") {
+ doLast {
+ def source = project(":Bcore").file("src/main/java/top/niunaijun/blackbox/app/BActivityThread.java").text
+ def loader = source.indexOf("FridaGadgetLoader.loadIfEnabled()")
+ def makeApplication = source.indexOf("makeApplication(", loader)
+ if (loader < 0 || makeApplication < 0 || loader >= makeApplication) {
+ throw new GradleException("Frida Gadget loader must execute before guest makeApplication")
+ }
+ }
+}
+
+tasks.register("verifyDemoGuestUnmodified") {
+ dependsOn("copyDemoGuestDebug")
+ doLast {
+ def source = project(":sample-guest").layout.buildDirectory.file("outputs/apk/debug/sample-guest-debug.apk").get().asFile
+ def embedded = layout.buildDirectory.file("generated/demoGuestAssets/demo/sample-guest.apk").get().asFile
+ if (!java.util.Arrays.equals(java.security.MessageDigest.getInstance("SHA-256").digest(source.bytes),
+ java.security.MessageDigest.getInstance("SHA-256").digest(embedded.bytes))) {
+ throw new GradleException("Embedded sample APK differs from generated sample APK")
+ }
+ }
+}
+
+tasks.named("check").configure {
+ dependsOn("verifyDebugApkFridaPackaging", "verifyInstrumentationOrdering", "verifyDemoGuestUnmodified")
}
dependencies {
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index f4e5465..98441e5 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -41,4 +41,6 @@
@top.niunaijun.blackreflection.annotation.BMethodCheckNotProcess.* ;
@top.niunaijun.blackreflection.annotation.BConstructor.* ;
@top.niunaijun.blackreflection.annotation.BConstructorNotProcess.* ;
-}
\ No newline at end of file
+}
+-keep class top.niunaijun.blackbox.instrumentation.GuestRuntimeRegistry { public static *; }
+-keep class top.niunaijun.blackbox.instrumentation.FridaGadgetLoader { public static *; }
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 66ec39f..477102b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,7 +14,9 @@
+
@@ -53,4 +59,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java b/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java
new file mode 100644
index 0000000..472afb2
--- /dev/null
+++ b/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java
@@ -0,0 +1,53 @@
+package top.niunaijun.blackboxa.fridabox;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public final class ApkInspector {
+ private ApkInspector() {
+ }
+
+ public static Result inspect(File apk) throws IOException {
+ Set abis = new LinkedHashSet<>();
+ boolean hasNativeLibraries = false;
+ try (ZipFile archive = new ZipFile(apk)) {
+ if (archive.getEntry("AndroidManifest.xml") == null) {
+ throw new IOException("The selected file has no AndroidManifest.xml");
+ }
+ for (ZipEntry entry : Collections.list(archive.entries())) {
+ String name = entry.getName();
+ if (!entry.isDirectory() && name.startsWith("lib/") && name.endsWith(".so")) {
+ String[] parts = name.split("/", 3);
+ if (parts.length == 3) {
+ hasNativeLibraries = true;
+ abis.add(parts[1]);
+ }
+ }
+ }
+ }
+ boolean supported = !hasNativeLibraries || abis.contains("arm64-v8a");
+ return new Result(hasNativeLibraries, supported, abis);
+ }
+
+ public static final class Result {
+ public final boolean hasNativeLibraries;
+ public final boolean supported;
+ public final Set abis;
+
+ Result(boolean hasNativeLibraries, boolean supported, Set abis) {
+ this.hasNativeLibraries = hasNativeLibraries;
+ this.supported = supported;
+ this.abis = Collections.unmodifiableSet(new LinkedHashSet<>(abis));
+ }
+
+ public String description() {
+ if (!hasNativeLibraries) return "Pure Java/Kotlin (accepted)";
+ return supported ? "ARM64 supported: " + abis : "Rejected; no arm64-v8a: " + abis;
+ }
+ }
+}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java b/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java
new file mode 100644
index 0000000..7152c57
--- /dev/null
+++ b/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java
@@ -0,0 +1,33 @@
+package top.niunaijun.blackboxa.fridabox;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public final class ApkIntegrity {
+ private ApkIntegrity() {
+ }
+
+ public static String sha256(File file) throws IOException {
+ try (InputStream stream = new FileInputStream(file)) {
+ return sha256(stream);
+ }
+ }
+
+ public static String sha256(InputStream stream) throws IOException {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ byte[] buffer = new byte[64 * 1024];
+ int count;
+ while ((count = stream.read(buffer)) != -1) digest.update(buffer, 0, count);
+ StringBuilder result = new StringBuilder(64);
+ for (byte value : digest.digest()) result.append(String.format("%02x", value & 0xff));
+ return result.toString();
+ } catch (NoSuchAlgorithmException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt
new file mode 100644
index 0000000..9315288
--- /dev/null
+++ b/app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt
@@ -0,0 +1,423 @@
+package top.niunaijun.blackboxa.fridabox
+
+import android.app.AlertDialog
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.graphics.Typeface
+import android.net.Uri
+import android.os.Bundle
+import android.provider.OpenableColumns
+import android.text.InputType
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.HorizontalScrollView
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.ScrollView
+import android.widget.Switch
+import android.widget.TextView
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import top.niunaijun.blackbox.BlackBoxCore
+import top.niunaijun.blackbox.instrumentation.InstrumentationSettings
+import top.niunaijun.blackboxa.BuildConfig
+import java.io.File
+import java.io.FileOutputStream
+import java.security.MessageDigest
+import java.util.Locale
+import java.util.concurrent.Executors
+
+/** Minimal host UI for APK import, virtual launch, runtime status, and settings. */
+class FridaBoxActivity : AppCompatActivity() {
+ private val worker = Executors.newSingleThreadExecutor()
+ private lateinit var content: LinearLayout
+ private val settings: SharedPreferences by lazy {
+ getSharedPreferences(InstrumentationSettings.PREFERENCES, Context.MODE_PRIVATE)
+ }
+ private val metadata: SharedPreferences by lazy {
+ getSharedPreferences("fridabox_imports", Context.MODE_PRIVATE)
+ }
+
+ private val apkPicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
+ if (uri != null) importApk(uri)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ showHome()
+ }
+
+ override fun onDestroy() {
+ worker.shutdown()
+ super.onDestroy()
+ }
+
+ private fun baseScreen(title: String): LinearLayout {
+ val root = LinearLayout(this).apply {
+ orientation = LinearLayout.VERTICAL
+ setPadding(dp(16), dp(12), dp(16), dp(12))
+ setBackgroundColor(0xfff7f8fa.toInt())
+ }
+ val header = LinearLayout(this).apply {
+ orientation = LinearLayout.HORIZONTAL
+ gravity = Gravity.CENTER_VERTICAL
+ }
+ header.addView(TextView(this).apply {
+ text = title
+ textSize = 24f
+ setTypeface(typeface, Typeface.BOLD)
+ }, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f))
+ header.addView(Button(this).apply {
+ text = "Home"
+ setOnClickListener { showHome() }
+ })
+ header.addView(Button(this).apply {
+ text = "Runtime"
+ setOnClickListener { showRuntime() }
+ })
+ header.addView(Button(this).apply {
+ text = "Settings"
+ setOnClickListener { showSettings() }
+ })
+ root.addView(header)
+ content = LinearLayout(this).apply {
+ orientation = LinearLayout.VERTICAL
+ setPadding(0, dp(12), 0, dp(24))
+ }
+ root.addView(ScrollView(this).apply { addView(content) }, LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f))
+ setContentView(root)
+ return content
+ }
+
+ private fun showHome() {
+ baseScreen("FridaBox")
+ content.addView(TextView(this).apply {
+ text = "Non-root Android application virtualization with per-guest Frida Gadget instrumentation."
+ textSize = 16f
+ })
+ content.addView(Button(this).apply {
+ text = "Import APK"
+ setOnClickListener { apkPicker.launch(arrayOf("application/vnd.android.package-archive", "application/octet-stream")) }
+ })
+ if (BuildConfig.DEBUG) {
+ content.addView(Button(this).apply {
+ text = "Install demo guest"
+ setOnClickListener { installDemoGuest() }
+ })
+ }
+ content.addView(sectionTitle("Virtual applications"))
+ refreshApps()
+ }
+
+ private fun refreshApps() {
+ val marker = TextView(this).apply { text = "Loading…" }
+ content.addView(marker)
+ worker.execute {
+ val packages = try {
+ BlackBoxCore.get().getInstalledPackages(PackageManager.GET_META_DATA, 0)
+ } catch (error: Throwable) {
+ runOnUiThread { marker.text = "Unable to read virtual packages: ${error.message}" }
+ return@execute
+ }
+ runOnUiThread {
+ content.removeView(marker)
+ if (packages.isEmpty()) {
+ content.addView(TextView(this).apply { text = "No APKs imported yet." })
+ } else {
+ packages.sortedBy { it.packageName }.forEach { addAppCard(it) }
+ }
+ }
+ }
+ }
+
+ private fun addAppCard(info: PackageInfo) {
+ val card = LinearLayout(this).apply {
+ orientation = LinearLayout.VERTICAL
+ setPadding(dp(12), dp(12), dp(12), dp(12))
+ setBackgroundColor(0xffffffff.toInt())
+ }
+ val heading = LinearLayout(this).apply { orientation = LinearLayout.HORIZONTAL }
+ heading.addView(ImageView(this).apply {
+ try { setImageDrawable(info.applicationInfo?.loadIcon(BlackBoxCore.getPackageManager())) } catch (_: Throwable) { }
+ }, LinearLayout.LayoutParams(dp(56), dp(56)))
+ heading.addView(TextView(this).apply {
+ text = buildString {
+ append(info.packageName)
+ append("\nVersion: ").append(info.versionName ?: "unknown")
+ append("\nInstrumentation: ")
+ append(if (settings.getBoolean("package_enabled_${info.packageName}", true)) "enabled" else "disabled")
+ }
+ setPadding(dp(12), 0, 0, 0)
+ }, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f))
+ card.addView(heading)
+ val actions = LinearLayout(this).apply { orientation = LinearLayout.HORIZONTAL }
+ actions.addView(actionButton("Launch instrumented") { confirmInstrumentedLaunch(info.packageName) })
+ actions.addView(actionButton("Launch without instrumentation") { launch(info.packageName, false) })
+ actions.addView(actionButton("Clear virtual app data") { clearApp(info.packageName) })
+ actions.addView(actionButton("Remove from virtual space") { removeApp(info.packageName) })
+ actions.addView(actionButton("View runtime details") { showRuntime(info.packageName) })
+ card.addView(HorizontalScrollView(this).apply { addView(actions) })
+ val sha = metadata.getString("${info.packageName}.sha256", null)
+ if (sha != null) {
+ card.addView(TextView(this).apply {
+ text = "SHA-256: $sha\nSource: ${metadata.getString("${info.packageName}.source", "unknown")}\n" +
+ "ABI: ${metadata.getString("${info.packageName}.abi", "unknown")}\n" +
+ "Target SDK: ${metadata.getInt("${info.packageName}.targetSdk", info.applicationInfo?.targetSdkVersion ?: -1)}"
+ textSize = 12f
+ setTextIsSelectable(true)
+ })
+ }
+ content.addView(card, LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { topMargin = dp(10) })
+ }
+
+ private fun confirmInstrumentedLaunch(packageName: String) {
+ AlertDialog.Builder(this)
+ .setTitle("Early instrumentation")
+ .setMessage("Guest startup is paused until Frida attaches. Run the generated attach command or disable instrumentation.")
+ .setPositiveButton("Launch") { _, _ -> launch(packageName, true) }
+ .setNegativeButton("Cancel", null)
+ .show()
+ }
+
+ private fun launch(packageName: String, instrumented: Boolean) {
+ worker.execute {
+ try {
+ InstrumentationSettings.setEnabledForPackage(packageName, instrumented)
+ BlackBoxCore.get().stopPackage(packageName, 0)
+ Thread.sleep(150)
+ val launched = BlackBoxCore.get().launchApk(packageName, 0)
+ runOnUiThread {
+ toast(if (launched) "Guest launch requested" else "Guest has no launchable activity")
+ if (instrumented) showRuntime(packageName)
+ }
+ } catch (error: Throwable) {
+ runOnUiThread { toast("Launch failed: ${error.message}") }
+ }
+ }
+ }
+
+ private fun clearApp(packageName: String) {
+ worker.execute {
+ try {
+ BlackBoxCore.get().stopPackage(packageName, 0)
+ BlackBoxCore.get().clearPackage(packageName, 0)
+ runOnUiThread { toast("Virtual app data cleared") }
+ } catch (error: Throwable) {
+ runOnUiThread { toast("Clear failed: ${error.message}") }
+ }
+ }
+ }
+
+ private fun removeApp(packageName: String) {
+ AlertDialog.Builder(this).setTitle("Remove $packageName?")
+ .setMessage("This removes the app and its data only from BlackBox virtual space.")
+ .setPositiveButton("Remove") { _, _ ->
+ worker.execute {
+ try {
+ BlackBoxCore.get().stopPackage(packageName, 0)
+ BlackBoxCore.get().uninstallPackageAsUser(packageName, 0)
+ runOnUiThread { showHome() }
+ } catch (error: Throwable) {
+ runOnUiThread { toast("Remove failed: ${error.message}") }
+ }
+ }
+ }.setNegativeButton("Cancel", null).show()
+ }
+
+ private fun importApk(uri: Uri) {
+ val name = displayName(uri)
+ val lowerName = name.lowercase(Locale.ROOT)
+ if (!lowerName.endsWith(".apk") || lowerName.endsWith(".apks") ||
+ lowerName.endsWith(".xapk") || lowerName.endsWith(".apkm")) {
+ toast("Select one base .apk file; bundles and split sets are not supported")
+ return
+ }
+ toast("Importing $name…")
+ worker.execute {
+ val directory = File(filesDir, "imported-apks").apply { mkdirs() }
+ val temporary = File.createTempFile("import-", ".partial", directory)
+ try {
+ val digest = MessageDigest.getInstance("SHA-256")
+ contentResolver.openInputStream(uri).use { input ->
+ requireNotNull(input) { "Unable to open the selected document" }
+ FileOutputStream(temporary).use { output ->
+ val buffer = ByteArray(64 * 1024)
+ while (true) {
+ val count = input.read(buffer)
+ if (count < 0) break
+ digest.update(buffer, 0, count)
+ output.write(buffer, 0, count)
+ }
+ output.fd.sync()
+ }
+ }
+ val originalHash = digest.digest().joinToString("") { "%02x".format(it) }
+ val archiveInfo = packageManager.getPackageArchiveInfo(temporary.absolutePath, PackageManager.GET_META_DATA)
+ ?: error("Android could not parse this APK")
+ if (!archiveInfo.splitNames.isNullOrEmpty()) error("Split-only APKs are not supported in this MVP")
+ val abi = ApkInspector.inspect(temporary)
+ if (!abi.supported) error("32-bit-only/native APK rejected: ${abi.description()}")
+ val safePackage = archiveInfo.packageName.replace(Regex("[^A-Za-z0-9._-]"), "_")
+ val stored = File(directory, "$safePackage-${originalHash.take(12)}.apk")
+ if (stored.exists()) stored.delete()
+ if (!temporary.renameTo(stored)) error("Unable to move APK into private storage")
+ if (ApkIntegrity.sha256(stored) != originalHash) error("SHA-256 changed while importing")
+ stored.setReadable(true, true)
+ stored.setWritable(false, false)
+ val installResult = BlackBoxCore.get().installPackageAsUser(stored, 0)
+ if (!installResult.success) error(installResult.msg ?: "Virtual installation failed")
+ if (ApkIntegrity.sha256(stored) != originalHash) error("Stored APK was modified during virtual installation")
+ metadata.edit()
+ .putString("${archiveInfo.packageName}.sha256", originalHash)
+ .putString("${archiveInfo.packageName}.source", stored.absolutePath)
+ .putString("${archiveInfo.packageName}.abi", abi.description())
+ .putString("${archiveInfo.packageName}.version", archiveInfo.versionName)
+ .putInt("${archiveInfo.packageName}.targetSdk", archiveInfo.applicationInfo?.targetSdkVersion ?: -1)
+ .apply()
+ InstrumentationSettings.setEnabledForPackage(archiveInfo.packageName, true)
+ runOnUiThread {
+ toast("Imported ${archiveInfo.packageName}; SHA-256 verified")
+ showHome()
+ }
+ } catch (error: Throwable) {
+ temporary.delete()
+ runOnUiThread { toast("Import rejected: ${error.message}") }
+ }
+ }
+ }
+
+ private fun installDemoGuest() {
+ worker.execute {
+ try {
+ val directory = File(filesDir, "imported-apks").apply { mkdirs() }
+ val output = File(directory, "sample-guest.apk")
+ if (output.exists() && !output.delete()) error("Unable to replace the prior demo APK")
+ assets.open("demo/sample-guest.apk").use { input ->
+ FileOutputStream(output).use { input.copyTo(it) }
+ }
+ val sha = ApkIntegrity.sha256(output)
+ output.setWritable(false, false)
+ val result = BlackBoxCore.get().installPackageAsUser(output, 0)
+ if (!result.success) error(result.msg ?: "Demo virtual installation failed")
+ metadata.edit().putString("${result.packageName}.sha256", sha)
+ .putString("${result.packageName}.source", output.absolutePath)
+ .putString("${result.packageName}.abi", ApkInspector.inspect(output).description()).apply()
+ runOnUiThread { toast("Demo guest installed into virtual space"); showHome() }
+ } catch (error: Throwable) {
+ runOnUiThread { toast("Demo install failed: ${error.message}") }
+ }
+ }
+ }
+
+ private fun showRuntime(packageHint: String? = null) {
+ baseScreen("Runtime status")
+ val packageName = settings.getString("runtime_package", packageHint) ?: packageHint ?: "No guest bound"
+ val state = settings.getString("runtime_state", "idle")
+ val basePort = settings.getInt(InstrumentationSettings.KEY_BASE_PORT, 27042)
+ val count = settings.getInt(InstrumentationSettings.KEY_SCAN_COUNT, 32)
+ val command = "python tools/attach_guest.py --package $packageName --keep-alive"
+ content.addView(detail("Guest package", packageName))
+ content.addView(detail("Guest process", settings.getString("runtime_process", "unknown") ?: "unknown"))
+ content.addView(detail("Virtual process slot", settings.getInt("runtime_vpid", -1).toString()))
+ content.addView(detail("Guest source path", settings.getString("runtime_source", "unknown") ?: "unknown"))
+ content.addView(detail("Instrumentation enabled", settings.getBoolean("runtime_enabled", false).toString()))
+ content.addView(detail("Gadget load status", state ?: "idle"))
+ content.addView(detail("Expected port range", "$basePort..${basePort + count - 1}"))
+ content.addView(detail("Latest error", settings.getString("runtime_error", "none") ?: "none"))
+ content.addView(TextView(this).apply {
+ text = "Attach command\n$command"
+ setTextIsSelectable(true)
+ setPadding(0, dp(12), 0, dp(8))
+ })
+ content.addView(Button(this).apply {
+ text = "Copy attach command"
+ setOnClickListener {
+ (getSystemService(CLIPBOARD_SERVICE) as ClipboardManager)
+ .setPrimaryClip(ClipData.newPlainText("FridaBox attach", command))
+ toast("Attach command copied")
+ }
+ })
+ content.addView(Button(this).apply { text = "Refresh"; setOnClickListener { showRuntime(packageHint) } })
+ }
+
+ private fun showSettings() {
+ baseScreen("Instrumentation settings")
+ val enabled = Switch(this).apply {
+ text = "Instrumentation enabled"
+ isChecked = settings.getBoolean(InstrumentationSettings.KEY_ENABLED, true)
+ }
+ val pause = CheckBox(this).apply {
+ text = "Pause guest until attach (required for this MVP)"
+ isChecked = true
+ isEnabled = false
+ }
+ val port = numericSetting("Frida base port", settings.getInt(InstrumentationSettings.KEY_BASE_PORT, 27042))
+ val count = numericSetting("Port scan count", settings.getInt(InstrumentationSettings.KEY_SCAN_COUNT, 32))
+ val logs = Switch(this).apply {
+ text = "Show advanced logs"
+ isChecked = settings.getBoolean(InstrumentationSettings.KEY_ADVANCED_LOGS, false)
+ }
+ content.addView(enabled); content.addView(pause); content.addView(port.first); content.addView(count.first); content.addView(logs)
+ content.addView(Button(this).apply {
+ text = "Save settings"
+ setOnClickListener {
+ settings.edit()
+ .putBoolean(InstrumentationSettings.KEY_ENABLED, enabled.isChecked)
+ .putInt(InstrumentationSettings.KEY_BASE_PORT, InstrumentationPreferenceParser.parsePort(port.second.text.toString(), 27042))
+ .putInt(InstrumentationSettings.KEY_SCAN_COUNT, InstrumentationPreferenceParser.parseScanCount(count.second.text.toString(), 32))
+ .putBoolean(InstrumentationSettings.KEY_ADVANCED_LOGS, logs.isChecked)
+ .apply()
+ toast("Settings saved")
+ }
+ })
+ content.addView(TextView(this).apply {
+ text = "Limitations: FridaBox is not undetectable. The host UID/SELinux domain, virtual stub process, host classes, ClassLoader topology, synthesized Binder responses, Gadget module/threads/socket, and /proc/self/maps remain observable. Play Integrity and hardware-backed attestation are not virtualized."
+ setPadding(0, dp(20), 0, 0)
+ })
+ }
+
+ private fun numericSetting(label: String, value: Int): Pair {
+ val input = EditText(this).apply {
+ setText(value.toString()); inputType = InputType.TYPE_CLASS_NUMBER
+ }
+ return LinearLayout(this).apply {
+ orientation = LinearLayout.HORIZONTAL; gravity = Gravity.CENTER_VERTICAL
+ addView(TextView(this@FridaBoxActivity).apply { text = label }, LinearLayout.LayoutParams(0, dp(56), 1f))
+ addView(input, LinearLayout.LayoutParams(dp(140), dp(56)))
+ } to input
+ }
+
+ private fun detail(label: String, value: String) = TextView(this).apply {
+ text = "$label: $value"; setTextIsSelectable(true); setPadding(0, dp(5), 0, dp(5))
+ }
+
+ private fun sectionTitle(text: String) = TextView(this).apply {
+ this.text = text; textSize = 19f; setTypeface(typeface, Typeface.BOLD); setPadding(0, dp(18), 0, dp(4))
+ }
+
+ private fun actionButton(label: String, action: () -> Unit) = Button(this).apply {
+ text = label; setOnClickListener { action() }
+ }
+
+ private fun displayName(uri: Uri): String {
+ contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use {
+ if (it.moveToFirst()) return it.getString(0) ?: "selected.apk"
+ }
+ return uri.lastPathSegment ?: "selected.apk"
+ }
+
+ private fun toast(message: String) = Toast.makeText(this, message, Toast.LENGTH_LONG).show()
+ private fun dp(value: Int) = (value * resources.displayMetrics.density).toInt()
+}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java b/app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java
new file mode 100644
index 0000000..526ff44
--- /dev/null
+++ b/app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java
@@ -0,0 +1,23 @@
+package top.niunaijun.blackboxa.fridabox;
+
+public final class InstrumentationPreferenceParser {
+ private InstrumentationPreferenceParser() {
+ }
+
+ public static int parsePort(String text, int fallback) {
+ return parseRange(text, 1024, 65535, fallback);
+ }
+
+ public static int parseScanCount(String text, int fallback) {
+ return parseRange(text, 1, 128, fallback);
+ }
+
+ private static int parseRange(String text, int minimum, int maximum, int fallback) {
+ try {
+ int value = Integer.parseInt(text == null ? "" : text.trim());
+ return value >= minimum && value <= maximum ? value : fallback;
+ } catch (NumberFormatException ignored) {
+ return fallback;
+ }
+ }
+}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt
index 0a2030a..31a0fa2 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt
@@ -17,7 +17,7 @@ class BlackBoxLoader {
private var mHideRoot by AppSharedPreferenceDelegate(App.getContext(), false)
- private var mDaemonEnable by AppSharedPreferenceDelegate(App.getContext(), false)
+ private var mDaemonEnable by AppSharedPreferenceDelegate(App.getContext(), true)
private var mShowShortcutPermissionDialog by AppSharedPreferenceDelegate(App.getContext(), true)
@@ -245,12 +245,7 @@ class BlackBoxLoader {
}
override fun isEnableDaemonService(): Boolean {
- return try {
- mDaemonEnable
- } catch (e: Exception) {
- Log.e(TAG, "Error checking daemonEnable: ${e.message}")
- false
- }
+ return true
}
override fun isUseVpnNetwork(): Boolean {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt
index 9c07fbd..3f3586d 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt
@@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModelProvider
import top.niunaijun.blackbox.BlackBoxCore
import top.niunaijun.blackboxa.util.InjectionUtil
import top.niunaijun.blackboxa.view.list.ListViewModel
+import top.niunaijun.blackboxa.fridabox.FridaBoxActivity
class WelcomeActivity : AppCompatActivity() {
@@ -22,7 +23,7 @@ class WelcomeActivity : AppCompatActivity() {
}
private fun jump() {
- MainActivity.start(this)
+ startActivity(Intent(this, FridaBoxActivity::class.java))
finish()
}
@@ -30,4 +31,4 @@ class WelcomeActivity : AppCompatActivity() {
val viewModel = ViewModelProvider(this,InjectionUtil.getListFactory()).get(ListViewModel::class.java)
viewModel.previewInstalledList()
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/jniLibs/arm64-v8a/libfrida-gadget.config.so b/app/src/main/jniLibs/arm64-v8a/libfrida-gadget.config.so
new file mode 100644
index 0000000..6b8b54f
--- /dev/null
+++ b/app/src/main/jniLibs/arm64-v8a/libfrida-gadget.config.so
@@ -0,0 +1,11 @@
+{
+ "interaction": {
+ "type": "listen",
+ "address": "127.0.0.1",
+ "port": 27042,
+ "on_port_conflict": "pick-next",
+ "on_load": "wait"
+ },
+ "runtime": "qjs",
+ "teardown": "minimal"
+}
diff --git a/app/src/main/jniLibs/arm64-v8a/libfrida-gadget.so b/app/src/main/jniLibs/arm64-v8a/libfrida-gadget.so
new file mode 100644
index 0000000000000000000000000000000000000000..b7829a8ec6e0d7d1ddfdc257d01d9aa192d6b94a
GIT binary patch
literal 25212656
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
qh8q6Aq2dx~;$F~j(?ApVgQhnN
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