J'ai commencé à travailler sur ce sujet. Je publie mes résultats ici sous forme de réponse "wiki communautaire" pour deux raisons : premièrement, si quelqu'un d'autre veut participer, il y a un endroit pour en parler ; deuxièmement, si je suis retiré de ce projet, il y aura des indices pour que quelqu'un d'autre commence à travailler.
La logique de sauvegarde sur l'hôte est entièrement contenue dans https://github.com/Android/platform_system_core/blob/master/adb/commandline.cpp dans la fonction nommée backup
. La fonction est très simple : il valide les options de la ligne de commande, envoie la commande telle quelle au démon adb sur le téléphone, et écrit la sortie du téléphone dans le fichier. Il n'y a même pas de contrôle d'erreur : si, par exemple, vous refusez la sauvegarde sur le téléphone, adb
écrit simplement un fichier vide.
Sur le téléphone, la logique de sauvegarde commence dans service_to_fd()
en https://github.com/Android/platform_system_core/blob/master/adb/services.cpp . La fonction identifie que la commande de l'hôte est "backup"
et transmet la commande non analysée à l'adresse suivante /system/bin/bu
qui est un shell trivial script pour lancer com.android.commands.bu.Backup
comme classe principale d'un nouveau processus d'application Android. Cela appelle ServiceManager.getService("backup")
pour obtenir le service de sauvegarde en tant que IBackupManager
et appelle IBackupManager.fullBackup()
en lui passant le descripteur de fichier encore inutilisé (de manière très indirecte) connecté à l'extension backup.ab
sur l'hôte.
Le contrôle passe à fullBackup()
en Service de gestion des sauvegardes com.Android.server.backup.BackupManagerService qui fait apparaître l'interface graphique demandant à l'utilisateur de confirmer ou de rejeter la sauvegarde. Lorsque l'utilisateur le fait, acknowledgeFullBackupOrRestore()
(même fichier) est appelé. Si l'utilisateur a approuvé la demande, acknowledgeFullBackupOrRestore()
détermine si la sauvegarde est cryptée, et transmet un message à BackupHandler
(même dossier.) BackupHandler
puis instancie et lance un PerformAdbBackupTask
( même fichier, ligne 4004 au moment de la rédaction)
Nous commençons finalement à générer des sorties à cet endroit, dans PerformAdbBackupTask.run()
entre ligne 4151 y ligne 4330 .
D'abord, run()
écrit un en-tête, qui consiste en 4 ou 9 lignes ASCII :
"ANDROID BACKUP"
- la version du format de sauvegarde : actuellement
"4"
- soit
"0"
si la sauvegarde est non compressée ou "1"
si c'est le cas
- la méthode de cryptage : actuellement soit
"none"
o "AES-256"
- (s'il est crypté), le "sel du mot de passe de l'utilisateur" codé en hexadécimal, tout en majuscules.
- (s'il est crypté), le "sel de contrôle de la clé principale" codé en hexadécimal, tout en majuscules.
- (s'il est crypté), le "nombre de tours PBKDF2 utilisés" sous forme de nombre décimal : actuellement
"10000"
- (s'il est crypté), le "IV de la clé utilisateur" codé en hexadécimal, tout en majuscules
- (s'il est crypté), le "master IV + key blob, crypté par la clé de l'utilisateur" codé en hexadécimal, tout en majuscules.
Les données de sauvegarde proprement dites suivent, sous forme de (selon la compression et le cryptage) tar
, deflate(tar)
, encrypt(tar)
ou encrypt(deflate(tar))
.
TODO : écrire le chemin de code qui génère la sortie tar -- vous pouvez simplement utiliser tar tant que les entrées sont dans le bon ordre (voir ci-dessous).
Format des archives Tar
Les données de l'application sont stockées dans le répertoire app/, en commençant par un fichier _manifest, l'APK (si demandé) dans a/, les fichiers de l'application dans f/, les bases de données dans db/ et les préférences partagées dans sp/. Si vous avez demandé une sauvegarde de stockage externe (en utilisant l'option -shared), il y aura également un répertoire shared/ dans l'archive contenant les fichiers de stockage externe.
$ tar tvf mybackup.tar
-rw------- 1000/1000 1019 2012-06-04 16:44 apps/org.myapp/_manifest
-rw-r--r-- 1000/1000 1412208 2012-06-02 23:53 apps/org.myapp/a/org.myapp-1.apk
-rw-rw---- 10091/10091 231 2012-06-02 23:41 apps/org.myapp/f/share_history.xml
-rw-rw---- 10091/10091 0 2012-06-02 23:41 apps/org.myapp/db/myapp.db-journal
-rw-rw---- 10091/10091 5120 2012-06-02 23:41 apps/org.myapp/db/myapp.db
-rw-rw---- 10091/10091 1110 2012-06-03 01:29 apps/org.myapp/sp/org.myapp_preferences.xml
Détails du cryptage
- Une clé AES 256 est dérivée du mot de passe de cryptage de sauvegarde en utilisant 10000 tours de PBKDF2 avec un sel de 512 bits généré aléatoirement.
- Une clé principale AES 256 est générée de façon aléatoire.
- Une "somme de contrôle" de la clé principale est générée en faisant passer la clé principale par 10000 cycles de PBKDF2 avec un nouveau sel de 512 bits généré de façon aléatoire.
- Un IV de cryptage de sauvegarde aléatoire est généré.
- Le IV, la clé principale et la somme de contrôle sont concaténés et chiffrés avec la clé dérivée en 1. Le blob résultant est enregistré dans l'en-tête sous forme de chaîne hexadécimale.
- Les données de sauvegarde proprement dites sont cryptées avec la clé principale et ajoutées à la fin du fichier.
Exemple de mise en œuvre du code d'empaquetage/dépaquetage (produit/utilise) des archives tar : https://github.com/nelenkov/Android-backup-extractor
Plus de détails ici : http://nelenkov.blogspot.com/2012/06/unpacking-Android-backups.html
Scripts Perl pour l'empaquetage/dépaquetage et la réparation des archives cassées :
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175
0 votes
Je crois qu'aucune des réponses sans utiliser Java ne fonctionnera sur les téléphones cryptés. Voir ma réponse ici : Android.stackexchange.com/a/224474/95893 résumant l'utilisation de l'application de nelenkov (github.com/nelenkov/Android-backup-extractor). Malheureusement, les scripts perl ab2tar d'Adebar d'Izzy ne fonctionneront pas sur les fichiers de sauvegarde chiffrés. Similaire : Android.stackexchange.com/questions/28481/