diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index ea23ea2..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -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 ] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..c997646 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..62883a5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -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 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..45b2389 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -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. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ac98147 --- /dev/null +++ b/.github/dependabot.yml @@ -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 diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..b63b43e --- /dev/null +++ b/.github/workflows/android.yml @@ -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 diff --git a/.github/workflows/build_and_telegram.yml b/.github/workflows/build_and_telegram.yml deleted file mode 100644 index 18ed8a2..0000000 --- a/.github/workflows/build_and_telegram.yml +++ /dev/null @@ -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 - diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 609c379..9a63ad1 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -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. | diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a1fda31 --- /dev/null +++ b/CHANGELOG.md @@ -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). diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d496f49 --- /dev/null +++ b/CODE_OF_CONDUCT.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. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2ed4b2d --- /dev/null +++ b/CONTRIBUTING.md @@ -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. diff --git a/README.md b/README.md index aabfbbf..e198aad 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,295 @@ +
+ # 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`. +[![Android](https://img.shields.io/badge/Android-12--16-3DDC84?logo=android&logoColor=white)](docs/TEST_RESULTS.md) +[![ABI](https://img.shields.io/badge/ABI-arm64--v8a-5C6BC0)](docs/BUILDING.md) +[![Frida](https://img.shields.io/badge/Frida_Gadget-17.16.0-FF6B35)](THIRD_PARTY_NOTICES.md) +[![Release](https://img.shields.io/badge/release-4.0.0-00BFA5)](CHANGELOG.md) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE) +[![Status](https://img.shields.io/badge/status-device--validated-success)](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). +
-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). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..03a445c --- /dev/null +++ b/SECURITY.md @@ -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. diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index fb3cf91..2893e82 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -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 diff --git a/assets/usage.gif b/assets/usage.gif deleted file mode 100644 index ef2bbb7..0000000 Binary files a/assets/usage.gif and /dev/null differ diff --git a/docs/ENGINEERING_JOURNEY.md b/docs/ENGINEERING_JOURNEY.md new file mode 100644 index 0000000..d4e4d64 --- /dev/null +++ b/docs/ENGINEERING_JOURNEY.md @@ -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). diff --git a/docs/FRIDA_CONNECTION.md b/docs/FRIDA_CONNECTION.md index 3d2cfba..c907f26 100644 --- a/docs/FRIDA_CONNECTION.md +++ b/docs/FRIDA_CONNECTION.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`. diff --git a/docs/GITHUB_PUBLISHING.md b/docs/GITHUB_PUBLISHING.md new file mode 100644 index 0000000..ccd1c48 --- /dev/null +++ b/docs/GITHUB_PUBLISHING.md @@ -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.