Introduction
Android applications, at their core, are compiled into Dalvik Executable (DEX) files. These files contain the bytecode that runs on the Android Runtime (ART) or older Dalvik virtual machine. Understanding and manipulating this bytecode is a powerful skill for security researchers, reverse engineers, and even developers looking to patch or analyze third-party applications. This lab will guide you through a hands-on process of decompiling an Android application, injecting custom Smali bytecode, recompiling it, and observing the altered behavior.
The Android DEX File Format: A Quick Primer
A DEX file isn’t just a simple collection of instructions; it’s a structured format designed for efficient execution on mobile devices. Key components include:
- Header: Contains file magic, checksum, and pointers to other data sections.
- String Table: A list of all unique strings used in the DEX file.
- Type IDs: References to types (classes, primitives, arrays).
- Method IDs: References to all methods declared or referenced.
- Field IDs: References to all fields declared or referenced.
- Class Definitions: Metadata for each class, including superclass, interfaces, source file, annotations, fields, and methods.
- Code Sections: The actual bytecode instructions for each method.
Our focus today will be on manipulating the bytecode within these code sections using Smali, a human-readable assembly language for DEX.
Essential Tools for the Lab
Before we begin, ensure you have the following tools set up:
-
Java Development Kit (JDK)
Required for
apktool,smali, andbaksmali. Download and install the latest LTS version from Oracle or OpenJDK. -
Android SDK Platform-Tools (ADB)
For installing applications on an Android device or emulator. Ensure
adbis in your system’s PATH. -
Apktool
This is our primary tool for decompiling and recompiling APKs. Download the
apktool.jarand its wrapper script from the official GitHub repository and place them in your PATH. -
Smali/Baksmali
These are the assembler/disassembler for DEX bytecode. They are often bundled and invoked by
apktool, but knowing their standalone existence is useful. -
A Text Editor
Any robust text editor (e.g., VS Code, Sublime Text, Notepad++) capable of handling large text files and offering syntax highlighting (if available for Smali) will suffice.
Setting Up Your Environment
Verify your installations:
java -versionapktool --versionadb version
If all commands return version information, you’re ready.
Acquiring and Decompiling a Target APK
For this lab, you can use any non-system APK. You can either extract one from your own Android device using adb pull /data/app/package.name-XYZ/base.apk or download a sample APK from a trusted source. Let’s assume our target is named example.apk.
Decompile the APK:
apktool d example.apk -o example_decompiled
This command will create a directory named example_decompiled containing the decompiled resources, AndroidManifest.xml, and most importantly, the smali directory which holds all the application’s bytecode in Smali assembly language.
Diving into Smali: The Bytecode Assembly
Smali provides a textual representation of DEX bytecode. Here’s a quick rundown of common elements:
.class,.super,.source: Define class properties..method,.end method: Delimit method definitions. Methods are described by their access modifiers (public,private), name, parameter types, and return type (e.g.,(Ljava/lang/String;)Zmeans a method taking a String and returning a boolean)..locals N: Declares the number of local registers a method uses..param pX, "variableName": Documents method parameters, mapped topregisters.- Registers:
vX: General-purpose local registers (can also hold parameters).pX: Parameter registers (a subset ofvXif.localsis sufficient).
- Instructions:
const/4 v0, 0x0: Load the 32-bit integer value 0 into registerv0.move-result v0: Move the result of the previousinvokeinstruction intov0.invoke-static {p0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I: Call the static methodLog.dwith parameters inp0andp1.return v0: Return the value inv0from the method.if-eqz v0, :label: Ifv0equals zero, jump to:label.
Consider this Java code:
public boolean checkFeatureEnabled(String featureName) { if (featureName.equals("premium")) { return false; // Default to false for premium feature } return true;}
Its simplified Smali equivalent might look something like this:
.method public checkFeatureEnabled(Ljava/lang/String;)Z .locals 2 .param p1, "featureName" # Ljava/lang/String; const-string v0, "premium" invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_0 const/4 v0, 0x1 return v0 :cond_0 const/4 v0, 0x0 return v0.end method
Identifying and Altering Target Logic
Our goal is to alter the app’s logic. A common scenario is to bypass a license check, enable a hidden feature, or inject logging. Let’s aim to force a method that returns a boolean to always return true.
Navigate into the example_decompiled/smali directory. You can use grep or your editor’s search function to find interesting method names or string literals (e.g., “premium”, “license”, “isPro”).
For instance, let’s assume we find a method like com/example/app/LicenseManager.smali containing a method isLicensed()Z. Open this file.
Original isLicensed()Z method (simplified):
.method public isLicensed()Z .locals 1 # ... some complex license check logic ... const/4 v0, 0x0 # Result of the license check is false return v0.end method
To force it to always return true, we can change the const/4 v0, 0x0 instruction to const/4 v0, 0x1.
Modified isLicensed()Z method:
.method public isLicensed()Z .locals 1 # ... some complex license check logic (now bypassed) ... const/4 v0, 0x1 # Force result to be true return v0.end method
Alternatively, let’s inject a debug log into a method to confirm its execution path. Find a method like com/example/app/MainActivity.smali and locate its onCreate method. We’ll add a log message.
Find .method protected onCreate(Landroid/os/Bundle;)V. Before the final return-void, inject the following lines:
const-string v0, "DEXLab" const-string v1, "onCreate method hijacked!" invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I # Original instruction that was here, e.g., return-void return-void
Note that we used v0 and v1 as temporary registers. Ensure these do not conflict with existing register usage in the method, or increment .locals if necessary (e.g., if method uses 1 local, and you need two more for log, increment to .locals 3).
Recompiling the Modified APK
After saving your Smali file changes, it’s time to recompile the application:
apktool b example_decompiled -o example_modified.apk
If the recompilation is successful, you’ll find example_modified.apk in your current directory. apktool handles the reassembly of Smali into DEX, and packaging it with resources.
Signing and Installing the New APK
Android requires all APKs to be digitally signed before they can be installed. Since apktool doesn’t sign the APK, we need to do it manually.
-
Generate a Keystore (if you don’t have one)
If you already have a keystore, skip this. Otherwise, create one:
keytool -genkey -v -keystore my-release-key.keystore -alias my_alias -keyalg RSA -keysize 2048 -validity 10000Follow the prompts to set passwords and provide details.
-
Sign the APK
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore example_modified.apk my_aliasEnter your keystore password when prompted.
-
Verify Signing (Optional)
To ensure the APK is correctly signed:
jarsigner -verify -verbose -certs example_modified.apk -
Zipalign (Recommended for Performance)
zipalignoptimizes the APK for faster loading. This tool is found in your Android SDK’sbuild-tools/<version>directory.zipalign -v 4 example_modified.apk example_final.apkThe
4specifies byte alignment. Your final, signed, and aligned APK isexample_final.apk. -
Install and Test
Uninstall the original app (if installed) to avoid signature conflicts:
adb uninstall com.example.appThen, install your modified APK:
adb install example_final.apkRun the app. If you modified a license check, you should now see the
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →