Smali - Decompiling/[Modifying]/Compiling

Reading time: 8 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Manchmal ist es interessant, den Anwendungscode zu verändern, um für dich versteckte Informationen zu erhalten (z. B. gut obfuskierte Passwörter oder flags). Dann kann es sinnvoll sein, die apk zu dekompilieren, den Code zu ändern und wieder zu kompilieren.

Opcodes-Referenz: http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

Schneller Weg

Mit Visual Studio Code und der Erweiterung APKLab kannst du die Anwendung automatically decompile, ändern, recompile, signieren & installieren, ohne einen Befehl auszuführen.

Ein weiteres Skript, das diese Aufgabe stark erleichtert, ist https://github.com/ax/apk.sh

APK dekompilieren

Mit APKTool kannst du auf den smali code und die Ressourcen zugreifen:

bash
apktool d APP.apk

Wenn apktool dir einen Fehler meldet, versuche installing the latest version

Einige interessante Dateien, die du dir ansehen solltest, sind:

  • res/values/strings.xml (und alle xml-Dateien in res/values/*)
  • AndroidManifest.xml
  • Jede Datei mit der Erweiterung .sqlite oder .db

Wenn apktool Probleme beim Decodieren der Anwendung hat, sieh dir https://ibotpeaches.github.io/Apktool/documentation/#framework-files an oder versuche das Argument -r zu verwenden (Ressourcen nicht decodieren). Wenn das Problem also in einer Ressource und nicht im Quellcode lag, wirst du das Problem nicht mehr haben (du wirst die Ressourcen dann auch nicht dekompilieren).

Smali-Code ändern

Du kannst Anweisungen ändern, den Wert einiger Variablen ändern oder neue Anweisungen hinzufügen. Ich ändere den Smali-Code mit VS Code, du installierst dann die smalise extension und der Editor zeigt dir, ob eine Anweisung inkorrekt ist.\ Einige Beispiele findest du hier:

Oder du kannst check below some Smali changes explained.

APK neu kompilieren

Nachdem du den Code geändert hast, kannst du den Code rekompilieren mit:

bash
apktool b . #In the folder generated when you decompiled the application

Es wird die neue APK compile innerhalb des dist Ordners.

Wenn apktool einen error wirft, versuche, die latest version zu installieren

Sign the new APK

Anschließend musst du generate a key (du wirst nach einem password und nach einigen Informationen gefragt, die du beliebig ausfüllen kannst):

bash
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <your-alias>

Zum Schluss das neue APK signieren:

bash
jarsigner -keystore key.jks path/to/dist/* <your-alias>

Neue Anwendung optimieren

zipalign ist ein Tool zur Ausrichtung von Archiven, das wichtige Optimierungen für Android-Anwendungen (APK-Dateien) bereitstellt. Weitere Informationen hier.

bash
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
zipalign -v 4 infile.apk

Signiere die neue APK (nochmals?)

Wenn du lieber apksigner statt jarsigner verwendest, solltest du die APK signieren nachdem du die Optimierung mit zipaling angewendet hast. ABER BEACHTE, DASS DU DIE ANWENDUNG NUR EINMAL DIE ANWENDUNG NUR EINMAL SIGNIEREN MIT jarsigner (vor zipalign) ODER MIT aspsigner (nach zipaling).

bash
apksigner sign --ks key.jks ./dist/mycompiled.apk

Smali ändern

Für den folgenden Hello World Java-Code:

java
public static void printHelloWorld() {
System.out.println("Hello World")
}

Der Smali-Code wäre:

java
.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

Das Smali-Instruktionsset ist hier.

Leichte Änderungen

Initialwerte einer Variable innerhalb einer Funktion ändern

Einige Variablen werden am Anfang der Funktion mit dem Opcode const definiert; du kannst deren Werte ändern oder neue definieren:

bash
#Number
const v9, 0xf4240
const/4 v8, 0x1
#Strings
const-string v5, "wins"

Grundlegende Operationen

bash
#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

Größere Änderungen

Logging

bash
#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>"

Empfehlungen:

  • Wenn du deklarierte Variablen innerhalb der Funktion verwenden willst (deklarierte v0,v1,v2...) setze diese Zeilen zwischen der .local und den Deklarationen der Variablen (const v0, 0x1).
  • Wenn du den Logging-Code in die Mitte des Codes einer Funktion einfügen möchtest:
    • Erhöhe die Anzahl der deklarierten Variablen um 2: z. B. von .locals 10 auf .locals 12.
    • Die neuen Variablen sollten die nächsthöheren Nummern der bereits deklarierten Variablen sein (in diesem Beispiel sollten es v10 und v11 sein, denk daran, dass es bei v0 beginnt).
    • Ändere den Code der Logging-Funktion und verwende v10 und v11 statt v5 und v1.

Toasts

Denk daran, am Anfang der Funktion 3 zur Anzahl der .locals hinzuzufügen.

Dieser Code ist dafür vorbereitet, in die Mitte einer Funktion eingefügt zu werden (ändere die Anzahl der Variablen bei Bedarf). Er nimmt den value of this.o, wandelt ihn in einen String um und zeigt dann einen toast mit dessen Wert an.

bash
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

Laden einer nativen Bibliothek beim Start (System.loadLibrary)

Manchmal müssen Sie eine native Bibliothek vorladen, damit sie sich vor anderen JNI libs initialisiert (z. B. um process-local telemetry/logging zu ermöglichen). Sie können einen Aufruf von System.loadLibrary() in einen statischen Initialisierer oder früh in Application.onCreate() injizieren. Beispiel-smali für einen statischen Klasseninitialisierer ():

smali
.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

Alternativ platzieren Sie dieselben zwei Anweisungen am Anfang Ihrer Application.onCreate(), um sicherzustellen, dass die Bibliothek so früh wie möglich geladen wird:

smali
.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

Hinweise:

  • Stellen Sie sicher, dass die korrekte ABI-Variante der Bibliothek unter lib// (z. B. arm64-v8a/armeabi-v7a) vorhanden ist, um UnsatisfiedLinkError zu vermeiden.
  • Sehr frühes Laden (class static initializer) garantiert, dass der native Logger nachfolgende JNI-Aktivität beobachten kann.

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks