Zacząłem nad tym pracować. Do tej pory zamieszczam wyniki jako odpowiedź „wiki społeczności” z dwóch powodów: po pierwsze, jeśli ktoś inny chce dołączyć, istnieje miejsce do rozmowy; po drugie, jeśli oderwę się od tego projektu, pojawią się wskazówki dla kogoś innego, aby zaczął działać.
Logika tworzenia kopii zapasowych na hoście jest całkowicie zawarta w https://github.com/android/platform_system_core/blob/master/adb/commandline.cpp w funkcji o nazwie backup
. Funkcja jest bardzo prosta: sprawdza poprawność opcji wiersza poleceń, wysyła polecenie głównie w niezmienionej postaci do demona adb w telefonie i zapisuje dane wyjściowe telefonu do pliku. Nie ma nawet sprawdzania błędów: jeśli na przykład odmówisz wykonania kopii zapasowej w telefonie, adb
po prostu zapisujesz pusty plik.
Na telefonie logika tworzenia kopii zapasowych rozpoczyna się service_to_fd()
w https://github.com/android/platform_system_core/blob/master/adb/services.cpp . Funkcja identyfikuje, że polecenie hosta jest "backup"
, i przekazuje nieprzetworzone polecenie /system/bin/bu
, które jest trywialnym skryptem powłoki, który można uruchomić com.android.commands.bu.Backup
jako główną klasę nowego procesu aplikacji na Androida. To wywołuje, ServiceManager.getService("backup")
aby uzyskać usługę tworzenia kopii zapasowych jako IBackupManager
, i wywołuje IBackupManager.fullBackup()
, przekazując jej wciąż nieużywany deskryptor pliku (bardzo pośrednio) podłączony do backup.ab
pliku na hoście.
Sterowanie przechodzi fullBackup()
w com.android.server.backup.BackupManagerService , która pojawia się GUI z prośbą o potwierdzenie / odrzucenie kopię zapasową. Gdy użytkownik to zrobi, acknowledgeFullBackupOrRestore()
wywoływany jest (ten sam plik). Jeśli użytkownik zatwierdzi żądanie, acknowledgeFullBackupOrRestore()
dowie się, czy kopia zapasowa jest zaszyfrowana, i przekaże wiadomość do BackupHandler
(tego samego pliku), BackupHandler
a następnie utworzy wystąpienie i uruchomi PerformAdbBackupTask
(ten sam plik, wiersz 4004 w momencie zapisu)
W końcu zaczynamy generować produkcję tamPerformAdbBackupTask.run()
, między linią 4151 a linią 4330 .
Najpierw run()
pisze nagłówek, który składa się z 4 lub 9 linii ASCII:
"ANDROID BACKUP"
- wersja formatu kopii zapasowej: obecnie
"4"
- albo
"0"
jeśli kopia zapasowa jest nieskompresowana, albo "1"
jest
- Metoda szyfrowania: obecnie albo
"none"
albo"AES-256"
- (jeśli są zaszyfrowane), „sól hasła użytkownika” zakodowana szesnastkowo, wszystkie wielkie litery
- (jeśli są zaszyfrowane), „sól kontrolna suma kontrolna” zakodowana szesnastkowo, wszystkie wielkie litery
- (jeśli są zaszyfrowane), „liczba użytych rund PBKDF2” jako liczba dziesiętna: obecnie
"10000"
- (jeśli są zaszyfrowane), „IV klucza użytkownika” zakodowane szesnastkowo, wszystkie wielkie litery
- (jeśli są zaszyfrowane), „główny obiekt blob IV +, zaszyfrowany kluczem użytkownika” zakodowany szesnastkowo, wszystkie wielkie litery
Rzeczywiste dane kopii zapasowej w następujący sposób, jako (w zależności od kompresji i szyfrowania) tar
, deflate(tar)
, encrypt(tar)
, lub encrypt(deflate(tar))
.
DO ZROBIENIA : napisz ścieżkę kodu, która generuje wyjście tar - możesz po prostu użyć tar, o ile wpisy są w odpowiedniej kolejności (patrz poniżej).
Format archiwum tar
Dane aplikacji są przechowywane w katalogu app /, zaczynając od pliku _manifest, APK (na żądanie) w /, pliki aplikacji w f /, bazy danych w db / i wspólne preferencje w sp /. Jeśli zażądano kopii zapasowej zewnętrznej pamięci masowej (przy użyciu opcji -shared), w archiwum będzie także udostępniony katalog / zawierający pliki zewnętrznej pamięci masowej.
$ 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
Szczegóły szyfrowania
- Klucz AES 256 jest uzyskiwany z hasła do szyfrowania kopii zapasowej przy użyciu 10000 rund PBKDF2 z losowo wygenerowaną 512-bitową solą.
- Klucz główny AES 256 jest generowany losowo
- „Suma kontrolna” klucza głównego jest generowana przez uruchomienie klucza głównego przez 10000 rund PBKDF2 z nową losowo wygenerowaną 512-bitową solą.
- Generowane jest losowe szyfrowanie kopii zapasowej IV.
- IV, klucz główny i suma kontrolna są łączone i szyfrowane za pomocą klucza pochodzącego z 1. Powstały obiekt blob jest zapisywany w nagłówku jako ciąg szesnastkowy.
- Rzeczywiste dane kopii zapasowej są szyfrowane kluczem głównym i dołączane na końcu pliku.
Przykładowa implementacja kodu paczki / rozpakowania (produkuje / wykorzystuje) archiwa tar: https://github.com/nelenkov/android-backup-extractor
Więcej szczegółów tutaj: http://nelenkov.blogspot.com/2012/06/unpacking-android-backups.html
Skrypty Perla do pakowania / rozpakowywania i naprawy uszkodzonych archiwów:
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175