mirror of
https://github.com/QM4RS/FridaBox.git
synced 2026-10-29 18:22:29 +01:00
docs: prepare FridaBox for public release
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
github: alex5402
|
||||
buy_me_a_coffee: alex5402
|
||||
custom: ["https://www.binance.com/en-IN/my/wallet/account/main/withdrawal/crypto/USDT", Binance__749326513 ]
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Bug report
|
||||
description: Report a reproducible FridaBox failure on an authorized test target.
|
||||
title: "[Bug]: "
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Do not upload proprietary APKs, private agents, credentials, or unsanitized device logs.
|
||||
Security vulnerabilities belong in a private GitHub security advisory.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Authorization and scope
|
||||
options:
|
||||
- label: I am authorized to test the device and application involved.
|
||||
required: true
|
||||
- label: I checked the documented limitations and existing issues.
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: FridaBox version or commit
|
||||
placeholder: 4.0.0 / commit SHA
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Device and Android build
|
||||
placeholder: Model, Android/API version, vendor ROM
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Launch mode
|
||||
options: [On-device, Computer, Clean, Import/build, Not mode-specific]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: Provide the smallest deterministic sequence.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected and actual behavior
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Sanitized evidence
|
||||
description: Relevant logcat, stack trace, controller output, ABI, and process state.
|
||||
render: text
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Research or feature proposal
|
||||
description: Propose a scoped capability or research direction.
|
||||
title: "[Proposal]: "
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Scope
|
||||
options:
|
||||
- label: This proposal is for authorized research and defensive testing.
|
||||
required: true
|
||||
- label: I reviewed the architecture and current limitations.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem
|
||||
description: What concrete limitation or workflow gap should be addressed?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed boundary
|
||||
description: Which host, virtual runtime, Gadget, controller, or UI component changes?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Acceptance evidence
|
||||
description: Describe the tests and device proof that would demonstrate success.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternatives and risks
|
||||
@@ -0,0 +1,30 @@
|
||||
## Summary
|
||||
|
||||
Describe the problem and the narrow change that solves it.
|
||||
|
||||
## Affected boundary
|
||||
|
||||
- [ ] Host UI/import/policy
|
||||
- [ ] Virtual package or process runtime
|
||||
- [ ] Gadget lifecycle or agent configuration
|
||||
- [ ] Controller or Frida scripts
|
||||
- [ ] Build/release/tooling
|
||||
- [ ] Documentation only
|
||||
|
||||
## Validation
|
||||
|
||||
- [ ] Relevant unit tests pass
|
||||
- [ ] `:app:check` passes
|
||||
- [ ] Debug build passes
|
||||
- [ ] Release build passes
|
||||
- [ ] Device validation attached when runtime behavior changed
|
||||
- [ ] Original guest APK remains unmodified
|
||||
- [ ] No credentials, private agents, proprietary APKs, or sensitive logs included
|
||||
|
||||
## Evidence
|
||||
|
||||
List exact commands, Android/device details, and sanitized output.
|
||||
|
||||
## Risks and limitations
|
||||
|
||||
Describe compatibility impact, process-lifecycle assumptions, and remaining gaps.
|
||||
@@ -0,0 +1,18 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gradle
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 5
|
||||
- package-ecosystem: npm
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 5
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 5
|
||||
@@ -0,0 +1,87 @@
|
||||
name: Android CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: android-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
name: Build, test, and verify
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
|
||||
steps:
|
||||
- name: Check out source
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
cache: gradle
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: pip
|
||||
cache-dependency-path: tools/requirements.txt
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: npm
|
||||
|
||||
- name: Install Android SDK components
|
||||
run: |
|
||||
yes | sdkmanager --licenses >/dev/null || true
|
||||
sdkmanager \
|
||||
'platforms;android-35' \
|
||||
'build-tools;35.0.0' \
|
||||
'ndk;29.0.14206865'
|
||||
|
||||
- name: Install controller and agent dependencies
|
||||
run: |
|
||||
python -m pip install --requirement tools/requirements.txt
|
||||
npm ci
|
||||
|
||||
- name: Verify reproducible Frida agents
|
||||
run: |
|
||||
python tools/build_frida_agents.py
|
||||
git diff --exit-code -- scripts/dist
|
||||
|
||||
- name: Build and test
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew \
|
||||
:app:assembleDebug \
|
||||
:app:assembleRelease \
|
||||
:Bcore:testDebugUnitTest \
|
||||
:app:testDebugUnitTest \
|
||||
:app:check \
|
||||
--stacktrace \
|
||||
--console=plain
|
||||
|
||||
- name: Upload APKs and reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: fridabox-${{ github.sha }}
|
||||
if-no-files-found: warn
|
||||
retention-days: 14
|
||||
path: |
|
||||
app/build/outputs/apk/**/*.apk
|
||||
app/build/reports/lint-results-*.html
|
||||
app/build/test-results/**/*.xml
|
||||
Bcore/build/test-results/**/*.xml
|
||||
@@ -1,167 +0,0 @@
|
||||
name: Build and Send APK to Telegram
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-send:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
cache: 'gradle'
|
||||
|
||||
- name: Set up Android SDK
|
||||
uses: android-actions/setup-android@v3
|
||||
|
||||
- name: Accept Android SDK licenses
|
||||
run: yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses || true
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x ./gradlew
|
||||
|
||||
- name: Build APKs and AARs
|
||||
run: ./gradlew assembleDebug assembleRelease :Bcore:assembleDebug :Bcore:assembleRelease :black-reflection:assemble :compiler:assemble
|
||||
|
||||
- name: Find Bcore AAR paths
|
||||
id: aar_paths
|
||||
run: |
|
||||
DEBUG_AAR=$(find ./Bcore/build/outputs/aar -name "*debug.aar" | head -n 1)
|
||||
RELEASE_AAR=$(find ./Bcore/build/outputs/aar -name "*release.aar" | head -n 1)
|
||||
echo "debug_aar_path=$DEBUG_AAR" >> $GITHUB_OUTPUT
|
||||
echo "release_aar_path=$RELEASE_AAR" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Find black-reflection and compiler artifact paths
|
||||
id: additional_artifacts
|
||||
run: |
|
||||
BLACK_REFLECTION_ART=$(find ./black-reflection/build/libs ./black-reflection/build/outputs -name "*.jar" -o -name "*.aar" 2>/dev/null | head -n 1)
|
||||
COMPILER_ART=$(find ./compiler/build/libs ./compiler/build/outputs -name "*.jar" -o -name "*.aar" 2>/dev/null | head -n 1)
|
||||
echo "black_reflection_path=$BLACK_REFLECTION_ART" >> $GITHUB_OUTPUT
|
||||
echo "compiler_path=$COMPILER_ART" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Send Bcore Debug AAR to Telegram and Pin
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%s)
|
||||
AAR_PATH="${{ steps.aar_paths.outputs.debug_aar_path }}"
|
||||
if [ -n "$AAR_PATH" ] && [ -f "$AAR_PATH" ]; then
|
||||
RESPONSE=$(curl -s -F document=@"$AAR_PATH" \
|
||||
-F chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-F caption="[Bcore DEBUG AAR] $COMMIT_MSG" \
|
||||
https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument)
|
||||
MESSAGE_ID=$(echo $RESPONSE | jq '.result.message_id')
|
||||
if [ "$MESSAGE_ID" != "null" ] && [ -n "$MESSAGE_ID" ]; then
|
||||
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/pinChatMessage" \
|
||||
-d chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-d message_id="$MESSAGE_ID"
|
||||
fi
|
||||
else
|
||||
echo "Debug AAR not found at $AAR_PATH"
|
||||
fi
|
||||
|
||||
- name: Send Bcore Release AAR to Telegram and Pin
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%s)
|
||||
AAR_PATH="${{ steps.aar_paths.outputs.release_aar_path }}"
|
||||
if [ -n "$AAR_PATH" ] && [ -f "$AAR_PATH" ]; then
|
||||
RESPONSE=$(curl -s -F document=@"$AAR_PATH" \
|
||||
-F chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-F caption="[Bcore RELEASE AAR] $COMMIT_MSG" \
|
||||
https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument)
|
||||
MESSAGE_ID=$(echo $RESPONSE | jq '.result.message_id')
|
||||
if [ "$MESSAGE_ID" != "null" ] && [ -n "$MESSAGE_ID" ]; then
|
||||
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/pinChatMessage" \
|
||||
-d chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-d message_id="$MESSAGE_ID"
|
||||
fi
|
||||
else
|
||||
echo "Release AAR not found at $AAR_PATH"
|
||||
fi
|
||||
|
||||
- name: Send black-reflection Artifact to Telegram and Pin
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%s)
|
||||
ART_PATH="${{ steps.additional_artifacts.outputs.black_reflection_path }}"
|
||||
if [ -n "$ART_PATH" ] && [ -f "$ART_PATH" ]; then
|
||||
FILENAME=$(basename "$ART_PATH")
|
||||
RESPONSE=$(curl -s -F document=@"$ART_PATH" \
|
||||
-F chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-F caption="[black-reflection] $FILENAME - $COMMIT_MSG" \
|
||||
https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument)
|
||||
MESSAGE_ID=$(echo $RESPONSE | jq '.result.message_id')
|
||||
if [ "$MESSAGE_ID" != "null" ] && [ -n "$MESSAGE_ID" ]; then
|
||||
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/pinChatMessage" \
|
||||
-d chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-d message_id="$MESSAGE_ID"
|
||||
fi
|
||||
else
|
||||
echo "black-reflection artifact not found at $ART_PATH"
|
||||
fi
|
||||
|
||||
- name: Send compiler Artifact to Telegram and Pin
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%s)
|
||||
ART_PATH="${{ steps.additional_artifacts.outputs.compiler_path }}"
|
||||
if [ -n "$ART_PATH" ] && [ -f "$ART_PATH" ]; then
|
||||
FILENAME=$(basename "$ART_PATH")
|
||||
RESPONSE=$(curl -s -F document=@"$ART_PATH" \
|
||||
-F chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-F caption="[compiler] $FILENAME - $COMMIT_MSG" \
|
||||
https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument)
|
||||
MESSAGE_ID=$(echo $RESPONSE | jq '.result.message_id')
|
||||
if [ "$MESSAGE_ID" != "null" ] && [ -n "$MESSAGE_ID" ]; then
|
||||
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/pinChatMessage" \
|
||||
-d chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-d message_id="$MESSAGE_ID"
|
||||
fi
|
||||
else
|
||||
echo "compiler artifact not found at $ART_PATH"
|
||||
fi
|
||||
|
||||
- name: Send ALL Debug APKs to Telegram and Pin
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%s)
|
||||
for APK in ./app/build/outputs/apk/debug/*.apk; do
|
||||
if [ -f "$APK" ]; then
|
||||
RESPONSE=$(curl -s -F document=@"$APK" \
|
||||
-F chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-F caption="[DEBUG] $(basename $APK) $COMMIT_MSG" \
|
||||
https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument)
|
||||
MESSAGE_ID=$(echo $RESPONSE | jq '.result.message_id')
|
||||
if [ "$MESSAGE_ID" != "null" ] && [ -n "$MESSAGE_ID" ]; then
|
||||
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/pinChatMessage" \
|
||||
-d chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-d message_id="$MESSAGE_ID"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Send ALL Release APKs to Telegram and Pin
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%s)
|
||||
for APK in ./app/build/outputs/apk/release/*.apk; do
|
||||
if [ -f "$APK" ]; then
|
||||
RESPONSE=$(curl -s -F document=@"$APK" \
|
||||
-F chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-F caption="[RELEASE] $(basename $APK) $COMMIT_MSG" \
|
||||
https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendDocument)
|
||||
MESSAGE_ID=$(echo $RESPONSE | jq '.result.message_id')
|
||||
if [ "$MESSAGE_ID" != "null" ] && [ -n "$MESSAGE_ID" ]; then
|
||||
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/pinChatMessage" \
|
||||
-d chat_id="$TELEGRAM_CHAT_ID" \
|
||||
-d message_id="$MESSAGE_ID"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
+126
-50
@@ -1,57 +1,133 @@
|
||||
# Architecture
|
||||
# FridaBox 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.
|
||||
FridaBox has two deliberate layers:
|
||||
|
||||
1. an independent host product under `com.qm4rs.fridabox`, responsible for APK
|
||||
import, integrity, launch policy, agent storage, runtime presentation, and
|
||||
the user experience;
|
||||
2. a retained virtual Android runtime responsible for package, process, Binder,
|
||||
filesystem, identity, signature, component, and lifecycle virtualization.
|
||||
|
||||
The runtime descends from the NewBlackbox/BlackBox lineage. Its internal package
|
||||
names are compatibility API and are not the FridaBox product namespace. They are
|
||||
kept stable because manifests, AIDL, reflection, native code, persisted paths,
|
||||
and virtual process dispatch all depend on that contract.
|
||||
|
||||
## End-to-end lifecycle
|
||||
|
||||
```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
|
||||
FridaBoxActivity
|
||||
│
|
||||
├── SAF document stream
|
||||
├── private immutable APK copy
|
||||
├── SHA-256 + ZIP ABI inspection
|
||||
└── virtual installation for user 0
|
||||
│
|
||||
▼
|
||||
virtual package manager
|
||||
│
|
||||
▼
|
||||
allocate :pN process and dispatch ProxyActivity
|
||||
│
|
||||
▼
|
||||
BActivityThread.handleBindApplication()
|
||||
│
|
||||
├── establish virtual identity and runtime
|
||||
├── initialize native IO redirection
|
||||
├── create guest Context / LoadedApk / PathClassLoader
|
||||
├── populate GuestRuntimeRegistry
|
||||
└── apply per-package InstrumentationPreferences
|
||||
│
|
||||
├── disabled: continue
|
||||
├── listen: load loopback Gadget and wait for attach
|
||||
└── script: load private Gadget + agent.js
|
||||
│
|
||||
▼
|
||||
guest makeApplication()
|
||||
│
|
||||
▼
|
||||
guest Application.onCreate()
|
||||
│
|
||||
▼
|
||||
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.
|
||||
The host copies a document-provider stream once into `files/imported-apks` and
|
||||
computes SHA-256 while copying. It inspects native ZIP entries, parses package
|
||||
metadata, verifies the stored hash, marks the private file read-only, and passes
|
||||
that path only to the virtual package manager.
|
||||
|
||||
There is no package-installer Intent, PackageInstaller session, APK mutation,
|
||||
repack, or resign. The original guest package is therefore absent from Android's
|
||||
real PackageManager.
|
||||
|
||||
## Instrumentation boundary
|
||||
|
||||
`GuestRuntimeRegistry` is authoritative, volatile, process-local state. It is
|
||||
populated only after `VirtualRuntime.setupRuntime`, `NativeCore.init`, IO
|
||||
redirection, and guest `LoadedApk` creation have succeeded. This gives Frida a
|
||||
real guest ClassLoader while still preceding `makeApplication()`.
|
||||
|
||||
`FridaGadgetLoader` makes one synchronized Gadget-load attempt per Linux process.
|
||||
The loader reads per-package policy from private host storage:
|
||||
|
||||
- **disabled** emits an explicit clean-launch state and never loads Gadget;
|
||||
- **listen** loads the pinned loopback configuration with `on_load=wait`;
|
||||
- **script** creates a private per-guest Gadget copy and adjacent Script
|
||||
interaction config referencing a read-only `agent.js`.
|
||||
|
||||
The build task `verifyInstrumentationOrdering` statically verifies that the
|
||||
loader remains before guest `makeApplication()`.
|
||||
|
||||
## Controller boundary
|
||||
|
||||
Gadget always listens on device loopback. ADB forwarding is a controller concern,
|
||||
not a guest concern. `tools/attach_guest.py` forwards a bounded port range,
|
||||
probes candidates using a compiled registry agent, rejects unrelated endpoints,
|
||||
and maps each endpoint to package/process metadata from `GuestRuntimeRegistry`.
|
||||
|
||||
Before loading a user agent, `guest-bootstrap.js` assigns the registry's guest
|
||||
ClassLoader to `Java.classFactory.loader` and reports native module enumeration.
|
||||
This prevents host-first class resolution from producing false negatives.
|
||||
|
||||
## Cross-process state
|
||||
|
||||
The registry itself is never treated as cross-process storage. A minimal private
|
||||
SharedPreferences snapshot lets the host UI display the latest package, process,
|
||||
virtual user, process slot, source APK, ClassLoader, state, and error. Reads use
|
||||
multi-process reload semantics because host and guest processes maintain
|
||||
independent in-memory preference caches.
|
||||
|
||||
## Process recycling
|
||||
|
||||
Instrumentation policy is process-scoped in effect even though it is persisted
|
||||
per package. Changing mode stops the guest before relaunch. This is essential:
|
||||
a native library cannot be unloaded safely from a living Android process, so a
|
||||
Clean launch must receive a fresh virtual process rather than attempting to undo
|
||||
Gadget initialization.
|
||||
|
||||
## Trust and security boundaries
|
||||
|
||||
- The imported APK and selected JavaScript agent are untrusted inputs.
|
||||
- Imported files are size-bounded, hashed, privately stored, and made read-only.
|
||||
- On-device agents require an explicit trust confirmation and execute with the
|
||||
guest process's access.
|
||||
- Gadget binds only to `127.0.0.1`; remote reachability requires an explicit ADB
|
||||
forwarding action.
|
||||
- Release builds never silently use the debug signing key.
|
||||
- FridaBox does not claim to defeat kernel, SELinux, Frida, virtualization, or
|
||||
hardware-attestation detection.
|
||||
|
||||
## Source layout
|
||||
|
||||
| Module | Responsibility |
|
||||
| --- | --- |
|
||||
| `app` | FridaBox application, UI, import pipeline, modes and management. |
|
||||
| `Bcore` | Virtual Android runtime, Gadget load point, registry and native integration. |
|
||||
| `black-reflection` | Generated/reflected access to hidden Android framework APIs. |
|
||||
| `compiler` | Annotation processing used by the reflection layer. |
|
||||
| `sample-guest` | Deterministic early-start and hook validation target. |
|
||||
| `scripts` | Source and reproducibly bundled Frida 17 agents. |
|
||||
| `tools` | Fetch, build, forward, discover and attach utilities. |
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Changelog
|
||||
|
||||
All notable FridaBox changes are documented here. The project follows semantic
|
||||
versioning for its public releases.
|
||||
|
||||
## [4.0.0] - 2026-07-20
|
||||
|
||||
### Added
|
||||
|
||||
- Independent FridaBox application, Android namespace, brand, icon, responsive
|
||||
workspace, runtime dashboard, settings, and per-guest management.
|
||||
- Per-app **On-device**, **Computer**, and **Clean** launch modes.
|
||||
- Trusted JavaScript selection through SAF with private byte-identical storage,
|
||||
SHA-256 recording, size bounds, and read-only execution permissions.
|
||||
- Autonomous Gadget Script interaction requiring no ADB or computer after agent
|
||||
selection.
|
||||
- Loopback Gadget endpoint discovery and guest mapping through
|
||||
`GuestRuntimeRegistry`.
|
||||
- Guest ClassLoader bootstrap and native module enumeration.
|
||||
- ARM64 APK inspection and clear rejection of incompatible/split inputs.
|
||||
- Generated sample guest and deterministic `Target.add(2, 3) -> 1337` hook.
|
||||
- Reproducible Frida 17 agent bundles with pinned npm dependencies.
|
||||
- Explicit production signing configuration, R8, and resource shrinking.
|
||||
- Android 16 device-validation transcript and engineering documentation.
|
||||
|
||||
### Changed
|
||||
|
||||
- Gadget now loads after virtual runtime/IO/ClassLoader setup and before guest
|
||||
`makeApplication()`.
|
||||
- Launch-mode changes recycle the virtual process to prevent instrumentation
|
||||
state from leaking into Clean launches.
|
||||
- Runtime snapshots reload safely across host/guest process boundaries.
|
||||
- Private Gadget and agent permissions comply with modern Android executable
|
||||
file constraints.
|
||||
- Guest-visible inherited product strings were replaced with FridaBox identity.
|
||||
|
||||
### Removed
|
||||
|
||||
- The inherited launcher and unrelated GMS, Xposed, fake-location, floating
|
||||
overlay, cloning-list, and legacy settings surfaces.
|
||||
- Obsolete launcher resources, translations, UI AARs, and product documents.
|
||||
- Debug-key fallback for release artifacts.
|
||||
|
||||
## Foundation
|
||||
|
||||
FridaBox began from NewBlackbox commit
|
||||
`89b59836c66f173756a4ae258cf379a957649820`. Upstream provenance and bundled
|
||||
Frida licensing are documented in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
||||
@@ -0,0 +1,25 @@
|
||||
# Community code of conduct
|
||||
|
||||
FridaBox is a technical research project. Participation must remain respectful,
|
||||
evidence-driven, and safe.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
- Treat contributors, maintainers, upstream projects, and users with respect.
|
||||
- Critique technical claims with reproducible evidence rather than personal
|
||||
attacks.
|
||||
- Respect authorization boundaries, privacy, licenses, and coordinated security
|
||||
disclosure.
|
||||
- Make room for different experience levels while maintaining engineering rigor.
|
||||
- Clearly distinguish measured results from assumptions or speculation.
|
||||
|
||||
## Unacceptable behavior
|
||||
|
||||
Harassment, discrimination, threats, doxxing, publication of secrets or private
|
||||
data, knowingly false claims, and requests for unauthorized exploitation are not
|
||||
welcome. Maintainers may edit, hide, reject, or remove contributions that violate
|
||||
these expectations and may restrict participation when necessary.
|
||||
|
||||
Report conduct concerns privately through the repository owner's available
|
||||
GitHub contact or security-advisory channel. Good-faith reports will be handled
|
||||
with discretion.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Contributing to FridaBox
|
||||
|
||||
FridaBox welcomes focused contributions that improve correctness,
|
||||
compatibility, observability, documentation, or responsible research workflows.
|
||||
|
||||
## Before opening an issue
|
||||
|
||||
- Confirm the target and device are authorized for your testing.
|
||||
- Read [docs/LIMITATIONS.md](docs/LIMITATIONS.md) and
|
||||
[docs/DETECTION_SURFACES.md](docs/DETECTION_SURFACES.md).
|
||||
- Search existing issues for the Android version, vendor ROM, package type, and
|
||||
failure signature.
|
||||
- Remove credentials, personal data, proprietary APKs, private agents, tokens,
|
||||
and device identifiers from logs.
|
||||
|
||||
Security vulnerabilities should follow [SECURITY.md](SECURITY.md), not a public
|
||||
issue.
|
||||
|
||||
## Development setup
|
||||
|
||||
Use JDK 21, Android SDK 35, NDK 29.0.14206865, Python 3.10+, and Node.js 20+.
|
||||
Follow [docs/BUILDING.md](docs/BUILDING.md) for Gadget verification and the
|
||||
Windows no-space native-build workaround.
|
||||
|
||||
```text
|
||||
npm ci
|
||||
python tools/build_frida_agents.py
|
||||
./gradlew :app:assembleDebug :Bcore:testDebugUnitTest :app:testDebugUnitTest :app:check
|
||||
```
|
||||
|
||||
## Pull requests
|
||||
|
||||
Keep changes narrow and explain the runtime boundary they affect. A useful pull
|
||||
request includes:
|
||||
|
||||
- the problem and why the current behavior is incorrect;
|
||||
- the smallest viable implementation;
|
||||
- affected Android versions, ABIs, and process types;
|
||||
- host-side test results;
|
||||
- device evidence for lifecycle, native, Binder, or virtualization changes;
|
||||
- explicit confirmation that imported APK bytes were not modified;
|
||||
- documentation updates for new behavior or limitations.
|
||||
|
||||
Do not combine unrelated reformatting, package renames, or generated-file churn
|
||||
with a runtime fix.
|
||||
|
||||
## Runtime changes
|
||||
|
||||
Changes around `BActivityThread`, `NativeCore`, IO redirection, Binder proxies,
|
||||
Gadget loading, process allocation, or package persistence require device
|
||||
validation. At minimum, test:
|
||||
|
||||
1. import of an original ARM64 base APK;
|
||||
2. absence of the guest from the real PackageManager;
|
||||
3. Computer-mode pause and attach;
|
||||
4. Java hook execution with the guest ClassLoader;
|
||||
5. native module enumeration;
|
||||
6. process recycling into Clean mode;
|
||||
7. a second instrumented launch after Clean mode.
|
||||
|
||||
Add exact commands and relevant log lines to a dedicated validation note. Never
|
||||
commit proprietary APKs or third-party scripts without redistribution rights.
|
||||
|
||||
## Style
|
||||
|
||||
- Preserve existing source encoding and line endings where practical.
|
||||
- Keep user-facing language precise; do not promise stealth or universal app
|
||||
compatibility.
|
||||
- Prefer explicit failure states over silent fallbacks.
|
||||
- Keep network listeners loopback-only by default.
|
||||
- Pin and verify externally fetched runtime artifacts.
|
||||
- Add tests for parsers, integrity rules, state transitions, and regressions.
|
||||
|
||||
By contributing, you agree that your contribution is licensed under the
|
||||
repository's Apache License 2.0.
|
||||
@@ -1,34 +1,295 @@
|
||||
<div align="center">
|
||||
|
||||
# FridaBox
|
||||
|
||||
FridaBox is an authorized mobile-security research workspace that runs an original,
|
||||
unmodified APK inside private 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.
|
||||
### On-device Android instrumentation, inside a private virtual workspace
|
||||
|
||||
The host application ID and Android namespace are both `com.qm4rs.fridabox`.
|
||||
Third-party engine provenance is isolated in `THIRD_PARTY_NOTICES.md`.
|
||||
[](docs/TEST_RESULTS.md)
|
||||
[](docs/BUILDING.md)
|
||||
[](THIRD_PARTY_NOTICES.md)
|
||||
[](CHANGELOG.md)
|
||||
[](LICENSE)
|
||||
[](docs/device-validation.log)
|
||||
|
||||
## MVP capabilities
|
||||
**Import an original APK. Choose a per-app mode. Run trusted Frida JavaScript
|
||||
directly on the phone, attach from a computer, or launch clean.**
|
||||
|
||||
- SAF import of one base APK into app-private, read-only storage.
|
||||
- SHA-256 verification before and after private 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.
|
||||
[Features](#what-fridabox-does) · [How it works](#how-it-works) ·
|
||||
[Quick start](#quick-start) · [Research](#engineering-and-research) ·
|
||||
[Limitations](#scope-and-limitations) · [Acknowledgements](#acknowledgements)
|
||||
|
||||
Start with [docs/BUILDING.md](docs/BUILDING.md), [docs/USAGE.md](docs/USAGE.md),
|
||||
and [docs/FRIDA_CONNECTION.md](docs/FRIDA_CONNECTION.md).
|
||||
</div>
|
||||
|
||||
FridaBox is not undetectable. See [docs/DETECTION_SURFACES.md](docs/DETECTION_SURFACES.md)
|
||||
and [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
|
||||
---
|
||||
|
||||
The complete Android 16 device transcript is in
|
||||
FridaBox is an Android mobile-security research workspace built for authorized
|
||||
dynamic analysis. It runs an original, unmodified APK inside app-private virtual
|
||||
processes and can load Frida Gadget before the guest `Application` is created.
|
||||
|
||||
It does **not** require root, Magisk, Zygisk, frida-server, a modified system
|
||||
image, real PackageManager installation, APK patching, repacking, or resigning.
|
||||
The host application ID and Android namespace are both
|
||||
`com.qm4rs.fridabox`.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> FridaBox is intended for applications and devices you own or are explicitly
|
||||
> authorized to test. It is a research tool, not an invisibility product. Read
|
||||
> [SECURITY.md](SECURITY.md) and [the documented detection surfaces](docs/DETECTION_SURFACES.md)
|
||||
> before using it in an assessment.
|
||||
|
||||
## Why FridaBox exists
|
||||
|
||||
Traditional Gadget workflows patch a target APK, add a native library, rebuild
|
||||
it, and sign the modified package. That changes the artifact under test and can
|
||||
invalidate signatures, integrity assumptions, update paths, and experimental
|
||||
results. A frida-server workflow avoids repacking but normally requires a rooted
|
||||
or specially prepared device.
|
||||
|
||||
FridaBox explores a different boundary:
|
||||
|
||||
- preserve the imported APK byte-for-byte;
|
||||
- install it only into a private virtual package manager;
|
||||
- create the guest's real Android `LoadedApk` and `ClassLoader`;
|
||||
- load a pinned Gadget inside the assigned virtual process;
|
||||
- pause before guest `Application.onCreate()` when interactive attachment is
|
||||
requested;
|
||||
- keep instrumentation policy per guest instead of globally.
|
||||
|
||||
The result is a repeatable laboratory for early Java/native hooks while the
|
||||
original package remains absent from Android's real PackageManager.
|
||||
|
||||
## What FridaBox does
|
||||
|
||||
| Capability | What it provides |
|
||||
| --- | --- |
|
||||
| Original APK import | SAF-based import into private storage with SHA-256 verification before and after virtual installation. |
|
||||
| Three launch modes | **On-device**, **Computer**, and **Clean**, remembered independently for every guest. |
|
||||
| Earliest practical Gadget load | Gadget is loaded after guest runtime/IO setup but before `makeApplication()` and guest `Application.onCreate()`. |
|
||||
| No-computer instrumentation | A trusted JavaScript agent can be selected once and automatically loaded on every On-device launch. |
|
||||
| Familiar desktop workflow | Computer mode supports the normal `frida -U gadget -l agent.js` flow and pauses startup until attachment. |
|
||||
| Deterministic clean launch | The virtual process is recycled before starting without Gadget, preventing mode leakage from a previous process. |
|
||||
| Correct Java context | The controller selects the guest `PathClassLoader`, not the host loader, before user hooks execute. |
|
||||
| Runtime observability | Package, process, virtual user, process slot, source APK, ClassLoader, mode, state, and latest error are exposed. |
|
||||
| Endpoint discovery | The controller probes a bounded forwarded range and identifies the correct Gadget endpoint for a guest. |
|
||||
| Native visibility | Loaded native modules can be enumerated before a user agent is installed. |
|
||||
| ARM64 validation | Native guests are inspected before import; incompatible native APKs and split containers are rejected clearly. |
|
||||
| Production-oriented host | Independent FridaBox identity, responsive Material UI, R8/resource shrinking, and explicit release signing. |
|
||||
|
||||
## Launch modes
|
||||
|
||||
### On-device
|
||||
|
||||
Choose a trusted `.js` file through Android's document picker. FridaBox stores a
|
||||
private byte-identical copy, records its hash, creates a per-guest Script
|
||||
interaction configuration, and loads it on future launches—without ADB, a USB
|
||||
cable, port forwarding, or a computer-side Frida client.
|
||||
|
||||
### Computer
|
||||
|
||||
FridaBox loads its loopback-only Gadget listener and pauses guest startup. Attach
|
||||
using the familiar workflow:
|
||||
|
||||
```text
|
||||
frida -U gadget -l path/to/agent.js
|
||||
```
|
||||
|
||||
For deterministic multi-guest discovery and automatic ClassLoader selection:
|
||||
|
||||
```text
|
||||
python tools/attach_guest.py --list
|
||||
python tools/attach_guest.py --package com.example.app --script scripts/example.js
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
||||
FridaBox stops the existing virtual process, disables instrumentation for the
|
||||
next process, and launches the guest normally. The saved on-device agent remains
|
||||
available for later use.
|
||||
|
||||
## How it works
|
||||
|
||||
```text
|
||||
Original APK selected with SAF
|
||||
│
|
||||
▼
|
||||
Private copy + SHA-256 + ABI inspection
|
||||
│
|
||||
▼
|
||||
Virtual package installation (not Android PackageManager)
|
||||
│
|
||||
▼
|
||||
Virtual process allocation and guest runtime setup
|
||||
│
|
||||
├── Clean ───────────────► guest makeApplication()
|
||||
│
|
||||
├── On-device ───────────► Gadget + private agent.js
|
||||
│ │
|
||||
│ ▼
|
||||
│ guest makeApplication()
|
||||
│
|
||||
└── Computer ────────────► Gadget listens + startup waits
|
||||
│
|
||||
controller attaches
|
||||
│
|
||||
▼
|
||||
guest makeApplication()
|
||||
```
|
||||
|
||||
The instrumentation hook lives in `BActivityThread.handleBindApplication()`.
|
||||
At that point the virtual identity, filesystem redirection, guest context, and
|
||||
guest ClassLoader exist, but the guest `Application` has not yet been created.
|
||||
That ordering is enforced by a build verification task.
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for component boundaries and
|
||||
[docs/ENGINEERING_JOURNEY.md](docs/ENGINEERING_JOURNEY.md) for the failures,
|
||||
constraints, and fixes that shaped the implementation.
|
||||
|
||||
## Demonstrated result
|
||||
|
||||
The repository includes a generated sample guest and a small hook:
|
||||
|
||||
```javascript
|
||||
Java.perform(function () {
|
||||
const Target = Java.use('com.qm4rs.fridabox.sample.Target');
|
||||
Target.add.implementation = function (a, b) {
|
||||
return 1337;
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
The complete Android 16 device validation proved that:
|
||||
|
||||
- the sample package was absent from the real Android PackageManager;
|
||||
- startup paused before `SampleApplication.onCreate()`;
|
||||
- the correct Gadget endpoint and guest ClassLoader were discovered;
|
||||
- native module enumeration returned hundreds of modules;
|
||||
- `Target.add(2, 3)` changed from `5` to `1337`;
|
||||
- recycling into Clean mode removed the listener and restored the result to `5`.
|
||||
|
||||
The commercial workspace flow was also validated with a real ARM64 Unity guest
|
||||
in On-device, Computer, and Clean modes. Evidence and exact commands are in
|
||||
[docs/TEST_RESULTS.md](docs/TEST_RESULTS.md) and
|
||||
[docs/device-validation.log](docs/device-validation.log).
|
||||
|
||||
## Quick start
|
||||
|
||||
### Requirements
|
||||
|
||||
- an ARM64 Android 12–16 device;
|
||||
- JDK 21;
|
||||
- Android SDK 35 and NDK 29.0.14206865;
|
||||
- Python 3.10+;
|
||||
- Node.js 20+ and npm when rebuilding the bundled Frida 17 agents.
|
||||
|
||||
### Build
|
||||
|
||||
```text
|
||||
python tools/fetch_frida_gadget.py
|
||||
npm ci
|
||||
python tools/build_frida_agents.py
|
||||
./gradlew :app:assembleDebug :Bcore:testDebugUnitTest :app:testDebugUnitTest :app:check
|
||||
```
|
||||
|
||||
Windows paths containing spaces need the scoped native-build workaround
|
||||
documented in [docs/BUILDING.md](docs/BUILDING.md). The output is written under
|
||||
`app/build/outputs/apk/debug/`.
|
||||
|
||||
### Use
|
||||
|
||||
1. Install and open FridaBox.
|
||||
2. Tap **Import APK** and select an ARM64 base APK.
|
||||
3. Choose **On-device**, **Computer**, or **Clean** on that guest's card.
|
||||
4. Select an agent for On-device mode, or attach normally in Computer mode.
|
||||
5. Inspect live state in the **Runtime** tab.
|
||||
|
||||
See [docs/USAGE.md](docs/USAGE.md) and
|
||||
[docs/FRIDA_CONNECTION.md](docs/FRIDA_CONNECTION.md) for the complete workflow.
|
||||
|
||||
## Engineering and research
|
||||
|
||||
FridaBox is the outcome of runtime investigation rather than a wrapper around a
|
||||
single `System.loadLibrary()` call. The project had to solve:
|
||||
|
||||
- ordering Gadget before guest `Application` creation without loading it in the
|
||||
host process;
|
||||
- preserving the guest's genuine `LoadedApk` ClassLoader for Java hooks;
|
||||
- discovering the right loopback Gadget among colliding virtual processes;
|
||||
- bundling `frida-java-bridge` explicitly for Frida 17 agents;
|
||||
- making autonomous Script interaction work with private, read-only artifacts;
|
||||
- maintaining reliable cross-process runtime state on Android;
|
||||
- recycling virtual processes so instrumentation mode never leaks;
|
||||
- satisfying Android 16 executable-file restrictions;
|
||||
- keeping the imported APK byte-identical and outside the real PackageManager;
|
||||
- producing reproducible debug/release builds across Windows path and NDK
|
||||
constraints;
|
||||
- replacing the inherited application shell with an independent FridaBox
|
||||
product while preserving the mature runtime engine boundary.
|
||||
|
||||
Each problem, failed assumption, narrow fix, and verification method is recorded
|
||||
in [the engineering journey](docs/ENGINEERING_JOURNEY.md).
|
||||
|
||||
## Repository map
|
||||
|
||||
```text
|
||||
app/ FridaBox Android product, UI, import and per-app policy
|
||||
Bcore/ Virtual Android runtime and instrumentation integration
|
||||
black-reflection/ Hidden-framework reflection layer used by the runtime
|
||||
compiler/ Compile-time reflection helpers
|
||||
sample-guest/ Deterministic hook demonstration target
|
||||
scripts/ Frida probe, bootstrap, sample and native agents
|
||||
tools/ Gadget fetch, agent build, forwarding and attach tools
|
||||
docs/ Build, usage, limitations and device evidence
|
||||
```
|
||||
|
||||
## Scope and limitations
|
||||
|
||||
FridaBox currently targets single-file ARM64 APKs. Split APK sets, privileged or
|
||||
system applications, full Google Play Services, Play Integrity, hardware-backed
|
||||
attestation, and perfect anti-instrumentation resistance are outside the current
|
||||
scope. Vendor behavior and hidden Android APIs can still affect compatibility.
|
||||
|
||||
FridaBox deliberately does not claim stealth. Frida mappings, sockets and
|
||||
threads; virtual stub processes; the shared host UID; Binder synthesis; and
|
||||
ClassLoader topology may all be observable. Read
|
||||
[docs/LIMITATIONS.md](docs/LIMITATIONS.md) and
|
||||
[docs/DETECTION_SURFACES.md](docs/DETECTION_SURFACES.md).
|
||||
|
||||
## Project status
|
||||
|
||||
FridaBox 4.0.0 is a device-validated research release. The full sample hook and
|
||||
three-mode guest flow have passed on a Samsung SM-S928B running ARM64 Android
|
||||
16/API 36. Compatibility reports for other devices and ROMs are welcome when
|
||||
they include reproducible logs and authorized test targets.
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md), [CONTRIBUTING.md](CONTRIBUTING.md), and
|
||||
[SECURITY.md](SECURITY.md). Repository owners can use the
|
||||
[GitHub publishing checklist](docs/GITHUB_PUBLISHING.md) for the first public
|
||||
push, branch protection, topics, and release setup.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
FridaBox stands on years of work by the Android instrumentation and
|
||||
virtualization communities.
|
||||
|
||||
- **[Frida](https://github.com/frida/frida)** provides the dynamic
|
||||
instrumentation engine, Frida Gadget, GumJS, the Java bridge, and the tooling
|
||||
model that makes this research possible. FridaBox pins and verifies Gadget
|
||||
17.16.0 and uses the official Frida 17 Java-agent toolchain.
|
||||
- **[NewBlackbox](https://github.com/ALEX5402/NewBlackbox)** and the broader
|
||||
**BlackBox** project lineage provided the virtual package/process/Binder/IO
|
||||
runtime foundation. FridaBox began from NewBlackbox commit
|
||||
`89b59836c66f173756a4ae258cf379a957649820`, then added its instrumentation
|
||||
lifecycle, controller protocol, per-app modes, integrity pipeline, research
|
||||
tooling, validation suite, and independent product surface.
|
||||
- The Android Open Source Project and its contributors provide the platform
|
||||
interfaces and runtime behavior this project studies.
|
||||
|
||||
Thank you to every upstream maintainer and researcher who published the work
|
||||
that made FridaBox possible. Ownership and license details are preserved in
|
||||
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
||||
|
||||
## License
|
||||
|
||||
FridaBox is distributed under the [Apache License 2.0](LICENSE). Bundled Frida
|
||||
components retain their own license terms; see
|
||||
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Security policy
|
||||
|
||||
## Supported version
|
||||
|
||||
FridaBox 4.x is the actively maintained research line. Older inherited launcher
|
||||
versions are not supported.
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Please use GitHub's private **Report a vulnerability** security-advisory flow for
|
||||
this repository when it is available. Do not open a public issue for a flaw that
|
||||
could expose imported APKs, JavaScript agents, device data, signing material, or
|
||||
an unintended network listener.
|
||||
|
||||
Include:
|
||||
|
||||
- affected commit/version and Android build;
|
||||
- device model, ABI, and ROM/vendor information;
|
||||
- a minimal reproduction using an APK you are allowed to share;
|
||||
- impact and the crossed trust boundary;
|
||||
- sanitized logs or a small proof of concept;
|
||||
- whether the issue reproduces in On-device, Computer, Clean, or all modes.
|
||||
|
||||
Please allow reasonable time for validation and a coordinated fix before public
|
||||
disclosure.
|
||||
|
||||
## Security model
|
||||
|
||||
- FridaBox processes APKs and JavaScript selected explicitly by the user.
|
||||
- Imported APKs and on-device agents are untrusted code and execute inside the
|
||||
host application's Android security boundary.
|
||||
- On-device agents have the same effective access as their virtual guest process.
|
||||
- Gadget is configured for device loopback. ADB forwarding is an explicit
|
||||
computer-side action.
|
||||
- Private files reduce accidental exposure but do not create a hardware-backed
|
||||
isolation boundary between the host, guest, and agent.
|
||||
- FridaBox is not designed to hide from a hostile guest, kernel inspection,
|
||||
SELinux inspection, Play Integrity, hardware attestation, or advanced RASP.
|
||||
|
||||
## Responsible use
|
||||
|
||||
Use FridaBox only on software and devices you own or are explicitly authorized
|
||||
to assess. The maintainers do not support credential theft, unauthorized access,
|
||||
surveillance, malware deployment, piracy, or bypassing protections outside a
|
||||
lawful research or defensive-testing scope.
|
||||
@@ -6,6 +6,18 @@ FridaBox is based on `ALEX5402/NewBlackbox` commit
|
||||
`89b59836c66f173756a4ae258cf379a957649820`. The foundation repository includes
|
||||
an Apache License 2.0 notice; see the repository root `LICENSE` file.
|
||||
|
||||
FridaBox gratefully acknowledges NewBlackbox and the wider BlackBox project
|
||||
lineage for the virtual package, process, Binder, filesystem, identity,
|
||||
signature, component, and lifecycle foundation. FridaBox's own work builds a
|
||||
separate instrumentation product on that foundation: early Gadget integration,
|
||||
guest runtime discovery, controller tooling, per-app launch modes, integrity and
|
||||
ABI validation, on-device agent execution, the FridaBox UI, and the associated
|
||||
test and research documentation.
|
||||
|
||||
- NewBlackbox source: `https://github.com/ALEX5402/NewBlackbox`
|
||||
- Pinned foundation revision:
|
||||
`https://github.com/ALEX5402/NewBlackbox/commit/89b59836c66f173756a4ae258cf379a957649820`
|
||||
|
||||
## Frida Gadget 17.16.0
|
||||
|
||||
- Origin: `https://github.com/frida/frida/releases/tag/17.16.0`
|
||||
@@ -26,6 +38,10 @@ authoritative text is available at
|
||||
Frida is copyright its respective contributors. FridaBox makes no claim of
|
||||
ownership over Frida Gadget.
|
||||
|
||||
FridaBox gratefully acknowledges the Frida maintainers and contributors for the
|
||||
instrumentation engine, GumJS runtime, Java bridge, Gadget deployment model, and
|
||||
controller APIs that make this research possible.
|
||||
|
||||
## Frida Java bridge and agent compiler
|
||||
|
||||
The compiled JavaScript agents under `scripts/dist/` include
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 MiB |
@@ -0,0 +1,256 @@
|
||||
# Engineering journey
|
||||
|
||||
This document records the engineering problems that turned FridaBox from a
|
||||
virtual-app proof of concept into a repeatable instrumentation workspace. It is
|
||||
not a claim that every Android application will run; it is a map of the concrete
|
||||
failure modes investigated, the narrow fixes selected, and the evidence used to
|
||||
accept those fixes.
|
||||
|
||||
## 1. Establishing a buildable baseline
|
||||
|
||||
### Problem
|
||||
|
||||
The inherited project did not build reproducibly on the available Windows host.
|
||||
AGP marker resolution differed from direct module resolution, the requested NDK
|
||||
revision was unavailable, and `ndk-build` could not parse an `APP_BUILD_SCRIPT`
|
||||
path containing spaces.
|
||||
|
||||
### Resolution
|
||||
|
||||
- Map Android plugin IDs to the official AGP module.
|
||||
- Use the installed complete NDK 29.0.14206865 revision explicitly.
|
||||
- Add a Bcore-scoped `FRIDABOX_NDK_PROJECT_DIR` override so only the native
|
||||
build sees a no-space junction path.
|
||||
- Record the exact deviation instead of silently changing toolchains.
|
||||
|
||||
### Evidence
|
||||
|
||||
The baseline investigation and commands are preserved in
|
||||
[`BASELINE.md`](BASELINE.md). Both Java/Kotlin and native ARM64 builds now run
|
||||
from the workspace path.
|
||||
|
||||
## 2. Finding the only useful early-load point
|
||||
|
||||
### Problem
|
||||
|
||||
Loading Gadget in the host `Application` instruments the wrong process. Loading
|
||||
after guest `Application.onCreate()` is too late for early hooks. Loading before
|
||||
virtual identity, IO redirection, and `LoadedApk` creation leaves Frida without
|
||||
the correct guest environment.
|
||||
|
||||
### Resolution
|
||||
|
||||
Insert `FridaGadgetLoader.loadIfEnabled()` inside
|
||||
`BActivityThread.handleBindApplication()` after runtime/native/ClassLoader setup
|
||||
and before `makeApplication()`.
|
||||
|
||||
### Evidence
|
||||
|
||||
The sample guest logs `attachBaseContext` and `onCreate`. During Computer mode,
|
||||
neither appeared until the Gadget client attached. A build verification task
|
||||
also rejects source ordering regressions.
|
||||
|
||||
## 3. Preserving the original APK
|
||||
|
||||
### Problem
|
||||
|
||||
The common Gadget workflow mutates and resigns an APK, which changes the object
|
||||
under study. Importing through Android's PackageInstaller would also place the
|
||||
guest in the real system package database.
|
||||
|
||||
### Resolution
|
||||
|
||||
Stream the selected base APK through SAF into private storage, hash while
|
||||
copying, inspect the archive, verify the private copy again, make it read-only,
|
||||
and install only through the virtual package manager.
|
||||
|
||||
### Evidence
|
||||
|
||||
The generated sample asset and imported copy were byte-identical. `adb shell pm
|
||||
list packages` did not contain the sample package while FridaBox could launch it.
|
||||
|
||||
## 4. Selecting the guest ClassLoader
|
||||
|
||||
### Problem
|
||||
|
||||
Frida's default Java factory can observe the host loader first in a virtual
|
||||
process. A valid guest class then appears missing even though the application is
|
||||
running.
|
||||
|
||||
### Resolution
|
||||
|
||||
Store the actual `LoadedApk` ClassLoader in `GuestRuntimeRegistry`. Load a
|
||||
bootstrap agent before the user's script and assign that loader to
|
||||
`Java.classFactory.loader`, with bounded retries during transient startup.
|
||||
|
||||
### Evidence
|
||||
|
||||
The controller reported `dalvik.system.PathClassLoader` and the sample hook
|
||||
resolved `com.qm4rs.fridabox.sample.Target` before `Application.onCreate()`.
|
||||
|
||||
## 5. Discovering the correct Gadget endpoint
|
||||
|
||||
### Problem
|
||||
|
||||
Every virtual guest process begins with the same preferred Gadget port. Multiple
|
||||
processes may move to fallback ports, while another unrelated Frida endpoint may
|
||||
already exist on the device. A fixed `adb forward tcp:27042 tcp:27042` cannot
|
||||
identify which guest it reached.
|
||||
|
||||
### Resolution
|
||||
|
||||
Use Gadget's bounded `pick-next` range, forward each candidate, probe it with a
|
||||
FridaBox registry agent, reject endpoints without the expected registry, and map
|
||||
valid endpoints to package and process.
|
||||
|
||||
### Evidence
|
||||
|
||||
`tools/attach_guest.py --list` discovered the correct sample endpoint and printed
|
||||
package, process, user ID, virtual process ID, source APK, and ClassLoader.
|
||||
|
||||
## 6. Adapting agents to Frida 17
|
||||
|
||||
### Problem
|
||||
|
||||
Frida 17 API-loaded agents no longer receive the Java bridge implicitly. Plain
|
||||
source scripts could load yet fail when calling `Java.perform()`.
|
||||
|
||||
### Resolution
|
||||
|
||||
Pin `frida-java-bridge` 7.0.13 and `frida-compile` 19.0.5, import the bridge
|
||||
explicitly, commit reproducible bundles under `scripts/dist`, and teach the
|
||||
controller to choose a compiled counterpart automatically.
|
||||
|
||||
### Evidence
|
||||
|
||||
Clean `npm ci` agent builds succeeded and the bundled sample hook changed
|
||||
`Target.add(2, 3)` to `1337`.
|
||||
|
||||
## 7. Running an agent without a computer
|
||||
|
||||
### Problem
|
||||
|
||||
Interactive Gadget listen mode requires a host to attach and resume execution.
|
||||
It cannot deliver the requested cable-free, persistent per-app behavior.
|
||||
|
||||
### Resolution
|
||||
|
||||
Add a per-package Script interaction mode. FridaBox copies the selected agent
|
||||
byte-for-byte into private storage, records its SHA-256, generates an adjacent
|
||||
relative-path config, and loads a private Gadget copy on every On-device launch.
|
||||
|
||||
### Evidence
|
||||
|
||||
A 198,960-byte real-world agent was imported with an identical SHA-256, marked
|
||||
0400, loaded without a controller, and reached `local_script_active` before the
|
||||
Unity guest became interactive.
|
||||
|
||||
## 8. Preventing launch-mode leakage
|
||||
|
||||
### Problem
|
||||
|
||||
Gadget is a native library. Once loaded, switching a living process to Clean
|
||||
mode cannot reliably reverse its threads, mappings, hooks, or listener.
|
||||
|
||||
### Resolution
|
||||
|
||||
Treat mode changes as process-boundary changes. Stop the virtual package before
|
||||
every relaunch and make each new process read the current per-package policy.
|
||||
|
||||
### Evidence
|
||||
|
||||
The validated clean launch used a different PID, emitted an explicit disabled
|
||||
state, opened no Gadget listener, and restored the sample result from `1337` to
|
||||
`5`.
|
||||
|
||||
## 9. Making runtime state honest across processes
|
||||
|
||||
### Problem
|
||||
|
||||
The guest registry is process-local. A host-screen read of cached
|
||||
SharedPreferences could display stale `Waiting for computer` state even after an
|
||||
On-device agent was active in another process.
|
||||
|
||||
### Resolution
|
||||
|
||||
Keep the registry authoritative inside the guest and use a deliberately small
|
||||
controller snapshot with cross-process reload semantics for presentation.
|
||||
|
||||
### Evidence
|
||||
|
||||
The persisted state was correct during the failure. Reloading eliminated the
|
||||
stale host display and subsequent On-device launches reported
|
||||
`local_script_active` consistently.
|
||||
|
||||
## 10. Android 16 executable-file constraints
|
||||
|
||||
### Problem
|
||||
|
||||
Copying a writable native executable into app-private storage triggered modern
|
||||
Android warnings and created an avoidable writable/executable overlap.
|
||||
|
||||
### Resolution
|
||||
|
||||
Finish copying and configuration first, then set the private Gadget executable
|
||||
to mode 0555 and the agent to 0400 before loading.
|
||||
|
||||
### Evidence
|
||||
|
||||
The final Android 16 run reported the expected permissions and no longer emitted
|
||||
the writable-executable warning for the private Gadget copy.
|
||||
|
||||
## 11. Building a real product boundary
|
||||
|
||||
### Problem
|
||||
|
||||
The inherited launcher mixed unrelated cloning, GMS, Xposed, fake-location, and
|
||||
floating-overlay features with the instrumentation research. Its namespace,
|
||||
resources, dependencies, and branding obscured the actual FridaBox workflow.
|
||||
|
||||
### Resolution
|
||||
|
||||
- Replace the launcher with a FridaBox-owned workspace and runtime UI.
|
||||
- Move all host source and tests to `com.qm4rs.fridabox`.
|
||||
- Replace the inherited `Application` shell with a minimal FridaBox runtime
|
||||
bootstrap.
|
||||
- Remove 7,000+ lines of unused UI code, obsolete resources, legacy AARs, and
|
||||
stale product documentation.
|
||||
- Keep the mature runtime engine as an internal compatibility boundary and
|
||||
preserve its required attribution.
|
||||
|
||||
### Evidence
|
||||
|
||||
Debug/release assembly, app/Bcore tests, lint/check, reinstall, launcher resume,
|
||||
guest restoration, and a real Clean-mode Unity launch all passed after removal.
|
||||
|
||||
## 12. Release safety and reproducibility
|
||||
|
||||
### Problem
|
||||
|
||||
Research APKs often accidentally ship with a debug key or depend on locally
|
||||
generated assets whose provenance cannot be reproduced.
|
||||
|
||||
### Resolution
|
||||
|
||||
- Release signing is configured only when all four explicit keystore variables
|
||||
are present; partial configuration fails and no debug fallback exists.
|
||||
- R8 and resource shrinking are enabled for release.
|
||||
- Gadget version and SHA-256 are pinned and verified before every app build.
|
||||
- The debug sample is generated and embedded byte-identically.
|
||||
- Frida 17 agents are reproducible from lockfile-pinned npm dependencies.
|
||||
|
||||
### Evidence
|
||||
|
||||
The debug signature verified, the unsigned release contained no debug signature,
|
||||
and all custom integrity/order/packaging tasks passed. Current artifact hashes
|
||||
are recorded in [`TEST_RESULTS.md`](TEST_RESULTS.md).
|
||||
|
||||
## Current research boundary
|
||||
|
||||
FridaBox demonstrates a robust architecture for ordinary single-file ARM64 APKs,
|
||||
not universal Android virtualization. Split delivery, privileged/system apps,
|
||||
Play Integrity, hardware-backed attestation, isolated services, WebView renderer
|
||||
processes, and adversarial commercial RASP remain distinct research problems.
|
||||
The project documents these boundaries rather than hiding them; see
|
||||
[`LIMITATIONS.md`](LIMITATIONS.md) and
|
||||
[`DETECTION_SURFACES.md`](DETECTION_SURFACES.md).
|
||||
@@ -9,7 +9,7 @@ python tools/build_frida_agents.py
|
||||
```
|
||||
|
||||
The Gadget listens only on device loopback. The controller verifies ADB, selects
|
||||
an authorized device, forwards TCP 27042–27073, probes each endpoint, rejects
|
||||
an authorized device, forwards TCP 27042-27073, probes each endpoint, rejects
|
||||
non-Gadget/non-FridaBox endpoints, and maps endpoints through
|
||||
`GuestRuntimeRegistry`.
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# GitHub publishing checklist
|
||||
|
||||
This repository is prepared to publish under the project name **FridaBox**.
|
||||
|
||||
## Suggested About description
|
||||
|
||||
> Android research workspace for per-app Frida Gadget instrumentation: on-device
|
||||
> JavaScript, desktop attach, and clean launches without root or APK patching.
|
||||
|
||||
## Suggested topics
|
||||
|
||||
```text
|
||||
android
|
||||
android-security
|
||||
arm64
|
||||
dynamic-analysis
|
||||
frida
|
||||
frida-gadget
|
||||
instrumentation
|
||||
mobile-security
|
||||
reverse-engineering
|
||||
virtualization
|
||||
kotlin
|
||||
research
|
||||
```
|
||||
|
||||
## Repository settings
|
||||
|
||||
- Set the default branch to `main`.
|
||||
- Enable Issues and private vulnerability reporting.
|
||||
- Enable Actions with read-only default workflow permissions.
|
||||
- Add branch protection requiring the **Build, test, and verify** check.
|
||||
- Require pull requests and dismiss stale approvals after new commits.
|
||||
- Prevent force pushes and branch deletion on `main`.
|
||||
- Enable Dependabot alerts and security updates.
|
||||
- Add a social preview image only when it reflects the current FridaBox UI.
|
||||
|
||||
Do not reuse the removed legacy BlackBox64 GIF as the social preview.
|
||||
|
||||
## First push
|
||||
|
||||
Review the destination remote before pushing:
|
||||
|
||||
```text
|
||||
git remote -v
|
||||
git status
|
||||
git log --oneline -5
|
||||
```
|
||||
|
||||
Then push the intended branch explicitly:
|
||||
|
||||
```text
|
||||
git push -u origin feature/fridabox-mvp
|
||||
```
|
||||
|
||||
If this branch is intended to become the public default, create/review a pull
|
||||
request into `main` and let Android CI finish before merging.
|
||||
|
||||
## Release checklist
|
||||
|
||||
1. Update `versionCode`, `versionName`, and `CHANGELOG.md`.
|
||||
2. Run the host test and verification commands from `docs/BUILDING.md`.
|
||||
3. Complete the device flow in `docs/TEST_RESULTS.md` on at least one supported
|
||||
ARM64 Android version.
|
||||
4. Build with all four `FRIDABOX_RELEASE_*` signing variables set.
|
||||
5. Verify the release signature, packaged ABIs, Gadget hash, and absence of a
|
||||
debug certificate.
|
||||
6. Publish checksums with the APK and identify the tested device/Android build.
|
||||
7. State known limitations and never describe FridaBox as undetectable.
|
||||
|
||||
The CI-produced release APK is intentionally unsigned unless a separate secure
|
||||
release process provides signing credentials. Never store a keystore or signing
|
||||
secret in the repository or workflow file.
|
||||
Reference in New Issue
Block a user