Smali - Decompile Etme/[Değiştirme]/Derleme

Reading time: 8 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Bazen uygulama kodunu, sizin için gizli bilgilere erişmek amacıyla (örneğin iyi obfuskelenmiş parolalar veya flag'ler) değiştirmek ilginç olabilir. Bu durumda apk'yı decompile etmek, kodu değiştirmek ve yeniden derlemek faydalı olabilir.

Opcodes reference: http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

Hızlı Yol

Visual Studio Code ve APKLab eklentisini kullanarak, herhangi bir komut çalıştırmadan uygulamayı otomatik olarak decompile edebilir, değiştirebilir, yeniden derleyebilir, imzalayıp yükleyebilirsiniz.

Bu işi çok kolaylaştıran başka bir script ise https://github.com/ax/apk.sh

APK'yı decompile etme

APKTool kullanarak smali koduna ve kaynaklara erişebilirsiniz:

bash
apktool d APP.apk

If apktool gives you any error, deneyin installing the latest version

Some interesting files you should look are:

  • res/values/strings.xml (ve res/values/* içindeki tüm xml dosyaları)
  • AndroidManifest.xml
  • Any file with extension .sqlite or .db

If apktool has problems decoding the application take a look to https://ibotpeaches.github.io/Apktool/documentation/#framework-files or try using the argument -r (Kaynakları çözümleme). Then, if the problem was in a resource and not in the source code, you won't have the problem (you won't also decompile the resources).

Change smali code

Bazı komutları değiştirebilir, bazı değişkenlerin değerini değiştirebilir veya yeni komutlar ekleyebilirsiniz. Smali kodunu VS Code ile değiştiriyorum; ardından smalise extension'ı kurduğunuzda editör herhangi bir talimatın yanlış olup olmadığını söyleyecektir.
Some examples can be found here:

Or you can check below some Smali changes explained.

Recompile the APK

Kodu değiştirdikten sonra şu komutla kodu yeniden derleyebilirsiniz:

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

Yeni APK, dist klasörünün içinde derlenecektir.

Eğer apktool bir hata verirse, en son sürümü yüklemeyi deneyin

Yeni APK'yi İmzala

Sonra, bir anahtar oluşturmanız gerekiyor (parola ve rastgele doldurabileceğiniz bazı bilgiler istenecek):

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

Son olarak, yeni APK'yı imzala:

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

Yeni uygulamayı optimize et

zipalign, Android uygulama (APK) dosyalarına önemli optimizasyon sağlayan bir arşiv hizalama aracıdır. Daha fazla bilgi burada.

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

Yeni APK'yı imzala (tekrar mi?)

Eğer jarsigner yerine apksigner kullanmayı tercih ediyorsanız, zipaling ile yapılan optimizasyonu uyguladıktan sonra APK'yı imzalamalısınız. ANCAK UNUTMAYIN Kİ UYGULAMAYI SADECE BİR KEZ İMZALAMANIZ YETERLİDİR jarsigner ile (zipalign'dan önce) veya aspsigner ile (zipaling'den sonra).

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

Smali'yi Değiştirme

Aşağıdaki Hello World Java kodu için:

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

Smali kodu şöyle olacaktır:

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

The Smali instruction set şu adreste mevcuttur here.

Hafif Değişiklikler

Bir fonksiyon içindeki bir değişkenin başlangıç değerlerini değiştirin

Bazı değişkenler fonksiyonun başında opcode const kullanılarak tanımlanır; değerlerini değiştirebilir veya yeni değişkenler tanımlayabilirsiniz:

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

Temel İşlemler

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

Daha Büyük Değişiklikler

Günlükleme

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

Recommendations:

  • Eğer fonksiyon içinde bildirilen değişkenleri kullanacaksanız (bildirilen v0,v1,v2...) bu satırları .local ile değişkenlerin bildirimleri (const v0, 0x1) arasına koyun.
  • Eğer logging kodunu bir fonksiyonun gövdesinin ortasına koymak istiyorsanız:
  • Bildirilen değişken sayısına 2 ekleyin: Örn: .locals 10 to .locals 12
  • Yeni değişkenler, zaten bildirilen değişkenlerin sonraki numaraları olmalıdır (bu örnekte v10 ve v11 olmalıdır, bunun v0'dan başladığını unutmayın).
  • Logging fonksiyonunun kodunu değiştirin ve v10 ve v11 kullanın, v5 ve v1 yerine.

Toast gösterimi

Fonksiyonun başında .locals sayısına 3 eklemeyi unutmayın.

Bu kod, bir fonksiyonun ortasına yerleştirilecek şekilde hazırlanmıştır (gerektiğinde değişken sayısını değiştirin). Bu kod this.o değerini alacak, onu String'e dönüştürecek ve ardından değeriyle bir toast gösterecektir.

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

Başlangıçta Yerel Bir Kütüphaneyi Yükleme (System.loadLibrary)

Bazen, diğer JNI kütüphanelerinden önce başlatılması için bir yerel kütüphaneyi önceden yüklemeniz gerekir (ör. process-local telemetri/kayıt etkinleştirmek için). System.loadLibrary() çağrısını bir static initializer içinde veya Application.onCreate() içinde erken bir aşamada enjekte edebilirsiniz. Statik sınıf başlatıcısı () için örnek smali:

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

Alternatif olarak, kütüphanenin mümkün olduğunca erken yüklenmesini sağlamak için aynı iki talimatı Application.onCreate()'in başına yerleştirin:

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

Notlar:

  • Kütüphanenin doğru ABI varyantının lib// altında (örn. arm64-v8a/armeabi-v7a) bulunduğundan emin olun; UnsatisfiedLinkError hatasını önlemek için.
  • Çok erken yükleme (class static initializer), native logger'ın sonraki JNI aktivitelerini gözlemleyebilmesini garanti eder.

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin