Reverse Engineering Android:
Disassembly & Code Injection
Thanasis Petsas
petsas@ics.forth.gr
petsas@ics.forth.gr - www.syssec-project.eu 1
Roadmap
The APK Structure
The Tools
Hacking Approach
Disassembly & App Analysis
Code Injection
petsas@ics.forth.gr - www.syssec-project.eu 2
The APK Structure
AndroidManifest.xml
classes.dex
res/
lib/ (sometimes)
META-INF
petsas@ics.forth.gr - www.syssec-project.eu 3
The Tools
Youll need
Android SDK
apktool (based on Smali/Baksmali)
jarsigner
keytool
petsas@ics.forth.gr - www.syssec-project.eu
Hacking Approach
petsas@ics.forth.gr - www.syssec-project.eu
Hacking Approach
1. Unzip APK & disassemble classes.dex
Disassemble (1)
(apktool/baksmali)
.smali
petsas@ics.forth.gr - www.syssec-project.eu
Hacking Approach
1. Unzip APK & disassemble classes.dex
2. Perform static analysis on the app
Static analysis (2)
Disassemble (1)
(apktool/baksmali)
.smali
petsas@ics.forth.gr - www.syssec-project.eu
Hacking Approach
1. Unzip APK & disassemble classes.dex
2. Perform static analysis on the app
3. Inject byte-code into the app
Static analysis (2)
Disassemble (1)
(apktool/baksmali)
.smali
Code injection (3)
petsas@ics.forth.gr - www.syssec-project.eu
Hacking Approach
1. Unzip APK & disassemble classes.dex
2. Perform static analysis on the app
3. Inject byte-code into the app
4. Reassemble classes.dex & zip/sign APK
Static analysis (2)
Disassemble (1) Reassemble (4)
(apktool/baksmali) (apktool/smali)
.smali
Code injection (3)
petsas@ics.forth.gr - www.syssec-project.eu
Disassembling APK
$ apktool d r MyApp.apk Myapp
decode Exclude out directory
resources
$ cd MyApp
$ ls
$ AndroidManifest.xml apktool.yml
assets res smali
petsas@ics.forth.gr - www.syssec-project.eu
Analyzing the APK
$ ls Myapp/smali/com/example/myapp
StartActivity.smali
R$attr.smali
R$drawable.smali
R$layout.smali
R$string.smali
R.smali
petsas@ics.forth.gr - www.syssec-project.eu
Analyzing the APK
$ ls Myapp/smali/com/example/myapp
StartActivity.smali com.example.myapp
R$attr.smali
R$drawable.smali
R$layout.smali
R$string.smali
R.smali
petsas@ics.forth.gr - www.syssec-project.eu
Analyzing the APK
$ ls Myapp/smali/com/example/myapp
StartActivity.smali com.example.myapp
R$attr.smali
R$drawable.smali StartActivity.java
R$layout.smali R.java
R$string.smali
R.smali
petsas@ics.forth.gr - www.syssec-project.eu
Java to Smali
# virtual methods
public class StartActivity extends Activity { .method protected onCreate(Landroid/os/Bundle;)V
.locals 3
@Override .parameter "savedInstanceState"
protected void onCreate( .prologue
Bundle savedInstanceState) { invoke-super {p0, p1}, Landroid/app/Activity
super.onCreate(savedInstanceState); ;->onCreate(Landroid/os/Bundle;)V
setContentView(R.layout.activity_start);
const/high16 v0, 0x7f03
Log.i("StartActivity:", Message");
const-string v0, "StartActivity:"
} const-string v1, Message"
invoke-static {v0, v1}, Landroid/util/Log;
->d(Ljava/lang/String;Ljava/lang/String;)I
move-result v0
return-void
Java code .end method Smali Byte code
petsas@ics.forth.gr - www.syssec-project.eu 8
Java to Smali
# virtual methods
public class StartActivity extends Activity { .method protected onCreate(Landroid/os/Bundle;)V
.locals 3
@Override .parameter "savedInstanceState"
protected void onCreate( .prologue
Bundle savedInstanceState) { invoke-super {p0, p1}, Landroid/app/Activity
super.onCreate(savedInstanceState); ;->onCreate(Landroid/os/Bundle;)V
setContentView(R.layout.activity_start);
const/high16 v0, 0x7f03
Log.i("StartActivity:", Message");
const-string v0, "StartActivity:"
} const-string v1, Message"
invoke-static {v0, v1}, Landroid/util/Log;
->d(Ljava/lang/String;Ljava/lang/String;)I
move-result v0
return-void
Java code .end method Smali Byte code
petsas@ics.forth.gr - www.syssec-project.eu 8
Java to Smali
# virtual methods
public class StartActivity extends Activity { .method protected onCreate(Landroid/os/Bundle;)V
.locals 3
@Override .parameter "savedInstanceState"
protected void onCreate( .prologue
Bundle savedInstanceState) { invoke-super {p0, p1}, Landroid/app/Activity
super.onCreate(savedInstanceState); ;->onCreate(Landroid/os/Bundle;)V
setContentView(R.layout.activity_start);
const/high16 v0, 0x7f03
Log.i("StartActivity:", Message");
const-string v0, "StartActivity:"
} const-string v1, Message"
invoke-static {v0, v1}, Landroid/util/Log;
->d(Ljava/lang/String;Ljava/lang/String;)I
move-result v0
return-void
Java code .end method Smali Byte code
petsas@ics.forth.gr - www.syssec-project.eu 8
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Class Representation in Smali
.class public Lcom/apkudo/util/Serializer;
.super Ljava/lang/Object; Class information
.source "Serializer.java
# static fields
.field public static final TAG:Ljava/lang/String; = String Static fields
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 5 Methods
invoke-direct {p0}, Ljava/lang/Object;-><init>()V Direct
Virtual
return-void
.end method
petsas@ics.forth.gr - www.syssec-project.eu
Smali Syntax Types
.method private doSomething()V
V void
Z boolean
B byte
S short
C char
F float
I int
J long
D double
[ array
petsas@ics.forth.gr - www.syssec-project.eu
Smali Syntax Classes
Lcom/example/myapp/MyClass;
full name space slash separated
prefixed with L
suffixed with ;
StringBuilder sb = new StringBuilder(str)
new-instance v1, Ljava/lang/StringBuilder;
const-string v2, str"
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-
><init>(Ljava/lang/String;)V
petsas@ics.forth.gr - www.syssec-project.eu
Smali Syntax Methods
.method private doSomething()V
keyword method name parameters/return
.method private delayedAnimationFrame(J)Z
.registers 8
.parameter "currentTime
# Static invocation
invoke-static {p2}, Landroid/text/TextUtils;
->isEmpty(Ljava/lang/CharSequence;)Z
# Virtual invocation
invoke-virtual {v0, v1}, Lcom/google/android/finsky/FinskyApp;
->drainAllRequests(I)V
petsas@ics.forth.gr - www.syssec-project.eu
Smali Syntax Registers
.locals # registers of a method
without parameters
#parameters # input parameters +
(p0: this reference)
v0 - local 0
p0 - parameter 0 (this)
p1 - parameter 1
petsas@ics.forth.gr - www.syssec-project.eu
Smali Syntax Opcodes
invoke-super vx, vy,
new-instance vx
invoke-direct vx, vy,
const-string vx
invoke-virtual vx, vy,
return-void
petsas@ics.forth.gr - www.syssec-project.eu
Hacking the App
Lets inject some code in the APK:
A toast message hacked!
Java code:
Toast.makeText(getApplicationContext(),
"Hacked!", Toast.LENGTH_SHORT).show();
How do we do this in smali?
Easy, lets just compile this into another app
(e.g., MyApp2) and disassemble
petsas@ics.forth.gr - www.syssec-project.eu
Result
Toast.makeText(getApplicationContext(),
"Hacked!", Toast.LENGTH_SHORT).show();
Java code
invoke-virtual {p0}, Lcom/example/myapp2/TestActivity;
->getApplicationContext()Landroid/content/Context;
move-result-object v1
const-string v2, "Hacked! Smali Byte code
const/4 v3, 0x0
invoke-static {v1, v2, v3}, Landroid/widget/Toast;
->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
Landroid/widget/Toast;
move-result-object v1
invoke-virtual {v1}, Landroid/widget/Toast;->show()V
petsas@ics.forth.gr - www.syssec-project.eu
Result
Toast.makeText(getApplicationContext(),
"Hacked!", Toast.LENGTH_SHORT).show();
Java code
invoke-virtual {p0}, Lcom/example/myapp2/TestActivity;
->getApplicationContext()Landroid/content/Context;
move-result-object v1
const-string v2, "Hacked! Smali Byte code
const/4 v3, 0x0
invoke-static {v1, v2, v3}, Landroid/widget/Toast;
->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
Landroid/widget/Toast;
move-result-object v1
invoke-virtual {v1}, Landroid/widget/Toast;->show()V
petsas@ics.forth.gr - www.syssec-project.eu
Result
Toast.makeText(getApplicationContext(),
"Hacked!", Toast.LENGTH_SHORT).show();
Java code
invoke-virtual {p0}, Lcom/example/myapp2/TestActivity;
->getApplicationContext()Landroid/content/Context;
move-result-object v1
const-string v2, "Hacked! Smali Byte code
const/4 v3, 0x0
invoke-static {v1, v2, v3}, Landroid/widget/Toast;
->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
Landroid/widget/Toast;
move-result-object v1
invoke-virtual {v1}, Landroid/widget/Toast;->show()V
petsas@ics.forth.gr - www.syssec-project.eu
Rebuilding the APK
$ apktool b ./MyApp
build out directory (produced previously)
This will instruct apktool to rebuild the app
The path to the new APK: ./Myapp/dist/Myapp.apk
But this app is not yet signed
petsas@ics.forth.gr - www.syssec-project.eu
Signing the APK
$ keytool -genkey -v -keystore my-release-
key.keystore -alias alias_name -keyalg RSA
-validity 10000
$ jarsigner -verbose -sigalg MD5withRSA -
digestalg SHA1 -keystore my-release-
key.keystore ./MyApp/dist/MyApp.apk
alias_name
petsas@ics.forth.gr - www.syssec-project.eu
Installing the APK
# remove it first, if it is already
installed using its package name
$ adb uninstall com.example.myapp
# then, install it
$ adb install ./MyApp/dist/MyApp.apk
petsas@ics.forth.gr - www.syssec-project.eu
Practical Session
You have received a malicious app named
Cthulhu.apk
This app sends some sensitive information to a
malicious server
Enhance the app with a static evasion heuristic
so that it will expose its malicious activity only
when running on a device
You dont have access to the apps source code
petsas@ics.forth.gr - www.syssec-project.eu 20
Steps to follow
a. First make Cthulhu app to display a toast
message hacked! (hint: use MyApp)
b. Patch Cthulhu app with the evasion heuristic
IMEI check (hint: use again MyApp)
c. Submit the app to an online analysis service
(e.g., Andrubis)
petsas@ics.forth.gr - www.syssec-project.eu 21
Step a. Inject a Toast Message
ToastMessage(Hacked!)
Build
MyApp (source code) eclipse MyApp (APK) MyApp (.smali)
Cthulhu (APK) Cthulhu (.smali)
petsas@ics.forth.gr - www.syssec-project.eu 22
Step a. Inject a Toast Message
ToastMessage(Hacked!)
Build
MyApp (source code) eclipse MyApp (APK) MyApp (.smali)
Cthulhu (APK) Cthulhu (.smali)
petsas@ics.forth.gr - www.syssec-project.eu 22
Step a. Inject a Toast Message
ToastMessage(Hacked!)
Build
MyApp (source code) eclipse MyApp (APK) MyApp (.smali)
Cthulhu (APK) Cthulhu (.smali)
petsas@ics.forth.gr - www.syssec-project.eu 22
Step a. Inject a Toast Message
ToastMessage(Hacked!)
Build
MyApp (source code) eclipse MyApp (APK) MyApp (.smali)
Cthulhu (APK) Cthulhu (.smali) Cthulhu (APK) +
evasion heuristic
petsas@ics.forth.gr - www.syssec-project.eu 22
Step b. Inject an Evasion Heuristic
Same procedure as in a. but the code we want
to inject is a static VM evasion heuristic
Simply check the Build.DEVICE field to find
out if app is running on Emulator
String device = Build.DEVICE;
if (device.equals("generic")) {
String env = "Emulator";
}
else {
String env = "Device";
}
petsas@ics.forth.gr - www.syssec-project.eu 23
Step c. Verify the repackaged app
Submit both the original and the repackaged
app on an online analysis service
(e.g., Andrubis)
Compare the produced reports
petsas@ics.forth.gr - www.syssec-project.eu 24
HINTS & TIPS
Always ensure you have sufficient amount of
registers when patching .locals
Always fix the package name path in any
injected method call
invoke-virtual p0, Lcom/example/myapp/StartActivity;->
getApplicationContext()Landroid/content/Context;
invoke-virtual p0, Lcom/example/cthulhu/MainActivity;->
getApplicationContext()Landroid/content/Context;
petsas@ics.forth.gr - www.syssec-project.eu 25