
Sandbox di clonazione di app Android con una CLI in stile Frida che avvia o si collega ad app clonate e inietta script QuickJS utilizzando Gum Interceptor e hook Stalker.

Spindle è il client da riga di comando. Invia uno script nell'host BBA o in un'app clonata e restituisce i log. I flag seguono la riga di comando di Frida: spawn con -f, attach con -n o -p, caricamento di un file con -l.
BBA stesso è una sandbox di clonazione di app Android. Il pacchetto host è com.android.bba. Un'app clonata viene eseguita all'interno di quel pacchetto, non come installazione normale. Installa l'APK, apri il clone dall'interfaccia di BBA, poi usa Spindle. Gli script vengono eseguiti solo su arm64, in QuickJS, con Interceptor e Stalker di Frida Gum.

La macchina di sviluppo non si connette mai direttamente a un clone. Comunica solo con com.android.bba:black su 127.0.0.1:2408. Il processo host e ogni clone sono agenti: si registrano via Binder, ricevono lo script e restituiscono i log. La modalità USB esegue adb forward tcp:0 tcp:2408 per te.
Dalla radice del repository, con un dispositivo collegato:
# Stop the clone on user 0, start it, inject, then let it continue
python3 tools/spindle -U -f com.example.app -l tools/test_js_api.js
# Attach to a clone that is already running
python3 tools/spindle -U -n com.example.app -l tools/test_native_hook.js
# Attach to a pid, including the host process com.android.bba
python3 tools/spindle -U -p 12345 -l tools/test_js_api.js
# One line of script, no file
python3 tools/spindle -U -n com.example.app -e 'console.log("hi")'
# Registered processes, JSON
python3 tools/spindle -U --list
# Same list, as a table
python3 tools/spindle-ps -U
-f è lo spawn. Il client invia lo script, poi UNLOCK. Il clone attende sul percorso di avvio finché quel frame non arriva, così lo script è in posizione prima di Application.onCreate. -f usa sempre l'utente 0.
-n e -p eseguono l'attach. Il processo deve essersi già registrato. Un nome è il nome del processo registrato da Spindle, di solito il nome del pacchetto clonato. Il processo UI dell'host è com.android.bba.
Più di un telefono:
python3 tools/spindle -D <serial> -n com.example.app -l tools/test_js_api.js
Se la porta è già inoltrata, salta adb:
python3 tools/spindle -H 127.0.0.1:2408 -n com.example.app -l tools/test_js_api.js
-H, -U e -D scelgono la connessione. Passane solo uno. Passa solo uno tra -f, -n e -p.
Il client resta attivo e stampa console.log finché il processo non termina, il server non cade o non premi Ctrl-C.
Uno script è semplice JavaScript. Questi esempi si trovano in tools/:
| File | Cosa fa |
|---|---|
test_js_api.js | Memory, puntatori, Module, Interceptor |
test_native_hook.js | Interceptor.attach("libz.so!deflate", …) |
test_java_hook.js | Java.hook su Activity.onCreate |
test_stalker.js | Stalker.follow dall'interno di un hook |
test_rpc.js | rpc.exports chiamato dalla riga di comando |
console.log torna come riga di log. Su armeabi-v7a non c'è runtime; una RPC lì risponde con js runtime is not in bba.
Chiama un export dopo il caricamento dello script. --args è un array JSON e si allinea con il corrispondente --call:
python3 tools/spindle -U -n com.example.app -l tools/test_rpc.js --call ping --args '["hi"]'
Questo stampa pong hi, poi continua ad attendere i log.
Gruppo chat: openbba. Il codice scade il 20 ottobre 2026.
