Smali - Dekomplovanje/[Modifikovanje]/Kompajliranje
Tip
Nauči i vežbaj AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Nauči i vežbaj GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Nauči i vežbaj Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Pregledaj kompletan HackTricks Training katalog za assessment tracks (ARTA/GRTA/AzRTA) i Linux Hacking Expert (LHE).
Podrži HackTricks
- Pogledaj pretplatničke planove!
- Pridruži se 💬 Discord grupi, telegram grupi, prati @hacktricks_live na X/Twitter, ili pogledaj LinkedIn stranicu i YouTube kanal.
- Deli hacking trikove slanjem PR-ova u HackTricks i HackTricks Cloud github repozitorijume.
Ponekad je interesantno izmeniti kod aplikacije da biste pristupili skrivenim informacijama (možda dobro obfuskisanim lozinkama ili flagovima). Zbog toga može biti korisno dekompilovati apk, izmeniti kod i ponovo ga kompajlirati.
Referenca opkodova: http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
Brzi način
Koristeći Visual Studio Code i ekstenziju APKLab, možete automatski dekompilovati, izmeniti, ponovo kompilovati, potpisati & instalirati aplikaciju bez izvršavanja bilo koje komande.
Još jedna skripta koja mnogo olakšava ovaj zadatak je https://github.com/ax/apk.sh
Split APKs / App Bundles
Savremeni ciljevi se obično isporučuju kao split APKs (base.apk + split_config.*.apk) umesto jednog monolitnog APK-a. Ako izmenite samo base.apk, resursi ili native biblioteke mogu postati neusklađeni i instalacija može da ne uspe.
Brza trijaža sa uređaja:
adb shell pm path com.example.app
adb pull /data/app/.../base.apk
adb pull /data/app/.../split_config.arm64_v8a.apk
adb pull /data/app/.../split_config.en.apk
Ako je cilj split package, ili ponovo izgradite ceo skup ili koristite alate koji prvo spajaju APK-ove. apk.sh je koristan ovde jer može da kombinuje split APK-ove u jedan APK koji se može patchovati i ispravi javne identifikatore resursa.
Za repacking tokove rada orijentisane na Frida/Objection, pogledajte i Android Anti-Instrumentation & SSL Pinning Bypass.
Dekompajlirajte APK
Koristeći APKTool možete pristupiti smali kodu i resursima:
apktool d APP.apk
Ako apktool prijavi bilo koju grešku, pokušajte installing the latest version
Some interesting files you should look are:
- res/values/strings.xml (i sve xml fajlove unutar res/values/*)
- AndroidManifest.xml
- Bilo koja datoteka sa ekstenzijom .sqlite ili .db
Ako apktool ima probleme pri dekodiranju aplikacije, pogledajte https://ibotpeaches.github.io/Apktool/documentation/#framework-files ili pokušajte da koristite argument -r (Ne dekodiraj resurse). Zatim, ako je problem bio u resursu, a ne u source code-u, nećete više imati problem (takođe nećete dekompajlirati resurse).
Izmeni Smali code
Možete promeniti instrukcije, promeniti vrednost nekih promenljivih ili dodati nove instrukcije. Ja menjam Smali code koristeći VS Code, zatim instalirajte smalise extension i editor će vam reći ako je neka instrukcija netačna.
Neki primeri se mogu naći ovde:
Ili možete check below some Smali changes explained.
Ponovo kompajlirajte APK
Nakon izmene koda možete ponovo kompajlirati kod koristeći:
apktool b . #In the folder generated when you decompiled the application
Ovo će compile novi APK inside dist folder.
Ako apktool izbaci grešku, pokušajte instalirati najnoviju verziju
Potpišite novi APK
Zatim, potrebno je generisati ključ (biće zatražena lozinka i neke informacije koje možete popuniti nasumično):
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <your-alias>
Na kraju, potpišite novi APK:
jarsigner -keystore key.jks path/to/dist/* <your-alias>
jarsigner još uvek radi za neke brze testove, ali za moderne Android buildove apksigner je poželjniji jer podržava novije sheme potpisivanja APK-a.
Optimizujte novu aplikaciju
zipalign je alat za poravnavanje arhiva koji pruža važnu optimizaciju Android APK datoteka. Više informacija ovde.
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
zipalign -v 4 infile.apk
Ako APK sadrži ugrađene nativne biblioteke (lib/*.so), Android sada preporučuje korišćenje -P 16 kako bi .so datoteke bile poravnate za uređaje sa veličinom stranice 16 KiB i 4 KiB:
zipalign -P 16 -f -v 4 infile.apk outfile.apk
Potpišite novi APK (ponovo?)
Ako više volite da koristite apksigner umesto jarsigner, trebalo bi da potpišete apk nakon primene optimizacije sa zipaling. ALI OBRATITE PAŽNJU DA JE POTREBNO POTPISATI APLIKACIJU SAMO JEDNOM SA jarsigner (pre zipalign) ILI SA aspsigner (posle zipaling).
apksigner sign --ks key.jks ./dist/mycompiled.apk
Praktičniji, moderniji tok je:
apktool b . -o dist/app-unsigned.apk
zipalign -P 16 -f -v 4 dist/app-unsigned.apk dist/app-aligned.apk
apksigner sign --ks key.jks --out dist/app-signed.apk dist/app-aligned.apk
apksigner verify --verbose --print-certs dist/app-signed.apk
Važne napomene:
- Ako izmenite APK nakon potpisivanja sa
apksigner, potpis se poništava i morate ga ponovo potpisati. apksigner verify --print-certsje koristan za potvrdu da je ponovo izgrađeni APK instalabilan i za pregled sertifikata koji će cilj prikazati tokom izvršavanja.
Izmena Smali
Za sledeći Hello World Java kod:
public static void printHelloWorld() {
System.out.println("Hello World")
}
Smali kod bi bio:
.method public static printHelloWorld()V
.registers 2
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "Hello World"
invoke-virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
return-void
.end method
The Smali instruction set is available here.
Lagane izmene
Izmena početnih vrednosti promenljive unutar funkcije
Neke promenljive su definisane na početku funkcije koristeći opcode const, možete izmeniti njihove vrednosti ili definisati nove:
#Number
const v9, 0xf4240
const/4 v8, 0x1
#Strings
const-string v5, "wins"
Osnovne operacije
#Math
add-int/lit8 v0, v2, 0x1 #v2 + 0x1 and save it in v0
mul-int v0,v2,0x2 #v2*0x2 and save in v0
#Move the value of one object into another
move v1,v2
#Condtions
if-ge #Greater or equals
if-le #Less or equals
if-eq #Equals
#Get/Save attributes of an object
iget v0, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Save this.o inside v0
iput v0, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Save v0 inside this.o
#goto
:goto_6 #Declare this where you want to start a loop
if-ne v0, v9, :goto_6 #If not equals, go to: :goto_6
goto :goto_6 #Always go to: :goto_6
Veće promene
Smali zamke koje obično kvare ponovnu izgradnju
- Preporučuje se povećati
.localskada su vam potrebni samo privremeni registri u telu postojeće metode. Parametarski registri (p0,p1…) mapirani su na najviše registre metode, pa besciljno prebacivanje na.registersčesto kvari raspored argumenata. move-result,move-result-wide, imove-result-objectmoraju se pojaviti odmah nakon odgovarajućeginvoke-*. Umetanje logovanja ili bilo kog drugog opkoda između njih čini metodu nevažećom.longidoublevrednosti su wide vrednosti i zauzimaju par registara. Ako kasnije ponovo koristite te registre, zapamtite dav10takođe zauzimav11.- Ako treba da prosledite mnogo registara, ili registre sa visokim brojevima, koristite
/rangevarijante kao što suinvoke-virtual/range.
Logovanje
#Log win: <number>
iget v5, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Get this.o inside v5
invoke-static {v5}, Ljava/lang/String;->valueOf(I)Ljava/lang/String; #Transform number to String
move-result-object v1 #Move to v1
const-string v5, "wins" #Save "win" inside v5
invoke-static {v5, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I #Logging "Wins: <num>"
Recommendations:
- Ako planirate da koristite deklarisane promenljive unutar funkcije (deklarisane v0,v1,v2…) stavite ove linije između .local
i deklaracija promenljivih (const v0, 0x1) - Ako želite da ubacite logging kod u sredinu koda funkcije:
- Dodajte 2 na broj deklarisanih promenljivih: Npr: od .locals 10 do .locals 12
- Nove promenljive treba da budu sledeći brojevi nakon već deklarisanih (u ovom primeru to treba da budu v10 i v11, zapamtite da počinje u v0).
- Izmenite kod logging funkcije i koristite v10 i v11 umesto v5 i v1.
Patching common anti-tamper checks
When an app is repacked, one of the first things that may break is an in-app signature / installer / integrity check. Good strings to search in JADX or in the smali tree are:
GET_SIGNATURESGET_SIGNING_CERTIFICATESapkContentsSignersMessageDigestSHA-256Base64getInstallerPackageNamecom.android.vending
Modern apps often call PackageManager.getPackageInfo(..., GET_SIGNING_CERTIFICATES), hash the signer bytes with MessageDigest, and compare the result with a hardcoded constant. In practice, it is usually easier to patch the final boolean / branch than to rewrite all the signature-handling code.
Example patterns:
# Force a boolean result to "valid"
const/4 v0, 0x1
# Or invert the branch that sends execution to the tamper handler
if-eqz v0, :tamper_detected # original
if-nez v0, :tamper_detected # patched
Ako je verifikacioni kod bučan, potražite poslednje poređenje pre dijaloga o grešci / finish() / System.exit() / poziva telemetry i izmenite tamo umesto da dirate celu rutinu.
Toasting
Zapamtite da dodate 3 broju .locals na početku funkcije.
Ovaj kod je pripremljen da bude umetnut u sredinu funkcije (promenite broj varijabli po potrebi). On će uzeti vrednost this.o, pretvoriti je u String i zatim prikazati toast sa tom vrednošću.
const/4 v10, 0x1
const/4 v11, 0x1
const/4 v12, 0x1
iget v10, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I
invoke-static {v10}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v11
invoke-static {p0, v11, v12}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v12
invoke-virtual {v12}, Landroid/widget/Toast;->show()V
Učitavanje nativne biblioteke pri pokretanju (System.loadLibrary)
Ponekad je potrebno unapred učitati nativnu biblioteku tako da se ona inicijalizuje pre ostalih JNI libova (npr. da bi se omogućila lokalna za proces telemetry/logging). Možete ubaciti poziv System.loadLibrary() u statički inicijalizator ili rano u Application.onCreate(). Primer smali za statički inicijalizator klase (
.class public Lcom/example/App;
.super Landroid/app/Application;
.method static constructor <clinit>()V
.registers 1
const-string v0, "sotap" # library name without lib...so prefix
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
Kao alternativu, postavite iste dve instrukcije na početak vašeg Application.onCreate() da biste osigurali da se biblioteka učita što ranije:
.method public onCreate()V
.locals 1
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
invoke-super {p0}, Landroid/app/Application;->onCreate()V
return-void
.end method
Napomene:
- Uverite se da odgovarajuća ABI varijanta biblioteke postoji u lib/
/ (npr. arm64-v8a/armeabi-v7a) kako biste izbegli UnsatisfiedLinkError. - Učitavanje veoma rano (class static initializer) garantuje da native logger može posmatrati naknadnu JNI aktivnost.
Smali statička analiza / Lov zasnovan na pravilima
Nakon dekompajliranja sa apktool, možete skenirati Smali liniju po liniju pomoću regex pravila da brzo otkrijete anti-analitičku logiku (provere root/emulator) i verovatno hardkodovane tajne. Ovo je brza trijaža tehnika: tretirajte pronađeno kao tragove koje morate verifikovati u okolnom Smali ili rekonstruisanom Java/Kotlin kodu.
Ključne ideje:
- Filtriranje biblioteka: potiskujte ili označavajte nalaze pod uobičajenim third-party namespace-ovima kako biste se fokusirali na putanje koda koje pripadaju aplikaciji.
- Naznake konteksta: zahtevajte da se sumnjivi stringovi pojavljuju blizu API-ja koji ih koriste (u istoj metodi, unutar N linija).
- Stepen poverenja: koristite jednostavne stepene (visok/srednji) za rangiranje tragova i smanjenje lažnih pozitivnih.
Example library prefixes to suppress by default:
Landroidx/
Lkotlin/
Lkotlinx/
Lcom/google/
Lcom/squareup/
Lokhttp3/
Lokio/
Lretrofit2/
Primeri pravila detekcije (regex + heuristike konteksta):
{
"category": "root_check",
"regex_patterns": [
"(?i)invoke-static .*Runtime;->getRuntime\\(\\).*->exec\\(.*\\"(su|magisk|busybox)\\"",
"(?i)const-string [vp0-9, ]+\\"(/system/xbin/su|/system/bin/su|/sbin/su)\\""
],
"context_hint": "Only report when the same method also calls File;->exists/canExecute or Runtime;->exec."
}
Dodatne heuristike koje dobro funkcionišu u praksi:
- Root package/path checks: zahtevaju prisustvo u blizini poziva
PackageManager;->getPackageInfoiliFile;->existsza stringove kao što sucom.topjohnwu.magiskili/data/local/tmp. - Emulator checks: sparuj sumnjive literale (npr.,
ro.kernel.qemu,generic,goldfish) sa bliskimBuild.*getterima i poređenjima stringova (->equals,->contains,->startsWith). - Hardcoded secrets: označi
const-stringsamo kada u blizini.fieldilimove-resultidentifikatora postoje ključne reči kaopassword,token,api_key. Izričito ignoriši markere koji su samo za UI kaoAutofillType,InputType,EditorInfo.
Skeneri zasnovani na pravilima poput PulseAPK Core implementiraju ovaj model kako bi brzo identifikovali logiku protiv analize i potencijalne tajne u Smali.
Reference
- PulseAPK Core
- PulseAPK Smali Detection Rules
- SoTap: Lagani in-app JNI (.so) logger ponašanja – github.com/RezaArbabBot/SoTap
- Android Developers: apksigner i zipalign
- apk.sh: github.com/ax/apk.sh
Tip
Nauči i vežbaj AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Nauči i vežbaj GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Nauči i vežbaj Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Pregledaj kompletan HackTricks Training katalog za assessment tracks (ARTA/GRTA/AzRTA) i Linux Hacking Expert (LHE).
Podrži HackTricks
- Pogledaj pretplatničke planove!
- Pridruži se 💬 Discord grupi, telegram grupi, prati @hacktricks_live na X/Twitter, ili pogledaj LinkedIn stranicu i YouTube kanal.
- Deli hacking trikove slanjem PR-ova u HackTricks i HackTricks Cloud github repozitorijume.


