Smali - Decompiling/[Modifying]/Compiling

Dowiedz się, jak hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Czasami interesujące jest zmodyfikowanie kodu aplikacji, aby uzyskać dostęp do ukrytych informacji (może to być dobrze zaszyfrowane hasła lub flagi). W takim przypadku warto zdekompilować plik apk, zmodyfikować kod i ponownie go skompilować.

Odwołanie do instrukcji: http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

Szybki sposób

Korzystając z Visual Studio Code i rozszerzenia APKLab, można automatycznie dekompilować, modyfikować, rekompilować, podpisać i zainstalować aplikację bez wykonywania żadnych poleceń.

Innym skryptem, który bardzo ułatwia to zadanie, jest https://github.com/ax/apk.sh

Dekompilacja APK

Korzystając z APKTool, można uzyskać dostęp do kodu smali i zasobów:

apktool d APP.apk

Jeśli apktool wyświetla jakikolwiek błąd, spróbuj zainstalować najnowszą wersję.

Niektóre interesujące pliki, na które powinieneś zwrócić uwagę, to:

  • res/values/strings.xml (oraz wszystkie xml-e wewnątrz res/values/*)

  • AndroidManifest.xml

  • Dowolny plik z rozszerzeniem .sqlite lub .db

Jeśli apktool ma problemy z dekodowaniem aplikacji, zajrzyj na stronę https://ibotpeaches.github.io/Apktool/documentation/#framework-files lub spróbuj użyć argumentu -r (Nie dekoduj zasobów). Wtedy, jeśli problem występował w zasobie, a nie w kodzie źródłowym, nie będziesz mieć tego problemu (nie zdekodujesz również zasobów).

Zmiana kodu smali

Możesz zmieniać instrukcje, zmieniać wartość niektórych zmiennych lub dodawać nowe instrukcje. Ja zmieniam kod Smali za pomocą VS Code, następnie instalujesz rozszerzenie smalise i edytor powie Ci, czy któraś instrukcja jest niepoprawna. Kilka przykładów można znaleźć tutaj:

Możesz również sprawdzić poniżej wyjaśnienia niektórych zmian w Smali.

Ponowne skompilowanie APK

Po zmodyfikowaniu kodu możesz ponownie skompilować kod za pomocą:

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

Skompiluje nowy plik APK wewnątrz folderu dist.

Jeśli apktool wygeneruje błąd, spróbuj zainstalować najnowszą wersję.

Podpisz nowy plik APK

Następnie musisz wygenerować klucz (zostaniesz poproszony o hasło i pewne informacje, które możesz wypełnić losowo):

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

W końcu, podpisz nowy plik APK:

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

Optymalizacja nowej aplikacji

zipalign to narzędzie do wyrównywania archiwów, które zapewnia ważne optymalizacje plików aplikacji Android (APK). Więcej informacji tutaj.

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

Podpisz nowy APK (ponownie?)

Jeśli wolisz używać apksigner zamiast jarsigner, powinieneś podpisać apk po zastosowaniu optymalizacji za pomocą zipalign. ALE ZWRÓĆ UWAGĘ, ŻE MUSISZ PODPISAĆ APLIKACJĘ TYLKO RAZ Z jarsigner (przed zipalign) LUB Z aspsigner (po zipalign).

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

Modyfikowanie Smali

Dla następującego kodu Hello World w języku Java:

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

Kod Smali będzie wyglądał następująco:

.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

Zestaw instrukcji Smali jest dostępny tutaj.

Lekkie zmiany

Modyfikowanie początkowych wartości zmiennej wewnątrz funkcji

Niektóre zmienne są definiowane na początku funkcji za pomocą opcode'u const, możesz zmieniać ich wartości lub definiować nowe:

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

Podstawowe operacje

Tworzenie nowej klasy

Aby utworzyć nową klasę w pliku Smali, należy utworzyć nowy plik o rozszerzeniu .smali i umieścić go w odpowiednim katalogu zgodnie z hierarchią pakietów. Następnie należy zdefiniować nazwę klasy, używając dyrektywy .class i określić dziedziczenie, jeśli jest to konieczne, za pomocą dyrektywy .super.

Przykład:

.class public Lcom/example/MyClass;
.super Ljava/lang/Object;

Dodawanie pól

Aby dodać pole do klasy, należy użyć dyrektywy .field i określić modyfikatory dostępu, typ pola oraz jego nazwę.

Przykład:

.field private static myField:I

Dodawanie metod

Aby dodać metodę do klasy, należy użyć dyrektywy .method i określić modyfikatory dostępu, typ zwracany, nazwę metody oraz listę argumentów. Następnie należy zdefiniować ciało metody, używając instrukcji Smali.

Przykład:

.method public static myMethod(II)I
    .registers 3
    add-int v0, p0, p1
    return v0
.end method

Dodawanie instrukcji

Aby dodać instrukcję do metody, należy użyć odpowiedniej instrukcji Smali, takiej jak move, add-int, invoke-static, itp. Instrukcje Smali są podobne do instrukcji Javy, ale mają nieco inną składnię.

Przykład:

add-int v0, p0, p1

Modyfikowanie istniejących instrukcji

Aby zmodyfikować istniejącą instrukcję w metodzie, należy znaleźć odpowiednią instrukcję w pliku Smali i zmienić jej argumenty lub operacje. Można to zrobić, edytując plik Smali ręcznie lub za pomocą narzędzi do automatycznego modyfikowania plików Smali.

Przykład:

invoke-static {p0}, Landroid/util/Log;->d(Ljava/lang/String;)I

Usuwanie instrukcji

Aby usunąć instrukcję z metody, należy znaleźć odpowiednią instrukcję w pliku Smali i usunąć ją. Można to zrobić, edytując plik Smali ręcznie lub za pomocą narzędzi do automatycznego modyfikowania plików Smali.

Przykład:

return-void

Dodawanie adnotacji

Aby dodać adnotację do klasy, pola lub metody, należy użyć dyrektywy .annotation i określić typ adnotacji oraz jej parametry.

Przykład:

.annotation system Ldalvik/annotation/EnclosingClass;
    value = Lcom/example/MyClass;
.end annotation
#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

Większe zmiany

Rejestrowanie działań

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

Rekomendacje:

  • Jeśli zamierzasz używać zadeklarowanych zmiennych wewnątrz funkcji (zadeklarowane v0,v1,v2...), umieść te linie między .local <number> a deklaracjami zmiennych (const v0, 0x1)

  • Jeśli chcesz umieścić kod logowania w środku kodu funkcji:

  • Dodaj 2 do liczby zadeklarowanych zmiennych: np. z .locals 10 na .locals 12

  • Nowe zmienne powinny mieć kolejne numery po już zadeklarowanych zmiennych (w tym przykładzie powinny to być v10 i v11, pamiętaj, że zaczynamy od v0).

  • Zmień kod funkcji logowania i użyj v10 i v11 zamiast v5 i v1.

Toastowanie

Pamiętaj, aby dodać 3 do liczby .locals na początku funkcji.

Ten kod jest przygotowany do wstawienia w środku funkcji (zmień liczbę zmiennych według potrzeb). Będzie on pobierał wartość this.o, przekształcał ją na String i następnie wyświetlał tost z jej wartością.

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
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated