200 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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