Smali: Assembler for Android’s VM

Assembly language for the dex format, used by Android’s Dalvik virtual machine.

The Mobile Security Guys
5 min readJun 9, 2020

When testing Android mobile apps, quite often you can find yourself in a situation where you face a security mechanism that you wish to bypass, either because the app won’t run (e.g root detection) or there is something else you want to investigate more (e.g SSL pinning).

Usually a tester has 2 options to bypass these mechanisms:

  1. Bypassing these checks at runtime when executing the app using tools such as Frida; attach the tool to the app process to inject code to manipulate the behaviour.
    Although fast and usually easier: you need to attach to the app process every time you run the app.
  2. Otherwise, another more powerful approach while at the same time slightly more complex, consists in modifying the app binary for the specific checks we wish to bypass. In the Android security community this process is referred to as smali code patching.

By patching the underlying binary code, we can bypass app protections and manipulate its behaviour.

Smali

From the official git¹, “smali/baksmali is an assembler/disassembler for the dex format used by dalvik, Android’s Java VM implementation”.

The smali code, which is what we wish to modify, can be thought of as an equivalent of assembly code of a C program.

Having said this, in order to fully understand what smali code is and how it works, it is worth taking a look at the compilation process of an Android app written in Java and where dalvik and dex fit into this.

Android apps are usually written in Java and compiled to Dalvik bytecode. Dalvik bytecode is created by first compiling the Java code to .class files, then converting the JVM bytecode to the Dalvik .dex format with the dx tool.

Extracted from the OWAP Mobile Security Testing Guide²

Java compilation process vs Android compilation process with the extra step for the dex compiler.
Java compilation process vs Android compilation process

In this comparison, it can be observed that in Android systems we have an extra compilation step rather than the usual Java program. The Java bytecode is compiled into Dalvik bytecode which is then executed by the Android environment; which in modern devices is Android RunTime (ART). ART is the modern day replacement for the Dalvik VM however still runs the .dex file format.

With this in mind, what smali/backsmali tools do is to reverse the compilation of this bytecode in this .dex format. This is exactly what tools such as apktool³ do; it uses smali/backsmali internally when decompiling an APK file.

There are still challenges that remain despite smali being a hybrid language; using opcodes as well as semi-readable code.

Despite all this, smali patching presents a couple of challenges:

  • Although smali code does not look exactly like assembly (in terms of syntax), at the same time it does not look like readable code. It is a hybrid mix of the two which the tester must understand.
  • Considering the complexity and how low level smali code is, quite often it is easy to modify something that breaks the logic of the app, making the app unusable or unstable.

Patching Smali

Having introduced and explained the basics of what smali code is, and the reason for modifying it, we’ll begin to talk over some of its structure and syntax, however we will not discuss all opcodes⁴

Before we start exploring the syntax and patching we first need to decompile the target apk. This can be done using apktool to reverse the application, the code and resources; the smali code files can then be found in myAppDirSrc\smali.

java -jar apktool.jar d MyAppName.apk -o myAppDirSrc

Once we’ve done the smali patches, we need to recompile our code to build it from .dex files back into an .apk.

java -jar apktool.jar b myAppDirSrc -o MyNewAppName.apk

However to ensure the modified app installs on a device, it also needs to be signed with a developer signature.

keytool -genkey -v -keystore myKey.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myAliaszipalign -v -p 4 MyNewAppName.apk MyNewAppNameAligned.apkapksigner sign — ks myKey.jks — out MyNewAppNameSigned.apk MyNewAppNameAligned.apk

We will look at some examples of Java and the associated smali code to identify where the similarities lie between the two. It is important to be aware of the syntax when working on smali patches in order understand the workflow of the application.

Registers and opcodes

.locals x   #local variables
.field public a:Ljava/lang/String; # instance fields
.method public constructor <init>(Ljava/lang/String;)V #methods
v0 #local variable 0
v1 #local variable 1
...
p0 #parameter 0 (Java 'this' context)
p1 #parameter 1
...
const/4 v0, 0x1 #constant value, putting decimal 1 into v0
if-eqz v0 #if v0 is equal to zero
if-nez v0 #if v0 is not equal to zero
move-result v1 #store previous result into v1
return v1 #return value of v1 back to calling method
return void #return a void value back to calling method
invoke-direct #invokes non static method, e.g private/constructor
invoke-static #invoke a static method
invoke-virtual #invoke non private/static/final, e.g native libs

Types

Single characters are used to define various Java types when used in method calls and return values.

V - void
Z - Boolean
B - byte
S - short
C - char
F - float
I - int
J - long
D - double
[ - array
L - class definition

Sample Syntax

  • method declaration of myMethod with a void return type
Java
private static void myMethod()
smali
.method private static myMethod()V
  • method declaration of myArgMethod with a Boolean return type and a Float argument
Java
private Boolean myArgMethod(float floatnum)
smali
.method private myArgMethod(F)Z –
  • method declaration of myStrMethod with a Boolean return type and a Byte and String argument
Java
public Boolean myStrMethod(byte mybyte, String str)
smali
.method public myStrMethod(B; Ljava/lang/String)Z –

We covered a brief intro into some of the vast subject that denotes the smali language; however with only understanding the basics we can start to pull apart the app structure, understand input parameters and return types, and try to modify certain behaviours to manipulate the underlying logic.

--

--

The Mobile Security Guys

Random posts about mobile security and testing techniques from a bunch of mobile professionals.