Simplify mengeksekusi aplikasi secara virtual untuk memahami perilakunya, lalu mencoba mengoptimalkan kode agar berperilaku sama tetapi lebih mudah dipahami oleh manusia. Setiap jenis pengoptimalan bersifat sederhana dan umum, jadi tidak masalah jenis kebingungan spesifik apa yang digunakan.
Kode di sebelah kiri adalah dekompilasi aplikasi yang dikaburkan, dan kode di sebelah kanan telah di-deobfuscated.
Ada tiga bagian dalam proyek ini: smalivm, penyederhanaan, dan aplikasi demo.
if
atau switch
apa pun dengan nilai yang tidak diketahui akan mengakibatkan kedua cabang diambil. usage: java -jar simplify.jar <input> [options]
deobfuscates a dalvik executable
-et,--exclude-types <pattern> Exclude classes and methods which include REGEX, eg: "com/android", applied after include-types
-h,--help Display this message
-ie,--ignore-errors Ignore errors while executing and optimizing methods. This may lead to unexpected behavior.
--include-support Attempt to execute and optimize classes in Android support library packages, default: false
-it,--include-types <pattern> Limit execution to classes and methods which include REGEX, eg: ";->targetMethod("
--max-address-visits <N> Give up executing a method after visiting the same address N times, limits loops, default: 10000
--max-call-depth <N> Do not call methods after reaching a call depth of N, limits recursion and long method chains, default: 50
--max-execution-time <N> Give up executing a method after N seconds, default: 300
--max-method-visits <N> Give up executing a method after executing N instructions in that method, default: 1000000
--max-passes <N> Do not run optimizers on a method more than N times, default: 100
-o,--output <file> Output simplified input to FILE
--output-api-level <LEVEL> Set output DEX API compatibility to LEVEL, default: 15
-q,--quiet Be quiet
--remove-weak Remove code even if there are weak side effects, default: true
-v,--verbose <LEVEL> Set verbosity to LEVEL, default: 0
Bangunan memerlukan Java Development Kit 8 (JDK) untuk diinstal.
Karena proyek ini berisi submodul untuk kerangka Android, kloning dengan --recursive
:
git clone --recursive https://github.com/CalebFenton/simplify.git
Atau perbarui submodul kapan saja dengan:
git submodule update --init --recursive
Kemudian, untuk membuat satu toples yang berisi semua dependensi:
./gradlew fatjar
Jar Simplify akan berada di simplify/build/libs/
. Anda dapat menguji kerjanya dengan menyederhanakan contoh aplikasi yang dikaburkan. Begini cara Anda menjalankannya (Anda mungkin perlu mengubah simplify.jar
):
java -jar simplify/build/libs/simplify.jar -it " org/cf/obfuscated " -et " MainActivity " simplify/obfuscated-app.apk
Untuk memahami apa yang di-deobfuscated, lihat README Aplikasi yang Dikaburkan.
Jika Simplify gagal, coba rekomendasi berikut secara berurutan:
-it
.--max-address-visits
, --max-call-depth
, dan --max-method-visits
yang lebih tinggi.-v
atau -v 2
dan laporkan masalah dengan log dan hash DEX atau APK.Jika pembangunan di Windows, dan pembangunan gagal dengan kesalahan yang mirip dengan:
Tidak dapat menemukan tools.jar. Harap periksa apakah C:Program FilesJavajre1.8.0_151 berisi instalasi JDK yang valid.
Ini berarti Gradle tidak dapat menemukan jalur JDK yang tepat. Pastikan JDK diinstal, atur variabel lingkungan JAVA_HOME
ke jalur JDK Anda, dan pastikan untuk menutup dan membuka kembali command prompt yang Anda gunakan untuk membangun.
Jangan malu. Menurut saya eksekusi virtual dan deobfuscation adalah masalah yang menarik. Siapapun yang berminat otomatis keren dan dipersilahkan memberikan kontribusi, meskipun hanya untuk memperbaiki kesalahan ketik. Jangan ragu untuk mengajukan pertanyaan dalam masalah ini dan mengirimkan permintaan penarikan.
Harap sertakan tautan ke APK atau DEX dan perintah lengkap yang Anda gunakan. Hal ini mempermudah untuk mereproduksi (dan dengan demikian memperbaiki ) masalah Anda.
Jika Anda tidak dapat membagikan sampel, harap sertakan hash file (SHA1, SHA256, dll).
Jika suatu operasi menempatkan nilai bertipe yang dapat diubah menjadi konstanta seperti string, angka, atau boolean, pengoptimalan ini akan menggantikan operasi tersebut dengan konstanta. Misalnya:
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
# Decrypts to: "Tell me of your homeworld, Usul."
move-result v0
Dalam contoh ini, string terenkripsi didekripsi dan ditempatkan ke dalam v0
. Karena string "dapat diubah", move-result v0
dapat diganti dengan const-string
:
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."
Kode mati jika menghapusnya tidak mungkin mengubah perilaku aplikasi. Kasus yang paling jelas adalah jika kode tidak dapat dijangkau, misalnya if (false) { // dead }
). Jika kode dapat dijangkau, kode tersebut dapat dianggap mati jika tidak mempengaruhi keadaan apa pun di luar metode, yaitu tidak memiliki efek samping . Misalnya, kode tidak boleh memengaruhi nilai kembalian metode, mengubah variabel kelas apa pun, atau menjalankan IO apa pun. Ini sulit ditentukan dalam analisis statis. Untungnya, smalivm tidak harus pintar. Ia hanya dengan bodohnya mengeksekusi semua yang ia bisa dan menganggap ada efek samping jika tidak bisa memastikan. Perhatikan contoh dari Propagasi Konstan:
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."
Dalam kode ini, invoke-static
tidak lagi mempengaruhi nilai kembalian metode dan anggap saja metode tersebut tidak melakukan hal aneh seperti menulis byte ke sistem file atau soket jaringan sehingga tidak memiliki efek samping. Itu bisa dihilangkan begitu saja.
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
const-string v0, "Tell me of your homeworld, Usul."
Terakhir, const-string
pertama memberikan nilai pada register, namun nilai tersebut tidak pernah digunakan, artinya penugasan sudah mati. Itu juga bisa dihilangkan.
const-string v0, "Tell me of your homeworld, Usul."
Sabas!
Salah satu tantangan utama dalam analisis statis Java adalah refleksi. Tidak mungkin mengetahui argumen untuk metode refleksi tanpa melakukan analisis aliran data yang cermat. Ada cara cerdas dan cerdas untuk melakukan hal ini, tetapi smalivm melakukannya hanya dengan mengeksekusi kode. Ketika menemukan pemanggilan metode yang tercermin seperti:
invoke-virtual {v0, v1, v2}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
Ia dapat mengetahui nilai v0
, v1
, dan v2
. Jika yakin dengan nilainya, ia dapat mengganti panggilan ke Method.invoke()
dengan pemanggilan metode sebenarnya yang tidak direfleksikan. Hal yang sama berlaku untuk pencarian bidang dan kelas yang direfleksikan.
Untuk segala sesuatu yang tidak sesuai dengan kategori tertentu, ada optimasi lubang intip. Ini termasuk menghapus operasi check-cast
yang tidak berguna, mengganti panggilan Ljava/lang/String;-><init>
dengan const-string
, dan seterusnya.
.method public static test1 () I
.locals 2
new-instance v0 , L java/lang/Integer ;
const/4 v1 , 0x1
invoke-direct { v0 , v1 }, L java/lang/Integer ; -> <init> ( I ) V
invoke-virtual { v0 }, L java/lang/Integer ; -> intValue () I
move-result v0
return v0
.end method
Yang dilakukan hanyalah v0 = 1
.
.method public static test1 () I
.locals 2
new-instance v0 , L java/lang/Integer ;
const/4 v1 , 0x1
invoke-direct { v0 , v1 }, L java/lang/Integer ; -> <init> ( I ) V
invoke-virtual { v0 }, L java/lang/Integer ; -> intValue () I
const/4 v0 , 0x1
return v0
.end method
move-result v0
diganti dengan const/4 v0, 0x1
. Hal ini karena hanya ada satu kemungkinan nilai kembalian untuk intValue()I
dan tipe kembalian dapat dibuat konstan. Argumen v0
dan v1
tidak ambigu dan tidak berubah. Artinya, ada konsensus nilai untuk setiap kemungkinan jalur eksekusi di intValue()I
. Jenis nilai lain yang dapat diubah menjadi konstanta:
const/4
, const/16
, dll.const-string
const-class
.method public static test1 () I
.locals 2
const/4 v0 , 0x1
return v0
.end method
Karena kode di atas const/4 v0, 0x1
tidak mempengaruhi keadaan di luar metode (tidak ada efek samping), maka dapat dihapus tanpa mengubah perilaku. Jika ada pemanggilan metode yang menulis sesuatu ke sistem file atau jaringan, hal itu tidak dapat dihapus karena mempengaruhi keadaan di luar metode. Atau jika test()I
mengambil argumen yang bisa berubah, seperti LinkedList
, instruksi apa pun yang mengaksesnya tidak dapat dianggap mati.
Contoh lain dari kode mati:
if (false) { dead_code(); }
Alat ini tersedia dalam dua lisensi: lisensi komersial yang cocok untuk proyek sumber tertutup dan lisensi GPL yang dapat digunakan dalam perangkat lunak sumber terbuka.
Tergantung pada kebutuhan Anda, Anda harus memilih salah satunya dan mengikuti kebijakannya. Detail kebijakan dan perjanjian untuk setiap jenis lisensi tersedia di file LICENSE.COMMERCIAL dan LICENSE.GPL.