Dekompilace androidích aplikací


Někdo se rád pídí po tom, jak věci fungují, někdo se rád občas nechává inspirovat cizími kusy kódu a někdo prachsprostě krade (možná by se to dalo nazvat nějakou IT kleptomanií). Všem těmto skupinám by ovšem mohl přijít vhod tento blogpost, protože v několika krocích popisuje operaci jednoduchou (tu jednoduchost myslím vážně, zabývat se dedexerem, aka android disassemblerem opravdu nehodlám, z toho už jsem vyrostl a zpohodlněl) – a sice rozbalování a dekompilaci androidí aplikace.

Jak je tvořena androidí aplikace asi každý vývojář ví, takže tuto část vypustíme a přejděme blíže k věci, což by mohl být aapt, neboli Android Asset Packing Tool, který je součástí nástrojů v SDK. Tento nástroj je jednak zodpovědný za parsování všemožných souborů (včetně manifestu) uvnitř projektu a následné přetváření takových properties do R.java souboru, ale především i za proces opačný, čili dolování informací z již hotových .apk souborů a to i podepsaných a zarovnaných. Nebudeme chodit kolem horké kaše a skočme rovnou do nějakého příkladu. Půjčil jsem si APKčko z mého rozdělaného projektu a provedl nad ním následující kouzlo:

[sourcecode type=“bash“]vbalak@vbalak-desktop:~/develop/workspace.sts/PlantATree/client/target$ aapt l -a pat-client.apk
res/layout/area_map.xml
res/layout/main.xml
res/layout/tree_details.xml
res/layout/tree_list.xml
res/layout/tree_list_item.xml
res/menu/map_menu.xml
AndroidManifest.xml
resources.arsc
res/drawable-hdpi/icon.png
res/drawable-ldpi/icon.png
res/drawable-mdpi/icon.png
classes.dex
org/codehaus/jackson/map/VERSION.txt
org/codehaus/jackson/impl/VERSION.txt
META-INF/MANIFEST.MF
META-INF/CERT.SF
META-INF/CERT.RSA
[/sourcecode]

Nejprve je vidět seznam souborů nacházejících se v archivu (.apk je obyčejný zip soubor, takže je možné jej jednoduše rozbalit, v tom není žádná věda). Další část (resource table) je zajímavější – jedná se o identifikátory zdrojů, neboli to, co je v souboru R.java – to jsou ty hexa čísla uvedená bezprostředně za spec resource a dále typ tohoto zdroje – layout, string, drawable, id…

[sourcecode type=“plain“]Resource table:
Package Groups (1)
Package Group 0 id=127 packageCount=1 name=cz.shmoula.pat
Package 0 id=127 name=cz.shmoula.pat typeCount=6
type 0 configCount=0 entryCount=0
type 1 configCount=3 entryCount=1
spec resource 0x7f020000 cz.shmoula.pat:drawable/icon: flags=0x00000100
spec resource 0x7f04000a cz.shmoula.pat:string/menu_toggle_view: flags=0x00000000
. . .[/sourcecode]

Nejzajímavější je ovšem část poslední, což je sám velký manifest. Kdo měl možnost nahlédnout do AndroidManifest.xml a teď kouká na tento výpis, všímá si velké podobnosti (pokud potlačí rozdílný způsob zobrazení – tohle není xml ;-)). Jsou zde krásně vidět využívaná oprávnění, je zde vidět, jakou program používá ikonu (to je ten hexa kód, který se dá dohledat v části se zdroji – Resources Table). Jsou zde vidět jednotlivé aktivity, parametry aktivit a definované intent-filtry a také využívané knihovny – prostě kompletní manifest, akorát jinak formátovaný. Pro naše další potřeby potřebujeme vstupní bod do aplikace, což bude LAUNCHER a ten je nastaven pro třídu MainActivity, která je v balíčku cz.shmoula.pat, bude se nám hodit za chvíli. Za zmínku ještě stojí anotherMapProcess v poslední aktivitě – dvě mapy se v jedné aplikaci nesnesou, tudíž je nutné je spouštět v rámci jiného procesu, tento parametr tohle zajišťuje (taky jsem nad tím tenkrát dlouho koumal).

[sourcecode type=“plain“]Android manifest:
N: android=http://schemas.android.com/apk/res/android
E: manifest (line=2)
A: android:versionCode(0x0101021b)=(type 0x10)0x1
A: android:versionName(0x0101021c)="0.1" (Raw: "0.1")
A: package="cz.shmoula.pat" (Raw: "cz.shmoula.pat")
E: uses-permission (line=5)
A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
E: application (line=7)
A: android:label(0x01010001)=@0x7f040001
A: android:icon(0x01010002)=@0x7f020000
E: activity (line=8)
A: android:name(0x01010003)=".MainActivity" (Raw: ".MainActivity")
E: intent-filter (line=9)
E: action (line=10)
A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
E: category (line=11)
A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
E: activity (line=15)
A: android:name(0x01010003)=".LookAroundActivity" (Raw: ".LookAroundActivity")
. . .
E: activity (line=16)
A: android:theme(0x01010000)=@0x1030006
A: android:name(0x01010003)=".ShowAreaMapActivity" (Raw: ".ShowAreaMapActivity")
A: android:process(0x01010011)=":anotherMapProcess" (Raw: ":anotherMapProcess")
E: uses-library (line=22)
A: android:name(0x01010003)="com.google.android.maps" (Raw: "com.google.android.maps")
[/sourcecode]

V této fázi tedy máme hrubý přehled o struktuře aplikace, bylo by vhodné se dostat ke třídám. Ty jsou zabalené uvnitř souboru classes.dex, který se nacházi uvnitř APKčka, takže bych prosil rozzipovat tento archiv. Tento soubor je víceméně nějakým způsobem rozsypaný Java ARchive a pro jeho sesypání do použitelného formátu slouží utilitka dex2jar, která se spouští jednoduchým způsobem:

[sourcecode type=“bash“]vbalak@vbalak-desktop:~/develop/stuff/dex2jar-0.0.7.8-SNAPSHOT$ ./dex2jar.sh classes.dex
version:0.0.7.8-SNAPSHOT
3 [main] INFO pxb.android.dex2jar.v3.Main – dex2jar classes.dex -> classes.dex.dex2jar.jar
Done.[/sourcecode]

Získali jsme tedy opravdový archiv .jar, který je opět možné rozzipovat a koukat na jednotlivé zkompilované třídy. Také je možné udělat víc – pomocí některého java dekompileru je možné se podívat dovnitř, já volil Java Decompiler. Pomocí něj je možné otevřít získaný .jar soubor a v levé části otevřít požadovanou třídu (výše jsme zjistili, že vstupním bodem je MainActivity) a užívat pocitu vítězství, nebo začít vykrádat se začít inspirovat cizím kódem. Toď vše, pro ilustraci ještě přikládám shot JavaDecompileru.

JavaDecompiler - screenshot
JavaDecompiler – screenshot

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *