J'ai commencé à travailler sur ça. Je publie mes résultats jusqu'ici comme réponse de "wiki de communauté" pour deux raisons: premièrement, si quelqu'un d'autre souhaite y participer, il existe un lieu de discussion; Deuxièmement, si je suis éloigné 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: elle valide les options de ligne de commande, envoie la commande essentiellement telle quelle au démon adb du téléphone et écrit la sortie du téléphone dans le fichier. Il n'y a même pas de vérification d'erreur: si, par exemple, vous refusez la sauvegarde sur le téléphone, écrivez adbsimplement un fichier vide.
Sur le téléphone, la logique de sauvegarde commence service_to_fd()dans https://github.com/android/platform_system_core/blob/master/adb/services.cpp . La fonction identifie la commande de l'hôte "backup"et transmet la commande non analysée à /system/bin/bu, ce qui est un script shell trivial à lancer en com.android.commands.bu.Backuptant que 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 transmettant le descripteur de fichier encore inutilisé (très indirectement) connecté au backup.abfichier sur l'hôte.
Le contrôle passe fullBackup()dans com.android.server.backup.BackupManagerService , qui affiche l'interface graphique demandant à l'utilisateur de confirmer / refuser 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 passe un message à BackupHandler(même fichier.) BackupHandlerPuis instancie et lance un PerformAdbBackupTask( même fichier, ligne 4004 à la date de rédaction).
Nous commençons enfin à générer une sortiePerformAdbBackupTask.run() entre les lignes 4151 et 4330 .
Commencez par run()écrire un en-tête composé de 4 ou 9 lignes ASCII:
"ANDROID BACKUP"
- la version du format de sauvegarde: actuellement
"4"
- soit
"0"si la sauvegarde est décompressée ou "1"si elle est
- la méthode de cryptage: actuellement
"none"ou"AES-256"
- (si crypté), le "sel de mot de passe de l'utilisateur" encodé en hexadécimal, en majuscules
- (si chiffré), le "sel de la clé de contrôle de la clé principale" codé en hexadécimal, toutes les majuscules
- (si chiffré), le "nombre de tours PBKDF2 utilisées" sous forme de nombre décimal: actuellement
"10000"
- (si crypté), le "IV de la clé d'utilisateur" encodé en hexadécimal, toutes les majuscules
- (si crypté), le "blob maître IV + clé, crypté par la clé d'utilisateur" codé en hexadécimal, tout en majuscule
Les données de sauvegarde réelle suit, soit ( en fonction de la compression et le cryptage) tar, deflate(tar), encrypt(tar)ou encrypt(deflate(tar)).
TODO : écrivez le chemin du code qui génère la sortie de tar - vous pouvez simplement utiliser tar tant que les entrées sont dans le bon ordre (voir ci-dessous).
Format d'archive Tar
Les données d'application sont stockées dans le répertoire app /, en commençant par un fichier _manifest, l'APK (si demandé) dans un /, les fichiers d'application en f /, les bases de données en db / et les préférences partagées en sp /. Si vous avez demandé une sauvegarde de stockage externe (à l'aide de l'option -shared), il y aura également un répertoire partagé / dans l'archive contenant les fichiers de stockage externes.
$ 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 chiffrement
- Une clé AES 256 est dérivée du mot de passe de chiffrement de sauvegarde en utilisant 10000 tours de PBKDF2 avec un sel de 512 bits généré de manière aléatoire.
- Une clé principale AES 256 est générée de manière aléatoire.
- Une "clé de contrôle" est générée en exécutant la clé principale sur 10000 tours de PBKDF2 avec un nouveau sel de 512 bits généré de manière aléatoire.
- Un chiffrement de sauvegarde aléatoire IV 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é obtenue en 1. Le blob résultant est enregistré dans l'en-tête en tant que chaîne hexagonale.
- Les données de sauvegarde réelles sont cryptées avec la clé principale et ajoutées à la fin du fichier.
Exemple d'implémentation / décompression du code (produit / utilise) les archives tar: https://github.com/nelenkov/android-backup-extractor
Quelques détails supplémentaires ici: http://nelenkov.blogspot.com/2012/06/unpacking-android-backups.html
Scripts Perl pour emballer / décompresser et réparer les archives endommagées:
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175