Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Smali Syntax and Class Structure Reference

Tech 1

Dalvik bytecode executes on a register-based VM. Each virtual registre is 32 bits wide; 64‑bit primitives (long, double) consume a pair of adjacent registers. Smali is the human-readable assembly for Dalvik, while baksmali is its decompiler.

1. Types in Dalvik/Smali

Primitive type descriptors:

Code Meaning
V void (return only)
Z boolean
B byte
S short
C char
I int
J long (64‑bit)
F float
D double (64‑bit)

Reference types and arrays:

  • Objects: Lpackage/ClassName; (example: Ljava/lang/String;) → java.lang.String
  • One-dimensional arrays: [I, [F, [Ljava/lang/String;, etc.
  • Multi-dimensional arrays: add one [ per dimension, e.g., [[I → int[][]

2. Core Syntax

2.1 Expressions

Java:

public void mathOps() {
    int x = 2;
    double y = 3.25;

    double sum  = x + y;
    double diff = y - x;
    double prod = x * y;
    double quot = y / x;

    int m = 5;
    int xorRes = x ^ m;

    int pick = (x < y) ? m : x;
}

Smali:

.method public mathOps()V
    .locals 16

    const/4 v0, 0x2                # x
    const-wide v1, 0x400a000000000000L  # y = 3.25

    # sum = x + y
    int-to-double v3, v0
    add-double/2addr v3, v1         # v3-v4 hold sum

    # diff = y - x
    int-to-double v5, v0
    sub-double v5, v1, v5           # v5-v6 hold diff

    # prod = x * y
    int-to-double v7, v0
    mul-double/2addr v7, v1         # v7-v8 hold prod

    # quot = y / x
    int-to-double v9, v0
    div-double v9, v1, v9           # v9-v10 hold quot

    # xorRes = x ^ m
    const/4 v11, 0x5                # m
    xor-int v12, v0, v11

    # pick = (x < y) ? m : x
    int-to-double v5, v0            # reuse v5-v6 for compare lhs
    cmpl-double v13, v5, v1         # v13: -1 if x<y, 0 if ==, 1 if >
    if-ltz v13, :lt
    move v14, v0
    goto :done
:lt
    move v14, v11
:done
    return-void
.end method

Operator families commonly used:

Java op Smali (examples)
+ add-int, add-float, add-double
- sub-int, sub-float, sub-double
* mul-int, mul-float, mul-double
/ div-int, div-float, div-double
^ (bitwise XOR) xor-int, xor-long
ternary a ? b : c if-… + move/goto

2.2 Conditional Branching

Java:

public void branchOps() {
    int p = 7, q = 4;
    int r = -1;

    if (p <= q) r = p;
    if (p >  q) r = q;
    if (p == q) r = 0;
    if (p != q) r = 1;
    if (p >= q) r = 2;
    if (p <  q) r = 3;
}

Smali:

.method public branchOps()V
    .locals 3

    const/4 v0, 0x7   # p
    const/4 v1, 0x4   # q
    const/4 v2, -0x1  # r

    if-gt v0, v1, :skip_le
    move v2, v0       # r = p when p <= q
:skip_le

    if-le v0, v1, :skip_gt
    move v2, v1       # r = q when p > q
:skip_gt

    if-ne v0, v1, :skip_eq
    const/4 v2, 0x0   # r = 0 when p == q
:skip_eq

    if-eq v0, v1, :skip_ne
    const/4 v2, 0x1   # r = 1 when p != q
:skip_ne

    if-lt v0, v1, :skip_ge
    const/4 v2, 0x2   # r = 2 when p >= q
:skip_ge

    if-ge v0, v1, :end
    const/4 v2, 0x3   # r = 3 when p < q
:end
    return-void
.end method

Single-register comparisons against zero are also available: if-eqz, if-nez, if-ltz, if-lez, if-gtz, if-gez.

Semantisc overview:

  • if-eq vA, vB, :label → jump if vA == vB
  • if-ne vA, vB, :label → jump if vA != vB
  • if-lt vA, vB, :label → jump if vA < vB
  • if-le vA, vB, :label → jump if vA <= vB
  • if-gt vA, vB, :label → jump if vA > vB
  • if-ge vA, vB, :label → jump if vA >= vB
  • Zero variants (…z) compare vA with 0

2.3 Loops

Java:

public void loopsDemo() {
    int w = 0;             // while
    while (w <= 3) {
        w++;
    }

    int acc = 0;           // for
    for (int i = 1; i < 3; i++) {
        acc += i;
    }

    int z = 0;             // do..while
    do {
        z++;
    } while (z <= 3);
}

Smali:

.method public loopsDemo()V
    .locals 6

    # while (w <= 3) { w++; }
    const/4 v0, 0x0         # w
:while_head
    const/4 v1, 0x3
    if-gt v0, v1, :after_while
    add-int/lit8 v0, v0, 0x1
    goto :while_head
:after_while

    # for (int i = 1; i < 3; i++) { acc += i; }
    const/4 v2, 0x1         # i
    const/4 v3, 0x0         # acc
:for_check
    if-ge v2, v1, :after_for
    add-int v3, v3, v2
    add-int/lit8 v2, v2, 0x1
    goto :for_check
:after_for

    # do { z++; } while (z <= 3)
    const/4 v4, 0x0         # z
:do_body
    add-int/lit8 v4, v4, 0x1
    if-le v4, v1, :do_body

    return-void
.end method

Key pattern: place a label at the top of the loop body, branch out on the exit condition, and jump back with goto for the next iteration.

2.4 try/catch/final

Java:

public void tryCatchFinally() {
    Object o = null;
    try {
        o.toString();         // will throw if o == null
    } catch (Exception ex) {
        o = new Object();
    } finally {
        o = null;
    }
}

Smali:

.method public tryCatchFinally()V
    .locals 3

    const/4 v0, 0x0               # o

    :try_start_0
    invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    :try_end_0
    goto :finally_block

    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_ex

:catch_ex
    move-exception v2
    new-instance v1, Ljava/lang/Object;
    invoke-direct {v1}, Ljava/lang/Object;-><init>()V
    move-object v0, v1
    goto :finally_block

:finally_block
    const/4 v0, 0x0               # o = null (finally)
    return-void
.end method

To guarantee finally executes for any throwable, add a catchall handler and rethrow after executign the finally block.

.method public tryCatchFinallyStrict()V
    .locals 3

    const/4 v0, 0x0               # o

    :tstart
    invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    :tend
    goto :fin

    .catch Ljava/lang/Exception; {:tstart .. :tend} :handler
    .catchall {:tstart .. :tend} :all

:handler
    move-exception v2
    new-instance v1, Ljava/lang/Object;
    invoke-direct {v1}, Ljava/lang/Object;-><init>()V
    move-object v0, v1
    goto :fin

:all
    move-exception v2
    const/4 v0, 0x0               # finally
    throw v2

:fin
    const/4 v0, 0x0               # finally
    return-void
.end method

3. Smali Class File Layout

3.1 Header

.class public Lcom/example/smali/IntroActivity;
.super Landroid/app/Activity;
.source "IntroActivity.java"
  • .class: fully-qualified class descriptor
  • .super: superclass descriptor
  • .source: original source file name

3.2 Constructor

# direct methods
.method public constructor <init>()V
    .locals 0
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
    return-void
.end method

p0 always references the current instance (this) in instance methods.

3.3 Virtual Methods

Example: onCreate

# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 1
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    const v0, 0x7f0a0000               # layout id
    invoke-virtual {p0, v0}, Lcom/example/smali/IntroActivity;->setContentView(I)V

    return-void
.end method

Notes:

  • Method signature uses type descriptors; return type V means void
  • Parameters follow the same descriptors; p0 is this, p1..pN are parameters
  • .locals declares the number of non-paramter registers v0..vN used within the method

3.4 Common Directives and Markers

  • .class: declare class descriptor
  • .super: declare superclass descriptor
  • .source: associate source filename
  • .field: declare fields
  • .method … .end method: declare methods
  • .annotation … .end annotation: annotations
  • .implements: implemented interface descriptor(s)
  • .locals N: number of local registers (v0..vN-1)
  • .registers N: total registers (parameters + locals) when explicit control is needed
  • .line N: source line markers
  • .param/.param pX: parameter name/descriptor metadata
  • Labels (e.g., :L0): branch targets for if/goto/try regions

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.