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 adb
simplement 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.Backup
tant 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.ab
fichier 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.) BackupHandler
Puis 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