Empecé a trabajar en esto. Estoy publicando mis resultados hasta ahora aquí como una respuesta de "wiki de la comunidad" por dos razones: primero, si alguien más quiere unirse, hay un lugar para hablar; segundo, si me alejan de este proyecto, habrá sugerencias para que alguien más comience a trabajar.
La lógica de respaldo en el host está completamente contenida en https://github.com/android/platform_system_core/blob/master/adb/commandline.cpp , en la función nombrada backup
. La función es muy simple: valida las opciones de la línea de comandos, envía el comando en su mayoría tal cual al adb daemon en el teléfono y escribe la salida del teléfono en el archivo. Ni siquiera hay verificación de errores: si, por ejemplo, rechaza la copia de seguridad en el teléfono, adb
simplemente escribe un archivo vacío.
En el teléfono, la lógica de respaldo comienza service_to_fd()
en https://github.com/android/platform_system_core/blob/master/adb/services.cpp . La función identifica que el comando del host es "backup"
, y pasa el comando no analizado a /system/bin/bu
, que es un script de shell trivial para iniciar com.android.commands.bu.Backup
como la clase principal de un nuevo proceso de aplicación de Android. Eso llama ServiceManager.getService("backup")
para obtener el servicio de respaldo como un IBackupManager
, y llama IBackupManager.fullBackup()
, pasándole el descriptor de archivo aún no utilizado (muy indirectamente) conectado al backup.ab
archivo en el host.
El control pasa al fullBackup()
de com.android.server.backup.BackupManagerService , la cual aparece la interfaz gráfica de usuario que pide al usuario que confirme / rechazar la copia de seguridad. Cuando el usuario lo hace, acknowledgeFullBackupOrRestore()
se llama (mismo archivo). Si el usuario aprobó la solicitud, acknowledgeFullBackupOrRestore()
descubre si la copia de seguridad está encriptada y pasa un mensaje a BackupHandler
(mismo archivo), BackupHandler
luego crea una instancia y lanza un PerformAdbBackupTask
( mismo archivo, línea 4004 al momento de la escritura)
Finalmente comenzamos a generar resultados allí, enPerformAdbBackupTask.run()
, entre la línea 4151 y la línea 4330 .
Primero, run()
escribe un encabezado, que consta de 4 o 9 líneas ASCII:
"ANDROID BACKUP"
- la versión del formato de copia de seguridad: actualmente
"4"
- ya sea
"0"
si la copia de seguridad no está comprimida o "1"
si está
- El método de cifrado: actualmente
"none"
o"AES-256"
- (si está cifrado), la "sal de contraseña de usuario" codificada en hexadecimal, todo en mayúsculas
- (si está cifrado), la "sal de comprobación de la clave maestra" codificada en hexadecimal, todo en mayúsculas
- (si está cifrado), el "número de rondas PBKDF2 utilizadas" como un número decimal: actualmente
"10000"
- (si está encriptado), el "IV de la clave de usuario" codificado en hexadecimal, todo en mayúsculas
- (si está encriptado), el "blob de claves maestro IV +, encriptado por la clave de usuario" codificado en hexadecimal, todo en mayúsculas
Los datos de copia de seguridad real sigue, ya sea como (dependiendo de la compresión y cifrado) tar
, deflate(tar)
, encrypt(tar)
, o encrypt(deflate(tar))
.
TODO : escriba la ruta del código que genera la salida de tar; simplemente puede usar tar siempre que las entradas estén en el orden correcto (consulte a continuación).
Formato de archivo tar
Los datos de la aplicación se almacenan en el directorio app /, comenzando con un archivo _manifest, el APK (si se solicita) en a /, archivos de aplicación en f /, bases de datos en db / y preferencias compartidas en sp /. Si solicitó una copia de seguridad de almacenamiento externo (utilizando la opción compartida), también habrá un directorio compartido en el archivo que contiene archivos de almacenamiento externo.
$ 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
Detalles de cifrado
- Una clave AES 256 se deriva de la contraseña de cifrado de respaldo utilizando 10000 rondas de PBKDF2 con una sal de 512 bits generada aleatoriamente.
- Se genera aleatoriamente una clave maestra AES 256
- Se genera una 'suma de verificación' de la clave maestra ejecutando la clave maestra a través de 10000 rondas de PBKDF2 con una nueva sal de 512 bits generada aleatoriamente.
- Se genera una encriptación de respaldo aleatoria IV.
- El IV, la clave maestra y la suma de verificación se concatenan y cifran con la clave derivada en 1. El blob resultante se guarda en el encabezado como una cadena hexadecimal.
- Los datos de la copia de seguridad real se cifran con la clave maestra y se agregan al final del archivo.
Ejemplo de implementación de código de paquete / desempaquetado (produce / usa) archivos tar: https://github.com/nelenkov/android-backup-extractor
Algunos detalles más aquí: http://nelenkov.blogspot.com/2012/06/unpacking-android-backups.html
Scripts de Perl para empacar / desempacar y arreglar archivos rotos:
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175