A continuación los pasos seguidos para habilitar el menú developer en un
celular con sistema operativo KaiOS 2.5 (sucesor de Firefox OS).
Datos del celular (por más informacion ver el manual de usuario):
- R3Di FR150 Bright Flip Phone
- OS: KaiOS 2.5.4 Version B166
Comunicación con celular en modo EDL
Para realizar el cambios en las particiones del celular debemos poner a este en en modo EDL.
Para ello, con el celular sin batería alimentado solo por cable usb conectado a
la computadora. Se presionan los botones * + #, se conecta el usb y
verificamos que haya entrado en modo EDL usando lsusb:
$ lsusb
Bus 002 Device 038: ID 05c6:9008 Qualcomm, Inc. Gobi Wireless Modem (QDL mode)
Se debe instalar el programa edl para comunicarse con el celular cuando se
encuentre en modo EDL.
Este programa se encuentra en el repositorio https://github.com/bkerler/edl/.
Seguimos los pasos para instalarlo:
$ cd ~/workspace
$ git clone https://github.com/bkerler/edl
$ cd edl
$ git submodule update --init --recursive
$ python3 -m venv ENV
$ source ENV/bin/activate
$ pip install -r requirements.txt
...
Installing collected packages: pyserial, passlib, keystone-engine, docopt, wheel, urllib3, qrcode, pyusb, pycryptodomex, pycryptodome, pycparser, lxml, invoke, idna, future, configparser, colorama, charset_normalizer, certifi, capstone, bcrypt, requests, cffi, pynacl, cryptography, paramiko, Exscript
Successfully installed Exscript-2.6.32 bcrypt-5.0.0 capstone-5.0.6 certifi-2025.11.12 cffi-2.0.0 charset_normalizer-3.4.4 colorama-0.4.6 configparser-7.2.0 cryptography-46.0.3 docopt-0.6.2 future-1.0.0 idna-3.11 invoke-2.2.1 keystone-engine-0.9.2 lxml-6.0.2 paramiko-4.0.0 passlib-1.7.4 pycparser-2.23 pycryptodome-3.23.0 pycryptodomex-3.23.0 pynacl-1.6.1 pyserial-3.5 pyusb-1.3.1 qrcode-8.2 requests-2.32.5 urllib3-2.6.2 wheel-0.45.1
Ahora ejecutamos el programa edl para verificar que podemos comunicarnos con el celular que se encuentra en modo EDL
Qualcomm Sahara / Firehose Client V3.62 (c) B.Kerler 2018-2025.
main - Trying with no loader given ...
main - Waiting for the device
main - Device detected :)
sahara - Protocol version: 2, Version supported: 1
main - Mode detected: sahara
sahara -
Version 0x2
------------------------
HWID: 0x009600e100000000 (MSM_ID:0x009600e1,OEM_ID:0x0000,MODEL_ID:0x0000)
CPU detected: "MSM8909"
PK_HASH: 0xcc3153a80293939b90d02d3bf8b23e0292e452fef662c74998421adad42a380f
Serial: 0x1f2a7c5e
sahara - Possibly unfused device detected, so any loader should be fine...
sahara - Trying loader: /home/jmpc/workspace/edl/edlclient/../Loaders/qualcomm/model_generic/msm8909/009600e100000000_cc3153a80293939b_fhprg_peek.bin
sahara - Protocol version: 2, Version supported: 1
sahara - Uploading loader /home/jmpc/workspace/edl/edlclient/../Loaders/qualcomm/model_generic/msm8909/009600e100000000_cc3153a80293939b_fhprg_peek.bin ...
sahara - 32-Bit mode detected.
sahara - Firehose mode detected, uploading...
sahara - Loader successfully uploaded.
Backup de particiones
Lo primero que debemos hacer es un backup de las particiones del celular.
$ mkdir -p ~/workspace/r3di-fr150-backup
$ ./edl rl ~/workspace/r3di-fr150-backup --genxml
Qualcomm Sahara / Firehose Client V3.62 (c) B.Kerler 2018-2025.
main - Trying with no loader given ...
main - Waiting for the device
main - Device detected :)
main - Mode detected: firehose
firehose
firehose - [LIB]: Sector size in XML 4096 does not match disk sector size 512
Wrote partition xml as rawprogram0.xml
Progress: |██████████| 100.0% Read (Sector 0x20000 of 0x20000, ) 15.24 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 15.09 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 15.10 MB/s
Progress: |██████████| 100.0% Read (Sector 0x800 of 0x800, ) 15.05 MB/s
Progress: |██████████| 100.0% Read (Sector 0x800 of 0x800, ) 15.00 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 14.47 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 15.27 MB/s
Progress: |██████████| 100.0% Read (Sector 0x1000 of 0x1000, ) 15.21 MB/s
Progress: |██████████| 100.0% Read (Sector 0x1000 of 0x1000, ) 14.97 MB/s
Progress: |██████████| 100.0% Read (Sector 0x200 of 0x200, ) 14.87 MB/s
Progress: |██████████| 100.0% Read (Sector 0x200 of 0x200, ) 14.97 MB/s
Progress: |██████████| 100.0% Read (Sector 0x800 of 0x800, ) 15.03 MB/s
Progress: |██████████| 100.0% Read (Sector 0xC00 of 0xC00, ) 12.50 MB/s
Progress: |██████████| 100.0% Read (Sector 0xC00 of 0xC00, ) 12.19 MB/s
Progress: |██████████| 100.0% Read (Sector 0x800 of 0x800, ) 14.65 MB/s
Progress: |██████████| 100.0% Read (Sector 0x2 of 0x2, ) 2.23 MB/s
Progress: |██████████| 100.0% Read (Sector 0x10 of 0x10, ) 5.25 MB/s
Progress: |██████████| 100.0% Read (Sector 0x5000 of 0x5000, ) 14.90 MB/s
Progress: |██████████| 100.0% Read (Sector 0x40 of 0x40, ) 10.60 MB/s
Progress: |██████████| 100.0% Read (Sector 0xC00 of 0xC00, ) 12.09 MB/s
Progress: |██████████| 100.0% Read (Sector 0x20 of 0x20, ) 7.76 MB/s
Progress: |██████████| 100.0% Read (Sector 0x10000 of 0x10000, ) 15.26 MB/s
Progress: |██████████| 100.0% Read (Sector 0x190000 of 0x190000, ) 12.06 MB/s
Progress: |██████████| 100.0% Read (Sector 0x10000 of 0x10000, ) 15.06 MB/s
Progress: |██████████| 100.0% Read (Sector 0x1F3D15 of 0x1F4000, ) 11.71 MB/s
Progress: |██████████| 100.0% Read (Sector 0x1F4000 of 0x1F4000, ) 14.61 MB/s
Progress: |██████████| 100.0% Read (Sector 0x80000 of 0x80000, ) 14.57 MB/s
Progress: |██████████| 100.0% Read (Sector 0x10000 of 0x10000, ) 15.26 MB/s
Progress: |██████████| 100.0% Read (Sector 0x800 of 0x800, ) 15.16 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 14.83 MB/s
Progress: |██████████| 100.0% Read (Sector 0x20000 of 0x20000, ) 15.09 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 13.97 MB/s
Progress: |██████████| 100.0% Read (Sector 0x200 of 0x200, ) 14.99 MB/s
Progress: |██████████| 100.0% Read (Sector 0x200 of 0x200, ) 15.04 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 14.41 MB/s
Progress: |██████████| 100.0% Read (Sector 0x400 of 0x400, ) 15.16 MB/s
Progress: |██████████| 100.0% Read (Sector 0x227C79 of 0x227FDF, ) 12.43 MB/s
Progress: |██████████| 100.0% Read (Sector 0x227FDF of 0x227FDF, ) 15.01 MB/s
y verificamos si se escribieron los archivos del respaldo:
$ ls -lh ~/workspace/r3di-fr150-backup
total 3.4G
-rw-rw-r-- 1 jmpc jmpc 1.0M Jan 10 22:52 abootbak.bin
-rw-rw-r-- 1 jmpc jmpc 1.0M Jan 10 22:52 aboot.bin
-rw-rw-r-- 1 jmpc jmpc 256K Jan 10 22:52 apdp.bin
-rw-rw-r-- 1 jmpc jmpc 32M Jan 10 22:52 boot.bin
-rw-rw-r-- 1 jmpc jmpc 256M Jan 10 22:55 cache.bin
-rw-rw-r-- 1 jmpc jmpc 256K Jan 10 22:55 cmnlibbak.bin
-rw-rw-r-- 1 jmpc jmpc 256K Jan 10 22:55 cmnlib.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:55 config.bin
-rw-rw-r-- 1 jmpc jmpc 32K Jan 10 22:52 DDR.bin
-rw-rw-r-- 1 jmpc jmpc 256K Jan 10 22:52 devcfg.bin
-rw-rw-r-- 1 jmpc jmpc 1.0M Jan 10 22:55 devinfo.bin
-rw-rw-r-- 1 jmpc jmpc 1.0K Jan 10 22:52 fsc.bin
-rw-rw-r-- 1 jmpc jmpc 1.5M Jan 10 22:52 fsg.bin
-rw-rw-r-- 1 jmpc jmpc 4.5K Jan 10 22:52 gpt_backup0.bin
-rw-rw-r-- 1 jmpc jmpc 5.5K Jan 10 22:52 gpt_main0.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:55 keymasterbak.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:55 keymaster.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:55 keystore.bin
-rw-rw-r-- 1 jmpc jmpc 1.0M Jan 10 22:52 misc.bin
-rw-rw-r-- 1 jmpc jmpc 64M Jan 10 22:52 modem.bin
-rw-rw-r-- 1 jmpc jmpc 1.5M Jan 10 22:52 modemst1.bin
-rw-rw-r-- 1 jmpc jmpc 1.5M Jan 10 22:52 modemst2.bin
-rw-rw-r-- 1 jmpc jmpc 64M Jan 10 22:55 oem.bin
-rw-rw-r-- 1 jmpc jmpc 1.0M Jan 10 22:52 pad.bin
-rw-rw-r-- 1 jmpc jmpc 32M Jan 10 22:53 persist.bin
-rw-rw-r-- 1 jmpc jmpc 11K Jan 10 22:52 rawprogram0.xml
-rw-rw-r-- 1 jmpc jmpc 32M Jan 10 22:55 recovery.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:52 rpmbak.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:52 rpm.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:52 sbl1bak.bin
-rw-rw-r-- 1 jmpc jmpc 512K Jan 10 22:52 sbl1.bin
-rw-rw-r-- 1 jmpc jmpc 16K Jan 10 22:52 sec.bin
-rw-rw-r-- 1 jmpc jmpc 10M Jan 10 22:52 splash.bin
-rw-rw-r-- 1 jmpc jmpc 8.0K Jan 10 22:52 ssd.bin
-rw-rw-r-- 1 jmpc jmpc 800M Jan 10 22:53 system.bin
-rw-rw-r-- 1 jmpc jmpc 2.0M Jan 10 22:52 tzbak.bin
-rw-rw-r-- 1 jmpc jmpc 2.0M Jan 10 22:52 tz.bin
-rw-rw-r-- 1 jmpc jmpc 1000M Jan 10 22:55 usbmsc.bin
-rw-rw-r-- 1 jmpc jmpc 1.1G Jan 10 22:57 userdata.bin
En el archivo rawprogram0.xml también se puede encontrar información de las
particiones de las que se hizo un volcado (dump).
Habilitar menú Developer
Para habilitar el menú Developer y poder habilitar adb debemos modificar
archivos en la partición system.bin y luego realizar un Factory Reset.
Copiamos la partición al directorio de trabajo y creamos los directorios que utilizaremos:
$ mkdir -p ~/workspace/r3di-fr150
$ cd ~/workspace/r3di-fr150
$ cp ~/workspace/r3di-fr150-backup/system.bin .
$ mkdir mnt_system
Luego montamos la partición ext4 del archivo system.bin:
$ file system.bin
system.bin: Linux rev 1.0 ext4 filesystem data, UUID=da594c53-9beb-f85c-85c5-cedf76546f7a, volume name "system" (extents) (large files)
$ doas mount -t ext4 -o rw,loop system.bin mnt_system
Para evitar problemas de permisos, utilizamos root para navegar y editar
archivos en el sistema montado.
Luego buscamos el archivo settings.json y utilizamos el comando jq para
formatearlo así podremos editarlo más fácilmente:
$ doas su
# cd mnt_system
# file b2g/defaults/settings.json
b2g/defaults/settings.json: JSON text data
# wc -l b2g/defaults/settings.json
1 b2g/defaults/settings.json
# jq . b2g/defaults/settings.json > b2g/defaults/settings.json.tmp
# mv b2g/defaults/settings.json.tmp b2g/defaults/settings.json
Luego habilitamos el menú:
# cp b2g/defaults/settings.json b2g/defaults/settings.json.orig
# sed -i 's/"developer.menu.enabled": false,/"developer.menu.enabled": true,/' \
b2g/defaults/settings.json
Salimos de la consola con root, desmontamos, escribimos la partición en el
teléfono y lo reiniciamos:
# exit
$ doas umount mnt_system
$ cd ~/workspace/edl
$ ./edl w system ~/workspace/r3di-fr150/system.bin
$ ./edl reset
Al encender el teléfono e ir a Settings veremos que no se encuentra el menú
Developer; es necesario realizar un Factory Reset.
Para ello vamos a Settings > Device > Device information > Reset Phone.
Una vez que terminemos el factory reset e inicie el teléfono ya encontramos el
menú Developer en Settings > Device > Developer.
Allí elegimos Debugger (única opción) y entre las opciones ADB and DevTools.
Confirmamos que funciona:
$ lsusb
Bus 002 Device 061: ID 05c6:9092 Qualcomm, Inc. Nokia 8110 4G
$ adb devices
List of devices attached
c7d8d112 unauthorized
Instalar clave pública de adb
Para poder conectarnos al celular utilizando adb debemos instalar en el
celular la clave pública del certificado que está utilizando adb.
Para esto copiamos la clave pública de adb que se encuentra en
~/.android/adbkey.pub en el ramdisk de boot bajo /adb_keys.
Primero extraemos el ramdisk del boot usando abootimg:
$ cd ~/workspace/r3di-fr150
$ cp ~/workspace/r3di-fr150-backup/boot.bin .
$ mkdir boot_content
$ cd boot_content
$ abootimg -x ../boot.bin
writing boot image config in bootimg.cfg
extracting kernel in zImage
extracting ramdisk in initrd.img
Luego se utiliza cpio para extraer el ramdisk y poder modificarlo:
$ mkdir ramdisk
$ cd ramdisk
$ gunzip -c ../initrd.img | doas cpio -i
Pasamos a usar un shell con root para copiar los archivos y ajustar permisos:
$ doas su
# cp /home/$DOAS_USER/.android/adbkey.pub adb_keys
# ls -lh adb_keys
-rw-r--r-- 1 root root 713 Jan 10 23:59 adb_keys
Terminamos saliendo del shell, reconstruyendo el ramdisk, reconstruyendo el boot, grabando al celular y reiniciandolo:
No olvidar pasar el celular a modo EDL antes de grabar boot.bin al celular.
# exit
$ doas find . | doas cpio -o -H newc | gzip > ../initrd.img
3947 blocks
$ cd ..
$ abootimg -u ../boot.bin -r initrd.img
reading ramdisk from initrd.img
Writing Boot Image ../boot.bin
$ cd ~/workspace/edl
$ ./edl w boot ~/workspace/r3di-fr150/boot.bin
$ ./edl reset
Verificamos que nos podemos conectar utilizando adb:
$ adb devices
List of devices attached
c7d8d112 device
$ adb shell
shell@msm8909_512:/ $
shell@msm8909_512:/ $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1023(media_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=u:r:shell:s0
Notas
Modos usb
Una característica interesante del celular es la cantidad distinta de modos en
que puede ser reconocido por el PC utilizando lsusb.
Nota: Conviene quitarle la batería al celular para que sea más sencillo reiniciarlo, conectandolo a la computadora mediante un puerto usb que le de la suficiente carga para que pueda prenderse.
-
Si prendemos el celular y dejamos que cargue el sistema operativo, este es reconocido como:
ID 05c6:9092 Qualcomm, Inc. Nokia 8110 4G -
Si en kaios vamos a
Settings > Storage > USB storagey habilitamos el usb el celular pasa a ser reconocido como:ID 18d1:4ee1 Google Inc. Nexus/Pixel Device (MTP) -
Presionando el boton
vol-y conectando el usb se reconoce como:ID 18d1:d00d Google Inc. Xiaomi Mi/Redmi 2 (fastboot) -
Presionando los botones
vol++pwr, conectando el usb y soltando los botones cuando se enciente la retroiluminación del teclado (a unos 4 segundos de haber conectado el usb) se reconoce como:ID 18d1:d001 Google Inc. Nexus 4 (fastboot) -
Presionando los botones
vol++pwr, conectando el usb y dejando los botones presionados por unos 10 segundos sin soltar, primero se reconoce el usb comoID 18d1:d001 Google Inc. Nexus 4 (fastboot)si dejamos presionados los botones desaparece y aparece:
ID 05c6:900e Qualcomm, Inc. QHSUSB__BULK -
Presionando los botones
*+#y conectando el usb tenemos:ID 05c6:9008 Qualcomm, Inc. Gobi Wireless Modem (QDL mode)
Recursos
Documentación oficial:
BananaHackers:
Guides and resources to modify your KaiOS devices, by the community, for the community
- https://wiki.bananahackers.net/ (nueva)
- https://bananahackers.net/ (antigua)
La información está MUY desordenada.
EDL:
- Exploiting Qualcomm EDL Programmers https://alephsecurity.com/2018/01/22/qualcomm-edl-1/
Errores al montar particiones con opción readonly
En el caso que se quiera montar una partición en modo read only para inspeccionar el contenido sin modificarlo, puede aparecer un error del tipo:
$ doas mount -t ext4 -o ro,loop userdata.bin mnt_userdata
mount: /home/jmpc/workspace/r3di-fr150-backup/mnt_userdata: cannot mount /dev/loop1 read-only.
dmesg(1) may have more information after failed mount system call.
y en la salida de dmesg:
$ doas dmesg
[37411.035278] loop1: detected capacity change from 0 to 2260959
[37411.035655] EXT4-fs (loop1): INFO: recovery required on readonly filesystem
[37411.035659] EXT4-fs (loop1): write access unavailable, cannot proceed (try mounting with noload)
Esto quiere decir que hay información en el jornal de la partición que no aún no fué escrito al filesystem.
La solución es montar el filesystem como rw así se escribe la información del
journal al filesystem.
$ doas mount -t ext4 -o rw,loop userdata.bin mnt_userdata
y en dmesg vemos
[37631.700972] loop1: detected capacity change from 0 to 2260959
[37631.716541] EXT4-fs (loop1): recovery complete
[37631.717202] EXT4-fs (loop1): mounted filesystem 57f8f4bc-abf4-655f-bf67-946fc0f9f25b r/w with ordered data mode. Quota mode: none.
Aquí ya podemos proceder a desmontar y montar como ro aunque la imagen ya fué
modificada:
$ doas umount mnt_userdata/
$ doas mount -t ext4 -o ro,loop userdata.bin mnt_userdata
La salida de dmesg:
[37641.311462] EXT4-fs (loop1): unmounting filesystem 57f8f4bc-abf4-655f-bf67-946fc0f9f25b.
[37646.697110] loop1: detected capacity change from 0 to 2260959
[37646.697665] EXT4-fs (loop1): mounted filesystem 57f8f4bc-abf4-655f-bf67-946fc0f9f25b ro with ordered data mode. Quota mode: none.