Modifier l'image de démarrage Android

par Julien Lepiller — mar. 27 février 2018

Présentation de la bête

Le téléphone que je vais utiliser est un Galaxy S3 de Samsung, plus spécifiquement le modèle GT-9300. Il se trouve que ce modèle est l'un des rares supportés par Replicant, alors je ne me suis pas gêné :D. Je vais essayer d'être un peu générique pour que ça s'applique à n'importe quel appareil. Cependant, je ne connais pas bien tous les téléphones existants, donc ça peut être un peu plus compliqué que ça.

Les commandes que je donne ici n'ont pas fonctionnées pour moi (voir la fin). Pensez à sauvegarder les fichiers, surtout le fichier boot.img, sans quoi vous risquez de bloquer votre téléphone. La moindre fausse manip' peut bloquer votre téléphone, soyez prudent.

Comme je suis sous GuixSD (la meilleure distribution du monde, je vous en ai déjà parlé ?), je me fais un petit environnement aux petits oignons et découvre avec merveille que quelqu'un a déjà empaqueté les outils nécessaires :

guix environment --ad-hoc abootimg adb cpio heimdall

La première étape pour modifier l'image de démarrage, c'est évidemment d'obtenir cette image de démarrage. Voilà un peu à quoi ça ressemble :

adb root
adb shell

J'ai eu besoin des droits root pour pouvoir visualiser le dossier /dev qui m'intéressait. En effet, l'une des partitions contient l'image de démarrage. En fait, cette image contient le noyau android, quelques options pour le lancement du noyau et une image disque initiale (initrd). C'est cette dernière qui m'intéresse réellement. Je vous en parle juste après ça. Depuis la console adb, il faut maintenant trouver la partition qui contient l'image de démarrage. Pour cela, il est suggéré de chercher dans /proc/partitions, mais j'ai trouvé ça à la place :

ls -l /dev/block/platform/dw_mmc/by-name

me donne le résultat suivant :

total 0
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 BOOT -> /dev/block/mmcblk0p5
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 BOTA0 -> /dev/block/mmcblk0p1
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 BOTA1 -> /dev/block/mmcblk0p2
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 CACHE -> /dev/block/mmcblk0p8
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 EFS -> /dev/block/mmcblk0p3
lrwxrwxrwx 1 root root 21 2012-01-01 00:26 HIDDEN -> /dev/block/mmcblk0p10
lrwxrwxrwx 1 root root 21 2012-01-01 00:26 OTA -> /dev/block/mmcblk0p11
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 PARAM -> /dev/block/mmcblk0p4
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 RADIO -> /dev/block/mmcblk0p7
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 RECOVERY -> /dev/block/mmcblk0p6
lrwxrwxrwx 1 root root 20 2012-01-01 00:26 SYSTEM -> /dev/block/mmcblk0p9
lrwxrwxrwx 1 root root 21 2012-01-01 00:26 USERDATA -> /dev/block/mmcblk0p12

Les noms BOOT et RECOVERY sont ceux qui correspondent aux partitions qui contiennent les images de démarrage. Mon téléphone en possède deux : une normale et une de secours. Je m'intéresse évidemment au démarrage normal. Donc on ne touche pas à la partition 6. Je récupère alors l'image qui m'intéresse :

cd /mnt/sdcard; cat /dev/block/mmcblk0p5 > boot.img

Tout simplement. Je fini ensuite en récupérant l'image sur le PC :

adb pull /mnt/sdcard/boot.img

Travail sur l'image

Me voilà fin prêt à décortiquer cette image. Comme je l'ai dit, elle contient un noyau, de la configuration et une image disque initiale. Voilà comment récupérer tout ça :

abootimg -x boot.img

Cette commande demande à abootimg, un outil pour gérer le fichier boot.img, d'extraire le contenu du fichier. Cela crée trois fichiers : bootimg.cfg, initrd.img et zImage. Il s'agit respectivement de la configuration, de l'image disque initiale qui nous intéresse et du noyau. Voyons comment extraire cette image initiale :

mkdir initrd; cd initrd
cat ../initrd.img | gunzip | cpio -vid

Et voilà ! L'image de démarrage est un réalité un répertoire archivée avec cpio puis compressée avec gzip. La commande permet simplement de faire ces opérations dans le sens inverse pour récupérer les fichiers d'origine. Voilà mon modique changement :

mkdir gnu

Ça me pemettra d'installer GuixSD sur ce téléphone un jour (il faut bien commencer quelque part). Maintenant, il est temps de tout réempaqueter. C'est l'opération inverse de tout à l'heure. Le format cpio exact est newc, qui est différent du format par défaut de la commande. Sans ce paramètre, l'image est illisible par .

find . | cpio --create --format='newc' | gzip > ../myinitrd.img

Enfin, on peut reformer l'image de démarrage complète avec ses options et son noyau :

abootimg --create myboot.img -f bootimg.cfg -k zImage -r myinitrd.img

Remplacer l'image existante

Et voilà, il ne reste plus qu'à remettre tout ça dans le téléphone. Pour cela, je le redémarre en mode téléchargement (adb reboot download). Puis :

heimdall flash --boot myboot.img

Et ça reboot \o/. Et ça reboot… Et ça reboot T.T

Alors on remet le fichier boot.img d'origine et on retentera une prochaine fois.