Reverse engineering APK file

Izvor: SIS Wiki
Skoči na: orijentacija, traži

Temu rezervirao: Filip Aleksić

Sadržaj

Reverzno inženjerstvo

Reverzno inženjerstvo je proces izvlačenja informacija i znanja iz proizvoda, te pomoću tih informacija kreiranje tog proizvoda ili dijela tog proizvoda. Kad govorimo o programskom reverznom inženjerstvu, tada najčešće mislimo na uzimanje postojećeg progama od kojeg nemamo izvorni kod i pokušavamo saznati kako je taj program implementiran i dizajniran.

APK - Android Package File

Apk je paket koji Android sustav koristi za distribuciju i instalaciju aplikacija. Izvorni kod se prvo kompilira i onda se pakira u APK. On je zapravo zip format baziran na JAR formatu. Zip je format datoteke koji služi za arhiviranje podataka u kompresiranom obliku bez gubitka podataka, a jar je paket koji obično sadrži više Java klasa, resursa, itd.

Sadržaj APK datoteke je strukturiran na sljedeći način:

MANIFEST.MF - Tekstualna datoteka koja sadrži imena svih datoteka i SHA256 hash blob-a svake datoteke.
CERT.RSA - Certifikat aplikacije
CERT.SF - Sadrži imena datoteka i SHA256 hash odgovarajućih linija iz MANIFEST.MF

Trenutni sadržaj možemo dobiti tako da unzipamo datoteku nekim alatom ili putem komandne linije unzip -e <ime_datoteke>.apk -d <ime_izlazne_datoteke>. Takav kod je jako teško analizirati jer je velik dio kompajliran te zbog toga koristimo razne alate koji nam olakšavaju analizu.

Kako doći do .apk datoteke?

Do datoteke je moguće doći na više načina. Ako je aplikacija instalirana na Android uređaj možemo koristiti alata koji se zove ADB (Android debug bridge). On nam omogućuje komuniciranje s uređajem putem komandne linije na računalu, uključen je u Android SDK tako da ako recimo razvijate za Android nije potrebno ništa dodatno instalirati. Pomoću naredbe adb shell pm list packages možete vidjeti sve pakete instalirane na uređaju. Nakon što smo vidjeli sva imena paketa, pronađemo onaj koji želimo "izvući" na naše računalo i upišemo naredbu adb pull /data/app/<ime_paketa>.apk <lokacija_spremanja>.

Osim preko uređaja moguće je koristiti web stranice poput APKMirror, APK Downloader, itd ili korištenjem ne službenog API-a Google Play API.

Proces kompajliranja

Android kod je najčešće pisan u Java programskom jeziku iako je u posljednje vrijeme sve češći i Kotlin. U ovom odjeljku ću objasniti kako se Java kod kompajlira.

Prvo se Java kod kompajlira u .class datoteke pomoću javac naredbe. Datoteke sadrže Java bytecode koji predstavlja Java bajt kod. Ovakav kod se uobičajeno pokreće na Java virtualnim mašinama JVM, ali Android ne koristi taj kod već drugu vrstu bajt koda koja se zove Dalvik. Kod se iz Java bajt koda i bilo kojih potrebnih .jar biblioteka u Dalvik bajt kod pretvara pomoću naredbe dx i izlazne datoteke su tipa .dex. Potom su sve class.dex datoteke, resursi, manifest i ostale kompresirane u .apk datoteku i može se napraviti pomoću alata aapt. Nakon što smo dobili .apk datoteku možemo ju distribuirati. Ako ju želimo distribuirati putem Google Play Storea onda aplikacija mora biti potpisana. Potpisivanje aplikacija se sastoji od dodavanja sljedećih datoteka u .apk datoteku: datoteka koja sadrži checksum i generiranog privatnog ključa. Potpisivanje se obavlja s alatom jarsigner koji se također koristi za potpisivanje jar datoteka. Za kraj potrebno je napraviti byte align što je način rasporeda bajtova. Android to zahtjeva kako bi mogao lakše i brže čitati datoteku.

Alati

Jedni od alata koji nam mogu pomoći u analizi koda su sljedeći:


Kali operacijski sustav ima u sebi sljedeće od spomenutih alata: apktool, dex2jar i radare2.

Primjeri

Ovo poglavlje ću prikazati praktične primjere. Prvi primjer će biti reverzno inženjerstvo jako jednostavne Android aplikacija kako bi vidjeli strukturu aplikacije, kako možemo izmjeniti kod i vratiti nazad u apk.

Za sljedeći primjer ćemo koristiti istu aplikaciju, ali će njen kod biti zamršen (obfuskiran). Objasnit ću što je i kako se radi obfuskacija, te mogućnosti zaobilaženja obuskacije.

Zadnji primer će biti stvarna aplikacija koju ćemo preuzeti s Google Play na uređaj, pa s uređaja na računalo i analizirati ju.

Primjer 1 - Hello Reverse

Hello Reverse je jako jednostavna aplikacija koja je kreirana pomoću empty predloška od Android Studia, jedina izmjena je da umjesto Hello World piše Hello Reverse. Nakon navedenih izmjena sam pokrenuo Run u Android Studiu i aplikacija se pokrenula. Znamo da je potrebna .apk datoteka kako bi se aplikacija mogla pokretati na uređaju i nalazi se na lokaciji <root_projekta>/app/build/outputs/apk/debug/app-debug.apk.

Sad kad smo pronašli .apk datoteku možemo započeti s radom.

Napravit ćemo disassemble pomoću apktool. Pozicioniramo se u lokaciju gdje je .apk smješten i pokrenemo komandu apktool d app-debug.apk.

Izlaz bi trebao izgledati otprilike ovako:

Printsc apktool.png

Alat je sve izlazne datoteke spremio u datoteku nazvanu kao i sama aplikacija, u ovo slučaju app-debug. Datoteka sadrži disassemblane resurse u XML datoteke koje su čitljive i pretvorio je sve class datoteke u smali format. Sad kad imamo čitljive datoteke napravit ćemo promjenu u aplikaciji. Krenimo prvo od AndroidManifest.xml datoteke jer u njoj kao manifest tipu datoteke pišu osnovne informacije o aplikaciji. Vidimo razne informacije, ali one koje su nama zanimljive za naš zadatak su aktivnosti. U ovoj aplikaciji ima samo jedna i zove se MainActivity. Znamo da želimo promjeniti tekst koji se ispisuje u dizajnu što znači da nam treba XML te aktivnosti. Poznavajući uobičajene konvencije pisanja Android koda taj tekst se može najvjerojatnije nalaziti samo na 2 mjesta. Prvo je u strings.xml datoteci koja sadrži sve tekstove iz aplikacije, a drugo je u njezinom layoutu. Ako se Java datoteka aktivnosti zove MainActivity.java tada se njen XML zove activity_main.xml. Zadnje moguće mjesto gdje je moguće da je programer stavio tekst je u sam java kod. Pa krenimo redoslijedom tražeći "Hello Reverse!" tekst.

Znamo da se string.xml datoteka inače nalazi u res/values pa ćemo i ovdje ići tim putem i stvarno pronaći naš strings.xml, no tokom analiziranja XML-a možemo vidjeti da se tu ne nalazi naš tekst. Sljedeći korak je activity_main.xml, on se inače nalazi u res/layout. Otvaranjem te datoteke možemo stvarno pronaći activity_main.xml i vidimo da TextView ima atribut text u kojem piše naša vrijednost. Možemo ju sad promjeniti pomoću bilo kojeg editora, ja ću ju promjeniti u "Hacked".

Printscr zad1.png

Sad je potrebno ponovo stvoriti .apk datoteku koju je moguće pokrenuti i apktool nam to omogućava.

Naredbom apktool b app-debug -o hack.apk ponovo kreiramo apk datoteku iz nasih izmjenjenih podataka. Ako pokušamo ovu datoteku samo prebaciti na uređaj i instalirati dobit ćemo upozorenje "The package appears to be corrupt.". Razlog tome je što aplikaciju nismo bitovno alignali niti potpisali, pa ćemo to napraviti pomoću zipalign i apksigner koji su dio Android SDK (može ih se pronaći u build tools).

Prvo ćemo bitovno poravnati aplikaciju naredbom ./zipalign -v -p 4 /Users/faleksic/Downloads/vbox/hacked.apk /Users/faleksic/Downloads/vbox/hacked-aligned.apk. Sljedeći korak je generirati ključ za potpisivanje aplikacije: keytool -genkey -v -keystore test-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias test-key i na kraju potpisujemo poravnatu aplikaciju ./apksigner sign --ks /Users/faleksic/Downloads/vbox/test-key.jks --out /Users/faleksic/Downloads/vbox/hack-r.apk /Users/faleksic/Downloads/vbox/hacked-aligned.apk.

Na kraju imamo izmjenjen tekst na aplikaciji:


Device-pr1.png


Primjer 2 - Hello Obfuscated

Možemo vidjeti da nije teško mijenjati nečiji kod niti pogledati kako funkcionira iz gotove aplikacije. Zbog toga programeri koji zarađuju novac osmišljavajući algoritme žele zaštiti svoje intelektualno vlasništvo i ne želie da netko njihov proizvod lako otvori i otkrije kako funkcionira. Osim toga reverzno inženjerstvo programa predstavlja i sigurnosni rizik jer to olakšava napadaču da pronađe moguće slabosti u programu.

Zbog toga je smišljen način otežavanja reverznog inženjerstva koda, a zove se obfuskacija. Obfuskacija je proces pomoću kojeg napravimo nešto čitko teško razumljivio. U svijetu softwarea kod se obfuskira tako da se imena varijabli, metoda i klasa promjene u besmisleni niz znakova tako da je teško naći smisao u kodu, dodaje se kod koji ne radi ništa kako bi zbunio čitatelja, kriptiraju se dijelovi koda, itd. Kod se obuskira pomoću alata koji se zove obfuskator.

Najpoznatiji obfuskatori za Android su ProGuard i DexGuard. Alati su razvijeni od firme Guard Square, razlika je u tome što je ProGuard besplatan alat otvorenog koda dok je DexGuard komercijalni proizvod. Osim toga ProGuard je optimizator Java bajt koda, minimizira, obfuskira i optimizira desktop, Android i ugrađene aplikacije. DexGuard radi sve što i ProGuard. ali je specifično rađen za Android aplikacije. Štiti od statičke i dinamičke analize aplikacije, dodaje mnogo slojeva kriptiranja i obfuskacije i procesira sve komponente aplikacije.

Prikaz ProGuard zaštite - Izvor
Prikaz DexGuard zaštite - Izvor

U ovom primjeru ću pokazati jednostavnu aplikaciju koja se sastoji od 2 ekrana. Prvi ekran očekuje unos šifre od korisnika kako bi mu pokazao sljedeći ekran na koje je tajna. Ako korisnik upiše netočnu šifru neće ga propustiti dalje. Aplikacija je namjerno isprogramirana nesigurno i šifra je stavljena u izvorni kod. Pokušat ćemo obfuskirati aplikaciju, te pokušati reveznim inženjerstvom doći do šifre.

Uključivanje obfuskacije nije komplicirano ako koristimo Android studio, samo je potrebno u build.gradle datoteci u modulu app postaviti minifyEnabled na true.

 release {
   minifyEnabled true
   proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }

proguard-rules.pro je datoteka unutar našeg projekta pomoću koje možemo definirati pravila koja govore ProGuardu koje datoteke sačuvati, a ne maknuti tokom procesa smanjivanja aplikacije. Mi nećemo dodati ništa jer nam je dovoljno ono što je zapisano u getDefaultProguardFile('proguard-android.txt').


Nakon što je sve definirano generiramo release verziju aplikacije, kako to napraviti možete pronaći ovdje.

Nakon svakog builda ProGuard generira dodatne datoteke u app/build/outputs/mapping/release/ među kojima je nama najzanimljiviji mapping.txt u kojem su prijevodi između svih originalnih nazivlja i onih koje je zadao ProGuard. Kada bi imali ovu datoteku za neku obfuskiranu aplikaciju mogli bi lako obrnuti proces. Samo napomena čitatelju ako radi Android aplikacije da ne izgubi ovu datoteku jer kasnije neće moći debuggirati logove, odnosno biti će jako teško.

Recimo u našem slučaju da mi ne posjedujemo tu datoteku i da idemo na isti način kao u prvom primjeru disassemblati aplikaciju. Ponovno smo iskoristili apktool, ali ovog puta na debug veziji i release (debug nije obfuskirana, release je). Gledajući osnovnu strukturu obe verzije se sastoje od istih direktorija, ali neke datoteke se zovu drugačije jer su im imena obfuskirana i na release verziji imamo puno manje release smali datoteka jer ProGuard minificira kod odnosno briše ono što nije skroz potrebno. U obe verzije se nalaze MainActivity.smali datoteka koja sadrži metode iz glavne aktivnosti.

Prikaz checkPassword metode (lijevo ne obfuskiran kod, desni obfuskiran)

Gledajući datoteke možemo primjetiti da se u obfuskiranom dijelu koda metoda zove a, ne piše naziv ulaznog parametra, ali ostalo je relativno slično i ono što je najbitnije da se hardkodirani tekst koji je šifra vidljiv čak i kad je aplikacija obfuskirana pomoću ProGuarda. Mi naravo ne bi odmah znali da je to šifra, ali možemo primjetiti da je to string koji ne bi očekivali u aplikaciji i poziva se metoda equals koja provjerava jednakost stringova. Ove činjenice nam mogu biti dovoljan povod za testiranje ove šifre. Isto tako smo i mogli zamjeniti tu vrijednost za prazan string i mogli bi ući u tajnu aktivnost bey ikakvog ulaza!


Primjer 3 - Analiza Erste aplikacije

U zadnjem primjeru ću pokazati kako dohvatiti aplikaciju i saznati osnovne informacije o njoj statičkom analizom. Za primjer ću koristiti Erste Android aplikaciju koju već imam instaliranu na mobitelu. Aplikaciju ću dohvatiti na računalo pomoću naredbe adb pull /data/app/com.infinum.erste-2/base.apk ~/Desktop/erste.apk . Nakon izvršenja naredbe na računalu se nalazi .apk datoteka koju pomoću apktoola disassemblamo: apktool d erste.apk. Sad imamo erste datoteku koju možemo analizirati.

Prvo ćemo početi s promatranjem AndroidManifest.xml datoteke, možemo vidjeti da aplikacija traži preko 20 dozvola, koristi google mape, crashlytics, neka vlastita 3 servisa i ima preko 100 aktivnosti što nam govori da je aplikacija stvarno velika. Otvaranjem smali datoteke možemo vidjeti da su neke datoteke nazvane samo jednim slovom po čemu možemo zaključiti da je aplikacija obfuskirana. Promatrajući imena datoteka koje nisu obfuskirane možemo prepoznati poznate biblioteke poput microblink, firebase, gson, itd. Pomoću ovih analizamožemo pretpostaviti koje funkcije može obavljati aplikacija i što se vjerojatno u njoj nalazi. Ovakva statička analiza se često koristi za provjeru da li neka aplikacija sadrži maliciozni kod.

Cilj je bio i promjeniti nešto unutar aplikacije, ali to bi zahtjevalo puno veću analizu zbog količine koda kojeg sadrži.

Literatura

  1. David Griffiths (2017.) How Android Apps are Built and Run, Dostupno 29.01.2018 https://github.com/dogriffiths/HeadFirstAndroid/wiki/How-Android-Apps-are-Built-and-Run
  2. Tim Strayyere, Jon Sawyer, Caleb Fenton (2015.) Offensive and defensive android reverse engineering, Dostupno 29.01.2018 https://github.com/rednaga/training/tree/master/DEFCON23
  3. Wikipedia (2018.) Android application package, Dostupno 29.01.2018 https://en.wikipedia.org/wiki/Android_application_package
  4. Wikipedia (2017.) Android Runtime, Dostupno 29.01.2018 https://en.wikipedia.org/wiki/Android_Runtime
  5. Wikipedia (2018.) Dalvik (software), Dostupno 29.01.2018 https://en.wikipedia.org/wiki/Dalvik_(software)
  6. Pau Oliva Fora (2014.) Beginners Guide to Reverse Engineering Android Apps, Dostupno 29.01.2018 https://www.rsaconference.com/writable/presentations/file_upload/stu-w02b-beginners-guide-to-reverse-engineering-android-apps.pdf
  7. GuardSquare (2017.) DexGuard vs. ProGuard, Dostupno 29.01.2018 https://www.guardsquare.com/en/blog/dexguard-vs-proguard
  8. Android Developers (2017.) Shrink Your Code and Resources, Dostupno 29.01.2018 https://developer.android.com/studio/build/shrink-code.html
Osobni alati
Imenski prostori
Inačice
Radnje
Orijentacija
Traka s alatima