This change introduces the ability to patch local APK files or directories, support for separate source and target devices, and detection of common anti-tampering libraries. Key changes: - **Local APK Support**: Added `--apk <path>` flag to use local `.apk` files or split-APK directories instead of pulling from a device. - **Two-Device Workflow**: Added `--source <serial>` flag to pull an APK from one device (e.g., a Play Store emulator) and install the patched version on another (e.g., a `userdebug` emulator). - **Anti-Tampering Detection**: The patching script now scans for known integrity-protection libraries (e.g., PairIP, DexGuard, Bangcle) and issues a warning if detected. - **Improved Disassembly**: Introduced a `--no-res` optimization when user certificate trust is not required, avoiding common `apktool` resource decoding errors. - **Package Name Extraction**: Integrated `aapt2` to automatically detect package names from local APK files for cleaner uninstalls. - **Enhanced Device Selection**: Updated the interactive menu to handle source/target selection and filter unauthorized devices more effectively. - **Documentation**: Updated `README.md` and `CLAUDE.md` with new usage examples and information regarding anti-tampering limitations.
95 lines
No EOL
7 KiB
Markdown
95 lines
No EOL
7 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
Three Bash scripts for making Android APKs debuggable and intercepting traffic:
|
|
- **`apk-debuggable.sh`** — End-to-end automation that handles device selection, APK extraction, patching (via `lib/make-debuggable.sh`), and reinstallation. Forwards `--trust-user-certs` to `lib/make-debuggable.sh`.
|
|
- **`lib/make-debuggable.sh`** — Core tool that converts release APKs into debuggable versions. It disassembles the APK, patches `AndroidManifest.xml` to set `android:debuggable="true"`, reassembles, and re-signs with a debug keystore. Optionally injects `network_security_config.xml` to trust user CA certs (`--trust-user-certs`).
|
|
- **`lib/proxy-setup.sh`** — Starts mitmproxy in Docker, restarts a running Android emulator with HTTP proxy enabled, and installs the mitmproxy CA certificate.
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
# Automated end-to-end (device → extract → patch → reinstall)
|
|
./apk-debuggable.sh <app-name> [--device <serial>] [--keep] [--trust-user-certs] [--proxy]
|
|
|
|
# Use a local APK file or split-APK directory
|
|
./apk-debuggable.sh --apk <path> [--device <serial>] [--keep] [--trust-user-certs] [--proxy]
|
|
|
|
# Single APK
|
|
./lib/make-debuggable.sh <path-to-apk> [output-apk] [--trust-user-certs]
|
|
|
|
# Split APK directory (contains base.apk + split APKs)
|
|
./lib/make-debuggable.sh <directory> [output-directory] [--trust-user-certs]
|
|
|
|
# Start mitmproxy and restart emulator with proxy
|
|
./lib/proxy-setup.sh
|
|
|
|
# Stop mitmproxy
|
|
./lib/proxy-setup.sh --stop
|
|
```
|
|
|
|
There are no build, test, or lint commands.
|
|
|
|
## Script Architecture
|
|
|
|
`lib/make-debuggable.sh` is organized into these key functions:
|
|
|
|
- **`find_android_tools()`** — Auto-discovers Android SDK, apksigner, Java/JDK, keytool, and apktool from standard macOS paths and environment variables (`ANDROID_HOME`, `ANDROID_SDK_ROOT`, `JAVA_HOME`)
|
|
- **`ensure_keystore()`** — Generates a debug keystore (`debug-resign.keystore`) if one doesn't exist
|
|
- **`sign_apk()`** — Signs an APK using apksigner with the debug keystore
|
|
- **`inject_network_security_config()`** — Creates `res/xml/network_security_config.xml` trusting system + user CAs, patches manifest to reference it. Called when `--trust-user-certs` is set.
|
|
- **`process_single_apk()`** — Disassembles APK via apktool, patches the manifest with `sed`, optionally injects network security config, reassembles, signs, and verifies
|
|
- **`process_split_apks()`** — Handles split APK bundles by processing `base.apk` then signing all splits
|
|
- **`main()`** — Entry point that parses `--trust-user-certs` flag, detects input type (file vs directory), and routes accordingly
|
|
|
|
### `apk-debuggable.sh` Architecture
|
|
|
|
Automation wrapper that orchestrates the full device-to-device workflow. Each function sets globals consumed by subsequent steps:
|
|
|
|
- **`parse_args()`** — Parses positional `APP_NAME` + optional `--apk`, `--device`, `--keep`, `--trust-user-certs`, `--proxy` flags (`--proxy` implies `--trust-user-certs`). Validates that exactly one of `APP_NAME` or `--apk` is provided.
|
|
- **`find_adb()`** — Discovers `adb` from SDK locations or PATH (same pattern as `find_android_tools()`)
|
|
- **`find_aapt2()`** — Discovers `aapt2` from latest `build-tools/*/aapt2` in SDK locations, fallback to `command -v aapt2`. Used only in `--apk` mode for package name extraction.
|
|
- **`select_device()`** — Parses `adb devices`, skips unauthorized; auto-selects if one device, interactive numbered menu if multiple. Fetches `ro.product.model` for display.
|
|
- **`prepare_local_apk()`** — (when `--apk`) For directory input, uses the path as-is as `PULL_DIR`. For single APK, copies to temp dir `apks_local_<basename>`. Extracts `PACKAGE_NAME` via `aapt2 dump badging` (soft failure if aapt2 unavailable).
|
|
- **`select_package()`** — Runs `adb shell pm list packages | grep -i <name>`; auto-selects if one match, interactive menu if multiple
|
|
- **`pull_apks()`** — Gets paths via `adb shell pm path`, pulls each to `apks_<package>/` directory
|
|
- **`make_debuggable()`** — Delegates to `./lib/make-debuggable.sh <pull-dir>` (directory mode), forwarding `--trust-user-certs` if set. Output lands in `<pull-dir>_debuggable/`.
|
|
- **`install_apks()`** — Uninstalls existing package if `PACKAGE_NAME` is known (non-fatal), then `adb install` or `adb install-multiple` depending on APK count
|
|
- **`cleanup()`** — Removes temp directories unless `--keep` flag was set. Never deletes a user-provided `--apk` directory.
|
|
- **`start_proxy()`** — (when `--proxy`) Starts mitmproxy Docker container with `--set web_password`, pushes CA cert to device, waits for web UI. Always restarts the container fresh to avoid stale state.
|
|
|
|
Proxy globals: `CONTAINER_NAME="mitmproxy-android"`, `PROXY_PORT=8080`, `WEB_PORT=8081`, `PROXY_PASSWORD="proxy"`, `MITMPROXY_DIR="$HOME/.mitmproxy"`.
|
|
|
|
Main flow: `find_adb → select_device → [prepare_local_apk | select_package + pull_apks] → make_debuggable → install_apks → cleanup`
|
|
|
|
Key conventions: all `adb` commands use `-s "$DEVICE_SERIAL"`, all `adb shell` output stripped of `\r` with `tr -d '\r'`, `grep` calls that may match zero use `|| true` to avoid `set -e` abort.
|
|
|
|
### `lib/proxy-setup.sh` Architecture
|
|
|
|
Sets up mitmproxy in Docker and configures an Android emulator to route traffic through it:
|
|
|
|
- **`parse_args()`** — Parses `--stop` and `--port <port>` flags
|
|
- **`find_tools()`** — Discovers `adb`, `emulator` binary, and checks Docker availability
|
|
- **`stop_proxy()`** — Stops the `mitmproxy-android` Docker container (used with `--stop`)
|
|
- **`start_mitmproxy()`** — Runs mitmproxy Docker container (detached, `--rm`, named `mitmproxy-android`), volume-mounts `~/.mitmproxy` for cert persistence. Polls for CA cert file to appear.
|
|
- **`find_emulator()`** — Finds running emulators from `adb devices` (entries matching `emulator-*`). Gets AVD name via `adb emu avd name`. Interactive menu if multiple.
|
|
- **`restart_emulator()`** — Kills running emulator, waits for it to disappear, relaunches with `-http-proxy http://127.0.0.1:$PROXY_PORT`, waits for boot via `sys.boot_completed`.
|
|
- **`install_cert()`** — Pushes `~/.mitmproxy/mitmproxy-ca-cert.cer` to emulator, attempts automated cert install via intent, prints manual fallback instructions.
|
|
- **`print_summary()`** — Displays proxy URL, web UI URL, device info, and usage tips.
|
|
|
|
Key details: Docker container uses `--rm` for auto-cleanup, `~/.mitmproxy` volume persists certs across runs, emulator launched in background with `&`.
|
|
|
|
## Platform Notes
|
|
|
|
- **macOS-specific**: Uses `sed -i ''` (BSD sed syntax) and searches macOS paths like `/Applications/Android Studio.app` for bundled JDK
|
|
- Requires: Android SDK (build-tools), apktool (`brew install apktool` or jar), Java/JDK
|
|
- `lib/proxy-setup.sh` additionally requires Docker and an Android emulator
|
|
|
|
## Hardcoded Configuration
|
|
|
|
Keystore credentials are intentionally hardcoded for debug use:
|
|
- Keystore: `debug-resign.keystore`, alias: `debug_key`, password: `debugpass123`
|
|
- Work directory: `apk-disassembled` (cleaned up after processing) |