smali_documentation - Shuriken-Group/Shuriken-Analyzer GitHub Wiki

Smali files are files with .smali extension, and used by the Smali assembler for generating the Dalvik files. Every Smali file corresponds to a Java class. Java packages are represented with / instead of with ., so for example `com.example.MyClass` would be represented like com/example/MyClass.smali.

Smali files can be divided into sections:

Class Header

The header contains several pieces of information. Smali files start with the .class directive with the name of the class in internal name representation:

.class public Lcom/example/MyClass;

The class MyClass from the package com.example is declared as public access modifier. The format of the class name is using type descriptor which starts by L and ends with ; for objects.

After the .class, header can include optional directives to provide additional information. Example, we can use .super directive for the parent class:

.super Ljava/lang/Object

There are other optional directives that can appear in the header:

  • .implements:

Used to specify that the current class implements one or more interfaces. For example, to specify more than one implemented class:

.implements Ljava/io/Serializable;
.implements Landroid/os/Parelable;
  • .source:

Directive used to specify the name of the original source that Smali code was generated from. Information can be useful for debugging purposes. Lambda-classes would point to lambda:

.source "MyClass.java"
  • .debug:

Used to enable debug information for the current class. When it is present, Smali assembler will include additional metadata in the final .dex that can be used by debuggers:

.debug 0

Class Annotations

Class annotations are used to provide metadata information about a class. Defined using .annotation directive followed by their descriptor and elements. Example of class annotations:

.class public Lcom/example/MyClass;
.super Ljava/lang/Object;

.annotation runtime Ljava/lang/Deprecated;
.end annotation

.annotation system Ldalvik/annotation/EnclosingClass;
    value = Lcom/example/OuterClass;
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0008
    name = "MyClass"
    outer = Lcom/example/OuterClass;
.end annotation

# class definition and methods go here

We have 3 different annotations:

  • @Deprecated: runtime annotation indicates class is deprecated and should no longer be used. Defined using the @java/lang/Deprecated annotation.
  • @EnclosingClass: this annotation specifies the enclosing class of the current. Defined using @dalvik/annotation/EnclosingClass descriptor. It specifies that the enclosing class of MyClass is OuterClass.
  • @InnerClass: System annotation specifies that the class is an inner class. Defined using the @dalvik/annotation/InnerClass descriptor. It specifies that the access flags for the class are 0x0008 (means it is static), name of the class is MyClass, and the other class is OuterClass.

We can specify for example the Signature annotation in an interface:

.class public interface abstract Lcom/example/MyClass;
.super Ljava/lang/Object;

# add the Signature annotation to the class
.annotation system Ldalvik/annotation/Signature;
    value = {
        "<T:",
        "Ljava/lang/Object;
        ">",
        "Ljava/lang/Object;"
    }
.end annotation

In the example, MyClass class is defined with a type parameter T using the signature annotation. In java this would be represented like:

public interface MyClass<T> {
	/// ...
}

Fields

.field directive is used to define a field within a class. General syntax:

.field <access_flags> <name>:<type_descriptor> [ = <value> ]

Different components of the field:

  • access_flags: Access flags specify access modifiers for the field being defined. Values:
Name Description
public The field can be accessed from anywhere within the application.
protected The field can be accessed within the same package or by a subclass.
private The field can only be accessed within the same class or by a non-static subclass.
static The field belongs to the class, but not to any instance of the class.
final The field cannot be modified once it has been initialized.
synthetic The field is generated by the compiler and not present in the original source code.

We can use a combination of the flags using their integer values.

  • name: name of the field, starting with a letter and can contain letters, digits, underscores, and dollar signs.
  • type_descriptor: string representation of the type of the field.
  • value: value definition used when field should be assigned directly with a value.

Example:

.field private myField:I

Methods

A method definition consists of several components like access modifiers, return type, parameter types, and implementation code. The code block contains actual assembly'like code executed when the method is called. It can contain registers, instructions, labels, and exception handlers.

.method <access_flags> <name>(<parameter_types>)<return_type>
	<code_block>
.end method

Breakdown of the different parts:

  • <access_flags>: access modifiers for the method. Same than those for fields.
  • <name>: name of the method. Two special method names <init> and <clinit>.
  • <parameter_types>: type descriptors of the parameters of the method.
  • <return_type>: type descriptor of return type.
  • <code_block>: instructions of the method that performs functionality. Next sections are included:
    • Registers: used to store temporary data and intermediate results, specified using the letter v and a number (e.g. v0, v1, v2).
    • Instructions: used to perform operations on registers or objects. Each instruction is represented by a mnemonic (e.g. move, add, sub, etc) followed by its operands. Operands can be registers, constants or labels.
    • Labels: used to mark specific locations in the code block. Specified using a colon : and a name :label1, :label2, etc.
    • Exception handlers: used to handle exceptions that may occur during execution of the method. Specified using .catch directive, followed by type of exception that is being caught and the label of the handler.

Example of a method with "Hello World":

.method public static main([Ljava/lang/String;)V
	.registers 2
	
	sget-object v0, Ljava/lang/System;->out:Ljava/lang/PrintStream;
	
	const-string v1, "Hello World"
	
	invoke-virtual {v0, v1}, Ljava/lang/PrintStream;->println(Ljava/lang/String;)V
	
	return-void

.end method

Annotations

The .annotation directive is used to define an annotation. The structure of this directive is as follows:

.[sub]annotation <visibility> <annotation_type>
	[ <properties> ]
.end [sub]annotation

Annotation directive starts with the .annotation or .subannotation followed by the visibility and the type descriptor for the annotation. Three possible values for the annotation's visibility:

  • runtime: Annotation is visible at runtime and can be queried using reflection.
  • system: Annotation is a system annotation and is not visible to the user.
  • build: Special treating of the annotated value.

After the visibility and the annotation type descriptor, properties are defined. These are key-value pairs, where the key is the property's name and the value is the property's value. Properties are defined using syntax key = value. Possible to define multiple properties on separate lines within one annotation directive.

Example:

.annotation runtime Lcom/example/MyAnnotation;
    name = "John Doe"
    age = .subannotation runtime Lcom/example/Age;
            value = 30
          .end subannotation
.end annotation

Smali Syntax

Data type

Registers are 32-bit and can support any type. Long/Double is represented by two registers. Two types: basic type and reference type (object and array).

Basic types

Type Explain
V void, only used for return value types
Z boolean
B byte
S short
C char
I int
J long
F float
D double

Reference type

Type Explain
L Object type (Lpackage/ObjectName;)
[I Represents one dimensional array
[Ljava/lang/String An array of objects representing a String

Basic Grammar

Expression

Smali first example:

.method public smaliExpression()V
	.locals 15
	
	.line 16
	const/4 v0, 0x1  #1
	
	.line 17
	.local v0, "a":I
	const-wide/high16 v1, 0x4004000000000000L # 2.5
	
	.line 18
	.local v1, "b":D
	int-to-double v3, v0 // Variable 1 of int type to 1.0 of double
	
	add-double/2addr v3, v1 // Add to double types
	
	.line 21
	.local v3, "c":D
	int-to-double v5, v0
	
	sub-double v5, v1, v5 // Substract v5 = v1 - v5
	
	.line 24
	.local v5, "d":D
	int-to-double v7, v0
	
	mul-double/2addr v7, v1 // multiplication
	
	.line 27
	.local v7, "e":D
	int-to-double v9, v0
	
	div-double v9, v1, v9 // division
	
	.line 30
	.local v9, "f":D
	const/4 v11, 0x3
	
	.line 31
	.local v11, "g":I
	xor-int v12, v0, v11 // XOR
	
	// Exclusive or statement
	.line 34
	.local v12, "h":I
	int-to-double v13, v0
	
	cmpl-double v13, v13, v1 // Cmpl double comparison
	
	if-lez v13, :cond_0
	
	move v13, v0
	
	goto :goto_0
	
	:cond_0
	move v13, v11 // Give the value of register v11 to v13
	
	.line 35
	.local v13, "i":I
	:goto_0
	return-void
.end method

The translations are the next:

java operators smali operator
addition add-double/2addr
subtraction sub-double
multiplication mul-double/2addr
division div-double
XOR xor-int

Conditional Statement

Smali Example:

.method public smaliIf()V
	.locals 3
	
	.line 38
	const/4 v0, 0x1
	
	.local v0, "a":I
	const/4 v1, 0x2
	
	.line 39
	.local v1, "b":I
	const/4 v2, 0x0
	
	.line 40
	.local v2, "c":I
	if-le v0, v1, :cond_0
	
	.line 41
	move v2, v0
	
	.line 43
	:cond_0
	if-ge v0, v1, :cond_1
	
	.line 44
	move v2, v1
	
	.line 46
	:cond_1
	if-lt v0, v1, :cond_2
	
	.line 47
	move v2, v0
	
	.line 49
	:cond_2
	if-gt v0, v1, :cond_3
	
	.line 50
	move v2, v1
	
	.line 52
	:cond_3
	if-ne v0, v1, :cond_4
	
	.line 53
	move v2, v0
	
	.line 55
	:cond_4
	if-eq v0, v1, :cond_5
	
	.line 56
	move v2, v1
	
	.line 58
	:cond_5
	return-void
.end method

Loop statement

.method public smaliWhile()V
	.locals 5
	.line 62
	const/4 v0, 0x0
	
	move v1, v0
	
	.line 63
	.local v1, "a":I
	:goto_0
	const/4 v2, 0x3
	
	if-gt v1, v2, :cond_0 //If a > 3, jump to cond u 0
	
	.line 64
	add-int/lit8 v1, v1, 0x1 //if condition above does not exist, a increases by 1
	
	goto :goto_0 //Loop body, continue to execute downward from goto 0
	
	.line 68
	:cond_0
	const/4 v3, 0x0
	
	.line 69
	.local v3, "b":I
	move v4, v3
	
	move v3, v0
	
	.local v3, "i":I
	.local v4, "b":I
	:goto_1
	if-ge v3, v2, :cond_1 // i >= 3
	
	.line 70
	add-int/lit8 v4, v4, 0x1 // b++;
	
	.line 69
	add-int/lit8 v3, v3, 0x1 //i++;
	
	goto :goto_1 //Circulation main body
	
	.line 74
	.end local v3 # "i":I
	:cond_1
	nop //It means empty operation, do nothing
	
	.line 76
	.local v0, "c":I
	:cond_2
	add-int/lit8 v0, v0, 0x1
	
	.line 77
	if-le v0, v2, :cond_2
	
	.line 78
	return-void
.end method

Try-catch statement

.method public divideNumbers(II)Ljava/lang/String;
    .registers 5

    .line 4
    const-string v0, "Execution of divideNumbers method is complete."

    :try_start_2
    div-int/2addr p1, p2

    .line 5
    new-instance p2, Ljava/lang/StringBuilder;

    invoke-direct {p2}, Ljava/lang/StringBuilder;-><init>()V

    const-string v1, "The result is: "

    invoke-virtual {p2, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object p2

    invoke-virtual {p2, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;

    move-result-object p1

    invoke-virtual {p1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object p1
    :try_end_16
    .catch Ljava/lang/ArithmeticException; {:try_start_2 .. :try_end_16} :catch_1e
    .catchall {:try_start_2 .. :try_end_16} :catchall_1c

    .line 9
    sget-object p2, Ljava/lang/System;->out:Ljava/io/PrintStream;

    invoke-virtual {p2, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    .line 5
    return-object p1

    .line 9
    :catchall_1c
    move-exception p1

    goto :goto_27

    .line 6
    :catch_1e
    move-exception p1

    .line 7
    :try_start_1f
    const-string p1, "Error: Division by zero is not allowed."
    :try_end_21
    .catchall {:try_start_1f .. :try_end_21} :catchall_1c

    .line 9
    sget-object p2, Ljava/lang/System;->out:Ljava/io/PrintStream;

    invoke-virtual {p2, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    .line 7
    return-object p1

    .line 9
    :goto_27
    sget-object p2, Ljava/lang/System;->out:Ljava/io/PrintStream;

    invoke-virtual {p2, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    .line 10
    throw p1
.end method
⚠️ **GitHub.com Fallback** ⚠️