[PL] Smalidea - debugowanie aplikacji Android bez kodu źródłowego

Wstęp

Posiadając aplikację tylko w formie pliku APK, na przykład po zainstalowaniu jej z Google Play Store, niemożliwe jest debugowanie jej w standardowy sposób. Wynika to z braku dostępu do kodu źródłowego. APK zawiera jedynie bajtkod dla maszyny wirtualnej Dalvik i ART, przechowywany w plikach o rozszerzeniu dex.

Z pomocą przychodzi smalidea. Jest to wtyczka dla IntelliJ IDEA i Android Studio, która dodaje obsługę języka smali (czyli asemblera bajtkodu Dalvika), a w tym również możliwość debugowania.

Wymagania:

Proces instalacji i uruchomienia będzie opisywany na przykładzie Kali Linuksa oraz Android Studio 3.1, które domyślnie zainstalowało Android SDK w katalogu domowym. Debugowaniu zostanie poddana aplikacja DIVA Android.

Przygotowanie projektu

Dezasemblacja

Najpierw powinniśmy zacząć od wydobycia APK z urządzenia. Do tego można wykorzystać narzędzie adb należące do Android SDK.

$ adb pull /data/app/jakhar.aseem.diva-1/base.apk diva.apk

A do przeprowadzenia dezasemblacji skorzystamy z apktool. Rozpakuje on wskazany przez nas plik APK, dezasemblując przy tym pliki dex za pomocą wbudowanego narzędzia baksmali.

$ apktool d -o DivaSmali diva.apk

Dodanie projektu

Będąc w posiadaniu kodu smali, możemy go teraz dodać do Android Studio. W tym celu należy zaimportować projekt, wybierając opcję z istniejącymi źródłami.

Zrzuty prezentują sposób na dodanie projektu przy pierwszym uruchomieniu Android Studio. Za to z kolejnymi uruchomieniami będziemy mogli dodawać projekty wybierając File -> New -> Import Project…

Import project

Create project from existing sources

Instalacja smalidea

Ten krok wykonujemy tylko dla pierwszego dodawanego projektu. Po instalacji, wtyczka będzie dostępna również dla nowych projektów.

Otwieramy ustawienia Android Studio wybierając File -> Settings. Odnajdujemy sekcję Plugins i instalujemy wtyczkę z dysku (Install plugin from disk…).

Install plugin from disk...

Po zakończeniu restartujemy Android Studio.

Konfiguracja projektu

Samo dodanie projektu nie jest wystarczające. Musimy jeszcze odpowiednio go przygotować. Domyślnym widokiem w projekcie jest Android, zmieniamy go jednak na widok plików projektu.

Project Files

Dzięki temu zobaczymy katalog z kodem smali (jakhar/aseem/diva), który oznaczymy jako katalog główny.

Mark directory as -> Sources Root

Teraz pozostaje już tylko ustawienie odpowiedniego SDK dla projektu. Otwieramy ustawienia projektu (File -> Project Structure) i odnajdujemy sekcję Project. W niej jako Project SDK wybieramy Android API, które powinniśmy mieć wcześniej zainstalowane.

File -> Project Structure -> Project -> Project SDK -> Android API

Łączenie z debuggerem

Przygotowanie debuggera

Zaczynamy od uruchomienia narzędzia Android Device Monitor. Po włączeniu go, powinniśmy zobaczyć nasze urządzenie wraz z listą możliwych do debugowania procesów i przypisanymi do nich portami. W tym przypadku proces jakhar.aseem.diva jest dostępny na porcie 8600.

$ Android/Sdk/tools/monitor

Android Device Manager

Wracamy do Android Studio, w którym musimy dodać konfigurację pozwalającą na zdalne uruchomienie projektu. Łączyć będziemy się z lokalnym hostem, na porcie powiązanym z naszą docelową aplikacją.

Run -> Edit Configuration Add -> Remote Host: localhost, Port: 8600

Wskazówka na przyszłość

Numery portów są przydzielane procesom dynamicznie, więc przy kolejnej próbie debugowania może on ulec zmianie. Rozwiązaniem jest ustawienie portu 8700 (zamiast pokazanego wyżej 8600). Jest on statyczny i zawsze odnosi się do aktualnie zaznaczonego procesu na liście w Android Device Monitor.

Uruchomienie debuggera

Po przygotowaniu konfiguracji, możemy ją wykorzystać do rozpoczęcia procesu debugowania.

Run -> Debug

O pomyślnym nawiązaniu połączenia poinformuje nas komunikat w konsoli Android Studio.

Connected to the target VM, address: 'localhost:8600', transport: 'socket'

Proces debugowania

Po udanym połączeniu z debuggerem możemy w wybranych miejscach w kodzie ustawiać breakpointy. A po zatrzymaniu się, wykonywać instrukcje krok po kroku oraz korzystać z wyrażeń do podglądania zawartości zmiennych lokalnych.

W ramach przykładu sprawdzimy dwa miejsca w aplikacji.

Przykład 1

Zadanie Access Control Part 3 wymaga wprowadzenia poprawnego numeru PIN, aby uzyskać dostęp do prywatnych notatek. Aplikacja porównuje wartość wprowadzoną przez użytkownika z numerem wcześniej zdefiniowanym w aplikacji. Za pomocą debuggera możemy zatrzymać się w miejscu, w którym odczytywany jest wcześniej zdefiniowany PIN i podejrzeć go.

Run -> Debug

W ten sposób dowiadujemy się, że zdefiniowany PIN to 9087.

Przykład 2

W zadaniu Input Validation Issues 1 występuje błąd typu SQL Injection. Zapytanie tworzone jest za pomocą konkatenacji stringów. Zatrzymując się na wywołaniu zapytania na bazie i korzystając z funkcji Evaluate expression, możemy się dokładnie przyjrzeć jak zostało ono zbudowane.

Run -> Debug Run -> Debug

Znalezienie odpowiedniego miejsca do ustawienia breakpointa może być trudne. Dlatego możemy sobie pomóc korzystając z dekompilatora (np. jadx). Wgląd w zdekompilowany kod może ułatwić namierzenie charakterystycznych miejsc w plikach smali.

Run -> Debug

Aplikacje z wyłączoną możliwością debugowania

W przypadku większości aplikacji w wersjach produkcyjnych, proces nie będzie widoczny w Android Device Monitor. Wynikać to będzie z faktu, że aplikacja nie została zbudowana z włączoną opcją debugowania. W takiej sytuacji konieczne będzie przepakowanie aplikacji, odpowiednio modyfikując jej manifest.

Mając już na komputerze plik APK, należy go rozpakować narzędziem apktool. Uruchamiając apktool tym razem, można skorzystać z opcji s. Sprawi ona, że odkodowane zostaną zasoby aplikacji, w tym AndroidManifest.xml, pozostawiając pliki .dex nienaruszone, co skróci czas wykonywania operacji.

$ apktool d -s base.apk

Po rozpakowaniu edytujemy plik AndroidManifest.xml. W elemencie application dodajemy atrybut debuggable ustawiony na true.

Run -> Debug

Proces budowania nowego APK, razem z podpisywaniem, opisany jest w poprzednim wpisie w części Zbudowanie nowego APK.

Written on July 5, 2018 by Michał Dardas