Empecé a trabajar en esto. Estoy publicando mis resultados hasta ahora aquí como una respuesta "wiki de la comunidad" por dos razones: primero, si alguien más quiere unirse, hay un lugar para hablar; segundo, si me sacan de este proyecto, habrá pistas para que alguien más empiece a trabajar.
La lógica de respaldo en el anfitrión está enteramente contenida en https://github.com/Android/platform_system_core/blob/master/adb/commandline.c en la función llamada backup
. La función es muy simple: valida las opciones de la línea de comandos, envía el comando tal cual al demonio adb del teléfono, y escribe la salida del teléfono en el archivo. Ni siquiera hay una comprobación de errores: si, por ejemplo, rechazas la copia de seguridad en el teléfono, adb
sólo escribe un archivo vacío.
En el teléfono, la lógica de la copia de seguridad comienza en service_to_fd()
en https://github.com/Android/platform_system_core/blob/master/adb/services.c . La función identifica que el comando del anfitrión es "backup"
y pasa la orden no preparada a backup_service()
en https://github.com/Android/platform_system_core/blob/master/adb/backup_service.c . Eso, a su vez, es un fino envoltorio alrededor /system/bin/bu
que es un trivial shell script para lanzar com.android.commands.bu.Backup
como la clase principal de un nuevo proceso de aplicación para Android. Eso llama ServiceManager.getService("backup")
para obtener el servicio de respaldo como IBackupManager
y llama IBackupManager.fullBackup()
pasándole el descriptor de archivo aún no utilizado (muy indirectamente) conectado a la backup.ab
archivo sobre el anfitrión.
El control pasa a fullBackup()
en com.Android.server.BackupManagerService lo que hace que aparezca el GUI pidiendo al usuario que confirme/rechace la copia de seguridad. Cuando el usuario lo hace, acknowledgeFullBackupOrRestore()
(mismo archivo) se llama. Si el usuario aprobó la solicitud, acknowledgeFullBackupOrRestore()
averigua si la copia de seguridad está encriptada, y pasa un mensaje a BackupHandler
(mismo archivo.) BackupHandler
y luego se instanciará y se pondrá en marcha un PerformFullBackupTask
( mismo archivo, línea 2228 en el momento de escribir este artículo)
Finalmente empezamos a generar la producción allí, en PerformFullBackupTask.run()
entre línea 2367 y línea 2453 .
Primero, run()
escribe un encabezado, que consiste en 4 o 9 líneas ASCII:
"ANDROID BACKUP"
- la versión del formato de copia de seguridad: actualmente siempre
"1"
- o bien
"0"
si la copia de seguridad no está comprimida o "1"
Si es así
- el método de encriptación: actualmente
"none"
o "AES-256"
- (si está encriptada), la "sal de la contraseña de usuario" codificada en hexágono, todo en mayúsculas
- (si está codificado), la "sal de suma de control de la llave maestra" codificada en hexágono, todo en mayúsculas
- (si está encriptado), el "número de rondas PBKDF2 utilizadas" como número decimal
- (si está codificado), la "IV de la llave de usuario" codificada en hexágono, todo en mayúsculas
- (si está codificado), el "master IV + blob de la llave, codificado por la llave de usuario" codificado en hexadecimal, todo en mayúsculas
Los datos de respaldo reales siguen, ya sea como (dependiendo de la compresión y el cifrado) tar
, deflate(tar)
, encrypt(tar)
o encrypt(deflate(tar))
.
TODO : escribir la ruta del código que genera la salida de alquitrán -- puedes usar simplemente alquitrán siempre y cuando las entradas estén en el orden apropiado (ver más abajo).
El formato de archivo de 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/, los archivos de la aplicación en f/, las bases de datos en db/ y las preferencias compartidas en sp/. Si ha solicitado una copia de seguridad de almacenamiento externo (utilizando la opción -compartido), también habrá un directorio compartido/ en el archivo que contiene los 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 la encriptación
- Una clave AES 256 se deriva de la contraseña de cifrado de respaldo usando 10000 rondas de PBKDF2 con una sal de 512 bits generada al azar.
- Una llave maestra AES 256 es generada aleatoriamente
- Una "suma de comprobación" de la llave maestra se genera al pasar la llave maestra a través de 10000 rondas de PBKDF2 con una nueva sal de 512 bits generada al azar.
- Se genera un IV de encriptación de respaldo aleatorio.
- La IV, la clave maestra y la suma de comprobación se concatenan y encriptan con la clave derivada en 1. La mancha resultante se guarda en el encabezamiento como una cadena hexagonal.
- Los datos reales de la copia de seguridad se codifican con la clave maestra y se añaden al final del archivo.
Implementación del código de muestra del paquete/desempaque (produce/utiliza) archivos de alquitrán: https://github.com/nelenkov/Android-backup-extractor
Algunos detalles más aquí: http://nelenkov.blogspot.com/2012/06/unpacking-Android-backups.html
Guiones en perl para empaquetar/desempaquetar y arreglar archivos rotos:
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175
0 votos
Creo que ninguna de las respuestas sin usar Java funcionará en teléfonos encriptados. Ver mi respuesta aquí: Android.stackexchange.com/a/224474/95893 que resume el uso de la aplicación de nelenkov (github.com/nelenkov/Android-backup-extractor). Lamentablemente, los scripts perl de Adebar ab2tar de Izzy no funcionan con archivos de copia de seguridad encriptados. Algo parecido: Android.stackexchange.com/questions/28481/