mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
200 lines
11 KiB
Markdown
200 lines
11 KiB
Markdown
# Smali - Decompiling/[Modifying]/Compiling
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
|
||
Іноді буває корисно змінити код додатку, щоб отримати приховану інформацію для себе (можливо добре обфусковані паролі або flags). Тоді може бути цікаво decompile the apk, modify the code і recompile його.
|
||
|
||
**Opcodes reference:** [http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html](http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html)
|
||
|
||
## Швидкий спосіб
|
||
|
||
Використовуючи Visual Studio Code та розширення APKLab, ви можете автоматично decompile, modify, recompile, sign & install додаток без виконання жодної команди.
|
||
|
||
Ще один скрипт, який значно полегшує це завдання — [**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)
|
||
|
||
## Decompile the APK
|
||
|
||
Використовуючи APKTool, ви можете отримати доступ до smali code and resources:
|
||
```bash
|
||
apktool d APP.apk
|
||
```
|
||
If **apktool** дає будь‑яку помилку, спробуйте [встановити **останній версії**](https://ibotpeaches.github.io/Apktool/install/)
|
||
|
||
Деякі **цікаві файли, які варто переглянути**,:
|
||
|
||
- _res/values/strings.xml_ (and all xmls inside res/values/*)
|
||
- _AndroidManifest.xml_
|
||
- Any file with extension _.sqlite_ or _.db_
|
||
|
||
Якщо `apktool` має **проблеми з декодуванням додатка**, перегляньте [https://ibotpeaches.github.io/Apktool/documentation/#framework-files](https://ibotpeaches.github.io/Apktool/documentation/#framework-files) або спробуйте використати аргумент **`-r`** (Do not decode resources). Тоді, якщо проблема була в ресурсі, а не в коді, ви уникаєте цієї проблеми (також ви не декомпілюєте ресурси).
|
||
|
||
## Змінити smali код
|
||
|
||
Ви можете **змінювати** **instructions**, змінювати **value** деяких змінних або **додавати** нові інструкції. Я змінюю Smali код за допомогою [**VS Code**](https://code.visualstudio.com), потім встановіть розширення **smalise**, і редактор скаже вам, якщо якась **instruction некоректна**.
|
||
Деякі **приклади** можна знайти тут:
|
||
|
||
- [Smali changes examples](smali-changes.md)
|
||
- [Google CTF 2018 - Shall We Play a Game?](google-ctf-2018-shall-we-play-a-game.md)
|
||
|
||
Або можна [**check below some Smali changes explained**](smali-changes.md#modifying-smali).
|
||
|
||
## Перекомпілювати APK
|
||
|
||
Після внесення змін у код ви можете **перекомпілювати** код, використовуючи:
|
||
```bash
|
||
apktool b . #In the folder generated when you decompiled the application
|
||
```
|
||
Він **скомпілює** новий APK **всередині** папки _**dist**_.
|
||
|
||
Якщо **apktool** викидає **помилку**, спробуйте[ installing the **latest version**](https://ibotpeaches.github.io/Apktool/install/)
|
||
|
||
### **Підпишіть новий APK**
|
||
|
||
Потім потрібно **згенерувати ключ** (вам буде запропоновано ввести пароль та деяку інформацію, яку можна заповнити випадковими даними):
|
||
```bash
|
||
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <your-alias>
|
||
```
|
||
Нарешті, **підпишіть** новий APK:
|
||
```bash
|
||
jarsigner -keystore key.jks path/to/dist/* <your-alias>
|
||
```
|
||
### Оптимізувати новий додаток
|
||
|
||
**zipalign** — це інструмент вирівнювання архівів, який забезпечує важливу оптимізацію файлів Android-додатків (APK). [More information here](https://developer.android.com/studio/command-line/zipalign).
|
||
```bash
|
||
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
|
||
zipalign -v 4 infile.apk
|
||
```
|
||
### **Підпишіть новий APK (знову?)**
|
||
|
||
Якщо ви **вважаєте за краще** використовувати [**apksigner**](https://developer.android.com/studio/command-line/) замість jarsigner, **ви повинні підписати apk** після застосування **оптимізації за допомогою** zipaling. Але зауважте, що вам потрібно **підписати додаток лише один раз** за допомогою jarsigner (до zipalign) або за допомогою aspsigner (після zipaling).
|
||
```bash
|
||
apksigner sign --ks key.jks ./dist/mycompiled.apk
|
||
```
|
||
## Модифікація Smali
|
||
|
||
Для наступного коду Hello World на Java:
|
||
```java
|
||
public static void printHelloWorld() {
|
||
System.out.println("Hello World")
|
||
}
|
||
```
|
||
Код Smali буде:
|
||
```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
|
||
```
|
||
Набір інструкцій Smali доступний [here](https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions).
|
||
|
||
### Незначні зміни
|
||
|
||
### Змінити початкові значення змінної всередині функції
|
||
|
||
Деякі змінні визначені на початку функції за допомогою опкоду _const_; ви можете змінити їхні значення або додати нові:
|
||
```bash
|
||
#Number
|
||
const v9, 0xf4240
|
||
const/4 v8, 0x1
|
||
#Strings
|
||
const-string v5, "wins"
|
||
```
|
||
### Основні операції
|
||
```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
|
||
```
|
||
### Великі зміни
|
||
|
||
### Логування
|
||
```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:
|
||
|
||
- Якщо ви збираєтесь використовувати оголошені змінні всередині функції (declared v0,v1,v2...) помістіть ці рядки між _.local <number>_ і деклараціями змінних (_const v0, 0x1_)
|
||
- Якщо ви хочете вставити код логування посеред коду функції:
|
||
- Додайте 2 до кількості оголошених змінних: Ex: from _.locals 10_ to _.locals 12_
|
||
- Нові змінні повинні бути наступними номерами після вже оголошених змінних (в цьому прикладі це повинні бути _v10_ та _v11_, remember that it starts in v0).
|
||
- Змініть код функції логування та використовуйте _v10_ і _v11_ замість _v5_ і _v1_.
|
||
|
||
### Відображення Toast
|
||
|
||
Пам'ятайте додати 3 до числа _.locals_ на початку функції.
|
||
|
||
This code is prepared to be inserted in the **середину функції** (**змініть** число **змінних** за потреби). It will take the **значення this.o**, **перетворить** його на **String** and them **зробить** a **toast** with its value.
|
||
```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
|
||
```
|
||
### Loading a Native Library at Startup (System.loadLibrary)
|
||
|
||
Іноді потрібно попередньо завантажити нативну бібліотеку, щоб вона ініціалізувалася перед іншими JNI libs (наприклад, щоб увімкнути локальну для процесу телеметрію/логування). Ви можете інжектувати виклик System.loadLibrary() у статичний ініціалізатор або на ранньому етапі Application.onCreate(). Приклад smali для статичного ініціалізатора класу (<clinit>):
|
||
```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
|
||
```
|
||
Або розмістіть ті самі дві інструкції на початку вашого Application.onCreate(), щоб гарантувати, що бібліотека завантажується якомога раніше:
|
||
```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
|
||
```
|
||
Примітки:
|
||
- Переконайтеся, що правильний варіант ABI бібліотеки існує в lib/<abi>/ (наприклад, arm64-v8a/armeabi-v7a), щоб уникнути UnsatisfiedLinkError.
|
||
- Завантаження дуже рано (class static initializer) гарантує, що native logger може спостерігати подальшу активність JNI.
|
||
|
||
## Посилання
|
||
|
||
- SoTap: Легкий in-app JNI (.so) behavior logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|