Editing Smali
Bagian ini hanya berisi trik dasar dalam unpacking/packing smali, serta beberapa modifikasi dasar yang sering saya lakukan. Sebaiknya Anda membaca resource berikut ini untuk mengenal lebih banyak mengenai bytecode dalvik:
Pemahaman file smali bisa dibantu dengan decompiler java: bacalah hasil dekompilasi dan bandingkan dengan file smali-nya.
Unpacking dan Packing
Untuk mengedit smali
(bytecode dalvik), langkah-langkahnya adalah dengan mengubah APK menjadi banyak file smali:
apktool d appku.apk
Kadang decoding resource gagal, pastikan bahwa aapt
/aapt.exe
sudah menggunakan versi terbaru dari SDK Android. Jika masih gagal juga, kita bisa mengekstrak file smali tanpa mengekstrak resource:
apktool d -r appku.apk
Setelah selesai, kita akan mendapati banyak file di direktori appku
. Setelah kita mengedit file smali, kita perlu mempack ulang apk tersebut, caranya:
cd appku
apktool b
Hasil file APK akan ada di apktool/dist
. File tersebut belum ditandatangani secara digital dan hanya bisa diinstall di emulator. Untuk menandatangani agar bisa diinstall di device, kita perlu memiliki keystore. Anda bisa mengikuti langkah di situs Android untuk membuat keystore.
Setelah memiliki keystore, kita bisa menandatangani APK (untuk gampangnya, Anda bisa memakai password yang sama untuk keystore, key password):
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore /path/to/my.keystore -storepass mypass -keypass mypass appku.apk mypass
Modifikasi dasar
Modifikasi paling dasar adalah mengubah kondisi dari true
menjadi false
atau sebaliknya. Ini bisa dilakukan dengan mencari kondisi, seperti ini:
if-ge v0, v2, :cond_0
Lalu mengubahnya menjadi kebalikannya. Dari tabel opcode, kita bisa tahu bahwa kebalikan if-ge
adalah if-lt
if-lt v0, v2, :cond_0
Modifikasi lain adalah mengubah sebuah konstanta (misalnya kita ingin mengijinkan teks yang lebih panjang). Contohnya nilai seperti ini:
const/16 v0, 0x10
Bisa diubah menjadi:
const/16 v0, 0x100
Modifikasi yang hampir selalu saya lakukan adalah menambah logging. Jika register v0
tidak dipakai, kita bisa langsung melakukan seperti ini:
const-string v0, "JOEJOEMAP"
invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
Jika ada banyak method yang ingin ditambahi lognya, biasanya saya akan menambahkan method baru ke sebuah kelas:
.method private static logShortString(Ljava/lang/String;)V
.registers 6
const-string v0, "JOEJOEMAP"
invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
return-void
.end method
Lalu di titik di mana saya ingin mendump variabel, saya tambahkan (ganti p1
dengan register yang ingin didump)
invoke-static {p1}, Lcom/xxx/yyy/zzz;->logShortString(Ljava/lang/String;)V
Menulis kode smali
Membuat kode smali seperti logShortString
di atas gampang dilakukan karena sangat singkat. Untuk membuat kode yang lebih panjang, seperti misalnya mendump sebuah Hashtable
, saya memilih menggunakan compiler java.
Pertama, tuliskan kode Java apa adanya, contohnya untuk mengubah list menjadi string (supaya bisa diprint dengan logShortString
di atas):
import java.util.List;
import java.util.Iterator;
class Hello {
private static String listToString(List l) {
if (l==null) {
return "<Empty List>";
}
Iterator iterator = l.iterator();
StringBuilder sb = new StringBuilder();
sb.append("List:[");
while (iterator.hasNext()) {
Object o = iterator.next();
sb.append(o.toString());
sb.append(", ");
}
sb.append("]");
return sb.toString();
}
}
Compile file tersebut dengant target bahasa Java 1.6:
javac -target 1.6 -source 1.6 Hello.java
Ubah menjadi file JAR (zip filenya):
jar cf hello.jar Hello.class
Lalu konversi menjadi APK:
/path/to/android/sdk/build-tools/android-4.4W/dx --dex --output=hello.apk hello.jar
Ganti path android-4.4W
dengan versi build-tools yang Anda miliki
Unpack lagi APK-nya menjadi file smali:
apktool d -f hello.apk
Sekarang kita memiliki kode smalli yang siap disisipkan ke file lain. Kode ini cukup panjang jika harus ditulis manual:
.method private static listToString(Ljava/util/List;)Ljava/lang/String;
.locals 3
.prologue
.line 39
if-nez p0, :cond_0
.line 40
const-string v0, "<Empty List>"
.line 51
:goto_0
return-object v0
.line 42
:cond_0
invoke-interface {p0}, Ljava/util/List;->iterator()Ljava/util/Iterator;
move-result-object v0
.line 43
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
.line 44
const-string v2, "List:["
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
.line 45
:goto_1
invoke-interface {v0}, Ljava/util/Iterator;->hasNext()Z
move-result v2
if-eqz v2, :cond_1
.line 46
invoke-interface {v0}, Ljava/util/Iterator;->next()Ljava/lang/Object;
move-result-object v2
.line 47
invoke-virtual {v2}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
.line 48
const-string v2, ", "
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
goto :goto_1
.line 50
:cond_1
const-string v0, "]"
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
.line 51
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
goto :goto_0
.end method
Copyright © 2009-2018 Yohanes Nugroho