Я почав працювати над цим. Я публікую свої результати поки що тут як відповідь на "вікі спільноти" з двох причин: по-перше, якщо хтось інший хоче приєднатися, є де поговорити; по-друге, якщо я відволічуся від цього проекту, з’являться підказки, щоб хтось інший почав працювати.
Логіка резервного копіювання на хості повністю міститься в https://github.com/android/platform_system_core/blob/master/adb/commandline.cpp , у функції, названій backup
. Функція дуже проста: вона перевіряє параметри командного рядка, відправляє команду здебільшого як є на демон демона на телефоні та записує вихід телефону у файл. Немає навіть перевірки помилок: якщо, наприклад, ви відмовитесь від резервної копії на телефоні, adb
просто випишете порожній файл.
У телефоні логіка резервного копіювання починається service_to_fd()
в https://github.com/android/platform_system_core/blob/master/adb/services.cpp . Функція визначає, що команда від хоста є "backup"
, і передає нерозділену команду /system/bin/bu
, що є тривіальним скриптом оболонки, який потрібно запустити com.android.commands.bu.Backup
як основний клас нового процесу додатків для Android. Це закликає ServiceManager.getService("backup")
отримати службу резервного копіювання як і IBackupManager
, і дзвонить IBackupManager.fullBackup()
, передаючи їй все ще невикористаний дескриптор файлу (дуже опосередковано), підключений до backup.ab
файла на хості.
Керування передається fullBackup()
в com.android.server.backup.BackupManagerService , який спливає графічний інтерфейс із проханням користувача підтвердити / відхилити резервну копію. Коли користувач робить це, acknowledgeFullBackupOrRestore()
викликається (той самий файл). Якщо користувач схвалив запит, acknowledgeFullBackupOrRestore()
з'ясовує, чи є резервна копія зашифрованою, і передає повідомлення BackupHandler
(той самий файл.), BackupHandler
Тоді створює копію PerformAdbBackupTask
(і той самий файл, рядок 4004 від часу написання)
Ми, нарешті, починаємо генерувати результат тамPerformAdbBackupTask.run()
, між, між рядком 4151 та рядком 4330 .
По-перше, run()
пише заголовок, який складається з 4-х або 9-ти рядків ASCII:
"ANDROID BACKUP"
- версія резервного формату: наразі
"4"
- або
"0"
якщо резервна копія не стиснута, або "1"
якщо вона є
- метод шифрування: в даний час
"none"
або"AES-256"
- (якщо зашифровано), "сіль для паролів користувача", закодована у шістнадцятковій формі, усі літери
- (якщо зашифровано), "солі головного ключа контрольної суми", закодовані у шістнадцяткові, з усіма кришками
- (якщо зашифровано), "кількість використаних раундів PBKDF2" як десяткове число: наразі
"10000"
- (якщо зашифровано), "IV ключа користувача", закодований у шістнадцятковій формі, усі літери
- (якщо зашифровано) "закодований ключ IV +, зашифрований користувацьким ключем", закодований у шістнадцять, усі літери
Фактичні дані резервного копіювання наступним чином , або в вигляді ( в залежності від стиснення і шифрування) tar
, deflate(tar)
, encrypt(tar)
, або encrypt(deflate(tar))
.
TODO : запишіть кодовий шлях, який генерує вихід дзеркалу - ви можете просто використовувати tar, якщо записи проходять у належному порядку (див. Нижче).
Формат архіву Тар
Дані програми зберігаються під додатком / каталогом, починаючи з файлу _manifest, APK (якщо вимагається) в /, файлів додатків у f /, баз даних у db / та спільних уподобань у sp /. Якщо ви попросили створити резервну копію зовнішнього сховища (використовуючи параметр -shared), в архіві також буде спільний / каталог, що містить зовнішні файли зберігання.
$ 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
Деталі шифрування
- Ключ AES 256 походить від пароля шифрування резервного копіювання, використовуючи 10000 раундів PBKDF2 з випадково генерованою 512 бітною сіллю.
- Головний ключ AES 256 генерується випадковим чином
- "Контрольна сума" головного ключа генерується за допомогою запуску головного ключа через 10000 раундів PBKDF2 з новою випадково генерованою 512 бітною сіллю.
- Створюється випадкове резервне шифрування IV.
- ІV, головний ключ і контрольна сума об'єднуються та шифруються з ключем, похідним у 1. Отриманий крап зберігається у заголовку у вигляді шістнадцяткової рядки.
- Фактичні дані резервного копіювання шифруються за допомогою головного ключа та додаються до кінця файлу.
Реалізація зразків упаковки / розпакування коду (виробляє / використовує) таргові архіви: https://github.com/nelenkov/android-backup-extractor
Ще кілька деталей тут: http://nelenkov.blogspot.com/2012/06/unpacking-android-backups.html
Сценарії Perl для упаковки / розпакування та виправлення зламаних архівів:
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175