SMALI

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

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., [Bbyte[])

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)

Method Type
Java
Smali (.locals)
Smali (.registers)

Static

public static int addInteger2(int num1, int num2) {
    int res = num1 + num2;
    return res;
}

.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
.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

Virtual

public int addInteger(int num1, int num2) {
    int res = num1 + num2;
    return res;
}
.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
.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

Initialization and return

Command

Description

Example (Java/Smali)

move vx,vy

Moves the content of vy into vx.

int a = 12; mov v0, 0xc

const/4 vx,lit4

Puts the 4-bit constant into vx Alternatives:

  • const vx, value: values higher than 7

  • const/16: 16-bit constant

  • const/high16:high 16-bit constant

int level = 3; const/4 v0, 0x5

new-array vx,vy,type_id

Generates a new array of type_id type and vy element size, then stores the reference in vx.

byte[] bArr = {0, 1, 2, 3, 4}; const/4 v0, 0x5 new-array v0, v0, [B

const vx, lit32

Puts a 32-bit integer constant into vx.

int level = 10000; const vx, 0x2710

const-string vx,string_id

Puts a reference to a string constant identified by string_id into vx.

String name = "Player"; const-string v5, "Player"

iget vx, vy, field_id

Reads an instance field into vx, where the instance is referenced by vy.

return this.highScore; iget v0, p0, Lde/fgerbig/spacepeng/services/Profile;->highScore:I return v0

iput vx,vy, field_id

Puts vx into an instance field, where the instance is referenced by vy.

this.lastPlayedLevel = lastPlayedLevel2; iput p1, p0, Lde/fgerbig/spacepeng/services/Profile;->lastPlayedLevel:I

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:

int[] numbers = new int[]{10, 20};
.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)

Arithmetic and binary operators

Operation

Description

Java example

Smali example

add-int vx,vy,vz

vy + vzvx

value = value + 1;

add-int/lit8 v5, v5, 0x1

sub-int vx,vy,vz

vy - vzvx

value = value - 1;

sub-int/lit8 v5, v5, 0x1

mul-int vx,vy,vz

vy * vzvx

value = value * 50;

mul-int/lit8 v6, v1, 0x32

div-int vx,vy,vz

vy / vzvx

value = value / 2;

div-int v4, v1, 0x2

rem-int vx,vy,vz

vy % vzvx

Math.abs(step2 % 4);

rem-int/lit8 v0, p1, 0x4

and-int vx,vy,vz

vy & vzvx

int value = b & 127;

and-int/lit8 v1, p3, 0x1f

or-int vx,vy,vz

vy | vzvx

int result = a | b;

xor-int v1, v2, v3

xor-int vx,vy,vz

vy ^ vzvx

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:

.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

Action
Java
Smali

Printing Variables

String example = "Example!!!";
System.out.println(example);
.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

Base64 encoding of byte array

System.out.println(Base64.encodeToString(, Base64.DEFAULT));
# 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>

Toast creation

Toast.makeText(this, "My message!!!", Toast.LENGTH_LONG).show();
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

Last updated