# SMALI

![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-8c5d6ef24ae54759175052b237351dccf0432770%2Fmapt.png?alt=media)

**Smali** is the assembly language used to represent Android's DEX bytecode. This guide organizes the most important instructions and concepts into a comprehensive and easy-to-understand format, providing clarity on the various components of Smali code.

## Smali File Structure

![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-9154a30deedd98d6ca02a7a40b57015bf04a08a9%2Fsmali_structure.png?alt=media)

## Data types

| **Syntax** | **Meaning**                                           |
| ---------- | ----------------------------------------------------- |
| `V`        | Void                                                  |
| `Z`        | Boolean                                               |
| `B`        | Byte                                                  |
| `S`        | Short                                                 |
| `C`        | Char                                                  |
| `F`        | Float                                                 |
| `I`        | Int                                                   |
| `J`        | Long (64-bit)                                         |
| `D`        | Double (64-bit)                                       |
| `\[`       | Array (e.g., `[B` → `byte[]`)                         |
| `L`        | Fully qualified class name (e.g. `Ljava/lang/Object`) |

## Annotations

| **Purpose**                                      | **Java code**                                                            | **Smali equivalent**                                                                                                                                                        |
| ------------------------------------------------ | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Inner / member classes**                       | *(implicit, compiler adds when you declare inner classes)*               | `smali .annotation system Ldalvik/annotation/MemberClasses; value = { Lcom/example/Outer$Inner;, Lcom/example/Outer$Nested; } .end annotation`                              |
| **Enclosing class**                              | *(added automatically for inner classes)*                                | `smali .annotation system Ldalvik/annotation/EnclosingClass; value = Lcom/example/Outer; .end annotation`                                                                   |
| **Enclosing method**                             | *(added for anonymous/local classes inside a method)*                    | `smali .annotation system Ldalvik/annotation/EnclosingMethod; value = Lcom/example/Outer;->myMethod()V .end annotation`                                                     |
| **Generics (Signature)**                         | `java class MyClass<T> { }`                                              | `smali .annotation system Ldalvik/annotation/Signature; value = { "<T:", "Ljava/lang/Object;", ">","Ljava/lang/Object;" } .end annotation`                                  |
| **Throws (declared exceptions)**                 | `java void read() throws IOException, InterruptedException;`             | `smali .annotation system Ldalvik/annotation/Throws; value = { Ljava/io/IOException;, Ljava/lang/InterruptedException; } .end annotation`                                   |
| **Annotation default (in annotation interface)** | `java @interface MyAnnotation { String value() default "defaultText"; }` | `smali .annotation system Ldalvik/annotation/AnnotationDefault; value = .subannotation Lcom/example/MyAnnotation; value = "defaultText" .end subannotation .end annotation` |
| **Deprecated (runtime)**                         | `java @Deprecated class OldClass { }`                                    | `smali .annotation runtime Ljava/lang/Deprecated; .end annotation`                                                                                                          |
| **Nullable (runtime)**                           | `java @Nullable String name;`                                            | `smali .annotation runtime Landroidx/annotation/Nullable; .end annotation`                                                                                                  |
| **SerializedName (runtime)**                     | `java @SerializedName("user_name") String userName;`                     | `smali .annotation runtime Lcom/google/gson/annotations/SerializedName; value = "user_name" .end annotation`                                                                |
| **SuppressLint (build)**                         | `java @SuppressLint({"NewApi","Recycle"}) void foo() { }`                | `smali .annotation build Landroid/annotation/SuppressLint; value = { "NewApi", "Recycle" } .end annotation`                                                                 |
| **Custom annotation**                            | `java @MyCustomAnnotation("Hello") class MyClass {}`                     | `smali .annotation runtime Lcom/example/MyCustomAnnotation; value = "Hello" .end annotation`                                                                                |

## Registers

In Dalvik, the registers are 32 bits long for any type of data. For 64-bit data types, (e.g. `long`,`double`), two registers are used.

* **Local registers (`vx`)**: local variables and temporary values (some registers are used for internal operations by the decompiler)
* **Parameter registers (`px`)**: Used for passing parameters in functions (`P0` typically representing the `this` operator)

| Keyword      | Description                                                                                               |
| ------------ | --------------------------------------------------------------------------------------------------------- |
| `.locals`    | number of local registers                                                                                 |
| `.registers` | total number of registers (if virtual method, there is also a register for the implicit parameter `this`) |

<table><thead><tr><th>Method Type</th><th>Java</th><th>Smali (.locals)</th><th>Smali (.registers)</th></tr></thead><tbody><tr><td>Static</td><td><pre class="language-java"><code class="lang-java">public static int addInteger2(int num1, int num2) {
    int res = num1 + num2;
    return res;
}
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">
.method public static addInteger(II)I
    .locals 1
    .param p0, "num1"   # I
    .param p1, "num2"   # I
    .line 13
    add-int v0, p0, p1
    .line 14
    .local v0, "res":I
    return v0
.end method
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">.method public static addInteger(II)I
    .registers 3
    .param p0, "num1"   # I
    .param p1, "num2"   # I
    .line 13
    add-int v0, p0, p1
    .line 14
    .local v0, "res":I
    return v0
.end method
</code></pre></td></tr><tr><td>Virtual</td><td><pre class="language-java"><code class="lang-java">public int addInteger(int num1, int num2) {
    int res = num1 + num2;
    return res;
}
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">.method public addInteger(II)I
    .locals 1
    .param p1, "num1"   # I
    .param p2, "num2"   # I
    .line 7
    add-int v0, p1, p2
    .line 8
    .local v0, "res":I
    return v0
.end method
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">.method public addInteger(II)I
    .registers 4
    .param p1, "num1"   # I
    .param p2, "num2"   # I
    .line 7
    add-int v0, p1, p2
    .line 8
    .local v0, "res":I
    return v0
.end method
</code></pre></td></tr></tbody></table>

## Initialization and return

| **Command**                 | **Description**                                                                                                                                                                                                                                         | **Example (Java/Smali)**                                                                                                                               |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `move vx,vy`                | Moves the content of vy into vx.                                                                                                                                                                                                                        | <p><code>int a = 12;</code><br><code>mov v0, 0xc</code></p>                                                                                            |
| `const/4 vx,lit4`           | <p>Puts the 4-bit constant into <code>vx</code><br><em>Alternatives:</em></p><ul><li><code>const vx, value</code>: values higher than 7</li><li><code>const/16</code>: 16-bit constant</li><li><code>const/high16</code>:high 16-bit constant</li></ul> | <p><code>int level = 3;</code><br><code>const/4 v0, 0x5</code></p>                                                                                     |
| `new-array vx,vy,type_id`   | Generates a new array of `type_id` type and `vy` element size, then stores the reference in `vx`.                                                                                                                                                       | <p><code>byte\[] bArr = {0, 1, 2, 3, 4};</code><br><code>const/4 v0, 0x5</code><br><code>new-array v0, v0, \[B</code></p>                              |
| `const vx, lit32`           | Puts a 32-bit integer constant into `vx`.                                                                                                                                                                                                               | <p><code>int level = 10000;</code><br><code>const vx, 0x2710</code></p>                                                                                |
| `const-string vx,string_id` | Puts a reference to a string constant identified by `string_id` into `vx`.                                                                                                                                                                              | <p><code>String name = "Player";</code><br><code>const-string v5, "Player"</code></p>                                                                  |
| `iget vx, vy, field_id`     | Reads an instance field into `vx`, where the instance is referenced by `vy`.                                                                                                                                                                            | <p><code>return this.highScore;</code><br><code>iget v0, p0, Lde/fgerbig/spacepeng/services/Profile;->highScore:I</code><br><code>return v0</code></p> |
| `iput vx,vy, field_id`      | Puts `vx` into an instance field, where the instance is referenced by `vy`.                                                                                                                                                                             | <p><code>this.lastPlayedLevel = lastPlayedLevel2;</code><br><code>iput p1, p0, Lde/fgerbig/spacepeng/services/Profile;->lastPlayedLevel:I</code></p>   |

## **Arrays**

In Smali, arrays are handled with the `new-array` instruction, which creates an array and stores it in a register. Elements are accessed via the `aget` and `aput` instructions.

**Example**:

<table data-header-hidden><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><pre class="language-java"><code class="lang-java">int[] numbers = new int[]{10, 20};
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">.locals 3 ; We assume the method has at least 3 local registers: v0, v1, v2
.line 10
# 1. Load the array size (2) into register v1
const/4 v1, 0x2
# 2. Create a new 'int' array ([I) of size 2 and save it to v0
new-array v0, v1, [I
.line 11
# 3. Insert value 10 at index 0
const/16 v2, 0xa  # Load 10 (0xa in hexadecimal) into register v2
const/4 v1, 0x0   # Load index 0 into register v1
aput v2, v0, v1   # Assign content of v2 (10) to array v0 at index v1 (0)
.line 12
# 4. Insert value 20 at index 1
const/16 v2, 0x14  # Load 20 (0x14 in hexadecimal) into register v2
const/4 v1, 0x1   # Load index 1 into register v1
aput v2, v0, v1   # Assign content of v2 (20) to array v0 at index v1 (1)
</code></pre></td></tr></tbody></table>

## Arithmetic and binary operators

| **Operation**      | **Description**   | **Java example**       | **Smali example**           |
| ------------------ | ----------------- | ---------------------- | --------------------------- |
| `add-int vx,vy,vz` | `vy + vz` → `vx`  | `value = value + 1;`   | `add-int/lit8 v5, v5, 0x1`  |
| `sub-int vx,vy,vz` | `vy - vz` → `vx`  | `value = value - 1;`   | `sub-int/lit8 v5, v5, 0x1`  |
| `mul-int vx,vy,vz` | `vy * vz` → `vx`  | `value = value * 50;`  | `mul-int/lit8 v6, v1, 0x32` |
| `div-int vx,vy,vz` | `vy / vz` → `vx`  | `value = value / 2;`   | `div-int v4, v1, 0x2`       |
| `rem-int vx,vy,vz` | `vy % vz` → `vx`  | `Math.abs(step2 % 4);` | `rem-int/lit8 v0, p1, 0x4`  |
| `and-int vx,vy,vz` | `vy & vz` → `vx`  | `int value = b & 127;` | `and-int/lit8 v1, p3, 0x1f` |
| `or-int vx,vy,vz`  | `vy \| vz` → `vx` | `int result = a \| b;` | `xor-int v1, v2, v3`        |
| `xor-int vx,vy,vz` | `vy ^ vz` → `vx`  | `int result = a ^ b;`  | `xor-int v1, v2, v3`        |

## Flow operations

### Comparison

| **Syntax**             | **Description**                 |
| ---------------------- | ------------------------------- |
| `if-eqz vx, target`    | Jumps to `target` if `vx == 0`  |
| `if-nez vx, target`    | Jumps to `target` if `vx != 0`  |
| `if-ltz vx, target`    | Jumps to `target` if `vx < 0`   |
| `if-gez vx, target`    | Jumps to `target` if `vx >= 0`  |
| `if-gtz vx, target`    | Jumps to `target` if `vx > 0`   |
| `if-lez vx, target`    | Jumps to `target` if `vx <= 0`  |
| `if-eq vx, vy, target` | Jumps to `target` if `vx == vy` |
| `if-ne vx, vy, target` | Jumps to `target` if `vx != vy` |
| `if-lt vx, vy, target` | Jumps to `target` if `vx < vy`  |
| `if-ge vx, vy, target` | Jumps to `target` if `vx >= vy` |
| `if-gt vx, vy, target` | Jumps to `target` if `vx > vy`  |
| `if-le vx, vy, target` | Jumps to `target` if `vx <= vy` |

### GOTO

| **Command**      | **Description**                                                        | **Smali example**  |
| ---------------- | ---------------------------------------------------------------------- | ------------------ |
| `goto :label`    | Unconditionally jumps to the specified label in the code.              | `goto :label_1`    |
| `goto/16 :label` | Unconditionally jumps to a label, used when the target is far in code. | `goto/16 :label_2` |
| `goto/32 :label` | Unconditionally jumps to a label for even farther targets.             | `goto/32 :label_3` |

## Methods

| **Command**                                   | **Description**                                                                      | **Java example**                                          | **Java example**                                                                            |
| --------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `invoke-virtual {parameters}, methodtocall`   | Invokes a virtual method with parameters                                             | `this.ds.increaseScore(value)`                            | `invoke-virtual {v5, v6}, Lde/fgerbig/spacepeng/systems/DirectorSystem;->increaseScore(I)V` |
| `invoke-direct {parameters}, methodtocall`    | Invokes a method with parameters without virtual method resolution (private methods) | DoubleShot doubleShot = new DoubleShot();                 | `invoke-direct {v0}, Lde/fgerbig/spacepeng/components/powerup/DoubleShot;-><init>()V`       |
| `invoke-static {parameters}, methodtocall`    | Invokes a static method with parameters                                              | `MathUtils.random((float) MIN_DELAY, (float) MAX_DELAY);` | `invoke-static {v0, v1}, Lcom/example/MathUtils;->random(FF)F`                              |
| `invoke-interface {parameters}, methodtocall` | Invokes an interface method                                                          | `itrt.hasNext();`                                         | `invoke-interface {v3}, Ljava/util/Iterator;->hasNext()Z`                                   |
| `Sget-object`                                 | Retrieves the value of a static object field and puts it into a register             | `String name = MyClass.staticField;`                      | `sget-object v0, Lcom/example/MyClass;->staticField:Ljava/lang/String;`                     |

### Method Definitions

A method in Smali starts with a `.method` directive and is followed by the method signature, return type, and parameters.

**Example**:

```smali
.method public myMethod(I)V  # A method named 'myMethod' that takes an integer and returns void
    .locals 1                    # Defines 1 local register
    return-void                  # Return from the method
.end method
```

### **Other Instructions**

* **`move`**: Moves the value from one register to another.
* **`return-void`**: Returns from a method with no value.
* **`return`**: Returns a value from a method.

## SMALI snippets

<table><thead><tr><th>Action</th><th>Java</th><th>Smali</th></tr></thead><tbody><tr><td>Printing Variables</td><td><pre class="language-java"><code class="lang-java">String example = "Example!!!";
System.out.println(example);
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">.line 14
const-string v0, "Example!!!"
.line 15
.local v0, "example":Ljava/lang/String;
sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
</code></pre></td></tr><tr><td>Base64 encoding of byte array</td><td><pre class="language-java"><code class="lang-java">System.out.println(Base64.encodeToString(, Base64.DEFAULT));
</code></pre></td><td><pre class="language-smali"><code class="lang-smali"># Base64 encoding of byte array
const/4 v5, 0x0   # Reference to your byte array
invoke-static {v2, v5}, Landroid/util/Base64;->encodeToString([BI)Ljava/lang/String;
move-result-object v5
# Print the encoded string
sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
invoke-virtual {v1, v5}, Ljava/io/PrintStream;->println(Ljava/lang/String;)Vcode>
</code></pre></td></tr><tr><td>Toast creation</td><td><pre class="language-java"><code class="lang-java">Toast.makeText(this, "My message!!!", Toast.LENGTH_LONG).show();
</code></pre></td><td><pre class="language-smali"><code class="lang-smali">const/4 v0, 0x1
const-string v1, "My message!!!"
invoke-static {p0, v1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
</code></pre></td></tr></tbody></table>
