If you haven't already, we need to install the CrackMe! application in our Genymotion emulator.
➜ app git:(master) ✗ adb devices
List of devices attached
192.168.56.101:5555 device
➜ app git:(master) ✗ adb install crackme.apk
7187 KB/s (907915 bytes in 0.123s)
pkg: /data/local/tmp/crackme.apk
Success
What happens when you try to run the application? -> CrackME! attempts to uninstall itself!
-- Analyze CrackME! with Androguard ---
➜ app git:(master) ✗ python ~/Tools/mobile/android/androguard/androlyze.py -s
In [2]: a.get_activities()
Out[2]: ['com.versprite.crackme.KeyActivity']
In [3]: a.get_main_activity()
Out[3]: u'com.versprite.crackme.KeyActivity'
So now know that com.versprite.crackme.KeyActivity is the Main Activity. Now we have a start point for reversing the application.
In our previous lab, I explained that 'd' in the AnalyzeAPK() assigment contains a class that has the ability the parse and understand the DEX format.
If you type d.C [tab] ->
d.CLASS_Lcom_versprite_crackme_BuildConfig
d.CLASS_Lcom_versprite_crackme_KeyActivity
d.CLASS_Lcom_versprite_crackme_KeyActivity_1
d.CLASS_Lcom_versprite_crackme_R
d.CLASS_Lcom_versprite_crackme_R_anim
d.CLASS_Lcom_versprite_crackme_R_attr
d.CLASS_Lcom_versprite_crackme_R_bool
d.CLASS_Lcom_versprite_crackme_R_color
d.CLASS_Lcom_versprite_crackme_R_dimen
d.CLASS_Lcom_versprite_crackme_R_drawable
d.CLASS_Lcom_versprite_crackme_R_id
d.CLASS_Lcom_versprite_crackme_R_integer
d.CLASS_Lcom_versprite_crackme_R_layout
d.CLASS_Lcom_versprite_crackme_R_menu
d.CLASS_Lcom_versprite_crackme_R_mipmap
d.CLASS_Lcom_versprite_crackme_R_string
d.CLASS_Lcom_versprite_crackme_R_style
d.CLASS_Lcom_versprite_crackme_R_styleable
d.CLASS_Lcom_versprite_crackme_emulator_Detect
d.CLASS_Lcom_versprite_crackme_generate_Generate
d.CLASS_Lcom_versprite_crackme_generate_GenerateReceiver
This displays all of the classes within the classes.dex that have been analzyed by Androlyze. Now, because we know which class we want to focus on (d.CLASS_Lcom_versprite_crackme_KeyActivity), we can access it directly.
In [4]: d.CLASS_Lcom_versprite_crackme_KeyActivity.
d.CLASS_Lcom_versprite_crackme_KeyActivity.FIELD_key
d.CLASS_Lcom_versprite_crackme_KeyActivity.FIELD_submitbtn
d.CLASS_Lcom_versprite_crackme_KeyActivity.METHOD_access_000
d.CLASS_Lcom_versprite_crackme_KeyActivity.METHOD_addListenerOnButton
d.CLASS_Lcom_versprite_crackme_KeyActivity.METHOD_init
d.CLASS_Lcom_versprite_crackme_KeyActivity.METHOD_onCreate
d.CLASS_Lcom_versprite_crackme_KeyActivity.access_flags
d.CLASS_Lcom_versprite_crackme_KeyActivity.access_flags_string
d.CLASS_Lcom_versprite_crackme_KeyActivity.annotations_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.class_data_item
d.CLASS_Lcom_versprite_crackme_KeyActivity.class_data_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.class_idx
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_access_flags
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_access_flags_string
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_annotations_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_class_data
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_class_data_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_class_idx
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_fields
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_interfaces
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_interfaces_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_length
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_methods
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_name
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_obj
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_raw
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_source
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_source_ext
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_source_file_idx
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_static_values_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_superclass_idx
d.CLASS_Lcom_versprite_crackme_KeyActivity.get_superclassname
d.CLASS_Lcom_versprite_crackme_KeyActivity.interfaces
d.CLASS_Lcom_versprite_crackme_KeyActivity.interfaces_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.name
d.CLASS_Lcom_versprite_crackme_KeyActivity.offset
d.CLASS_Lcom_versprite_crackme_KeyActivity.reload
d.CLASS_Lcom_versprite_crackme_KeyActivity.set_name
d.CLASS_Lcom_versprite_crackme_KeyActivity.show
d.CLASS_Lcom_versprite_crackme_KeyActivity.show_xref
d.CLASS_Lcom_versprite_crackme_KeyActivity.sname
d.CLASS_Lcom_versprite_crackme_KeyActivity.source
d.CLASS_Lcom_versprite_crackme_KeyActivity.source_file_idx
d.CLASS_Lcom_versprite_crackme_KeyActivity.static_values
d.CLASS_Lcom_versprite_crackme_KeyActivity.static_values_off
d.CLASS_Lcom_versprite_crackme_KeyActivity.superclass_idx
-- We can inspect the entire Class the easy way first! --
In [13]: d.CLASS_Lcom_versprite_crackme_KeyActivity.source()
package com.versprite.crackme;
public class KeyActivity extends android.app.Activity {
private android.widget.EditText key;
private android.widget.Button submitbtn;
public KeyActivity()
{
return;
}
static synthetic android.widget.EditText access$000(com.versprite.crackme.KeyActivity p1)
{
return p1.key;
}
public void addListenerOnButton()
{
this.key = ((android.widget.EditText) this.findViewById(2131296320));
this.submitbtn = ((android.widget.Button) this.findViewById(2131296321));
this.submitbtn.setOnClickListener(new com.versprite.crackme.KeyActivity$1(this));
return;
}
protected void onCreate(android.os.Bundle p5)
{
super.onCreate(p5);
this.setContentView(2130968599);
if (new com.versprite.crackme.emulator.Detect().detectEmulator().equals(Boolean.TRUE)) {
android.util.Log.d("Emulator Detected!", "Uninstalling ...");
android.content.Intent v1_1 = new android.content.Intent("android.intent.action.UNINSTALL_PACKAGE");
v1_1.setData(android.net.Uri.parse("package:com.versprite.crackme"));
this.startActivity(v1_1);
this.finish();
}
this.addListenerOnButton();
return;
}
}
In [14]:
We really care about what is going on in the onCreate() method. Why? -> http://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)
- Called when the Activity is starting
- This is where most initialization should go
What looks important in the onCreate() method?
if (new com.versprite.crackme.emulator.Detect().detectEmulator().equals(Boolean.TRUE)) {
android.util.Log.d("Emulator Detected!", "Uninstalling ...");
android.content.Intent v1_1 = new android.content.Intent("android.intent.action.UNINSTALL_PACKAGE");
v1_1.setData(android.net.Uri.parse("package:com.versprite.crackme"));
this.startActivity(v1_1);
this.finish();
- Creates a new instance of Detect()
- Calls detectEmulator()
- If it returns TRUE
- Create a new Intent object
- Assign the 'android.intent.action.UNINSTALL_PACKAGE' action
- Set the com.versprite.crackme package
- Start the appropriate Activitiy with this Intent object
The ActivityManager will handle this Intent object, and knows that com.android.packageinstaller/.UninstallerActivity
can handle this action.
This is what logcat will tell us:
I/ActivityManager(22534): START u0 {act=android.intent.action.UNINSTALL_PACKAGE dat=package:com.versprite.crackme cmp=com.android.packageinstaller/.UninstallerActivity} from pid 24549
I/ActivityManager(22534): Displayed com.android.packageinstaller/.UninstallerActivity: +195ms (total +210ms)
We have a pretty good representation of what the source code would like for this Activity, but we can also inspect the bytecode as well.
-- Enumerate Methods --
In [15]: for method in d.CLASS_Lcom_versprite_crackme_KeyActivity.get_methods(): print(method.pretty_show())
get_methods() returns a list of method instances that belong to the KeyActivity class. We can run a simple for in loop over these methods, and call pretty_show(), which will provide some syntax highlighting.
-- onCreate() --
########## Method Information
Lcom/versprite/crackme/KeyActivity;->onCreate(Landroid/os/Bundle;)V [access_flags=protected]
########## Params
- local registers: v0...v4
- v5: android.os.Bundle
- return: void
####################
***************************************************************************
onCreate-BB@0x0 :
0 (00000000) invoke-super v4, v5, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
1 (00000006) const v2, 2130968599
2 (0000000c) invoke-virtual v4, v2, Lcom/versprite/crackme/KeyActivity;->setContentView(I)V
3 (00000012) new-instance v0, Lcom/versprite/crackme/emulator/Detect;
4 (00000016) invoke-direct v0, Lcom/versprite/crackme/emulator/Detect;-><init>()V
5 (0000001c) invoke-virtual v0, Lcom/versprite/crackme/emulator/Detect;->detectEmulator()Ljava/lang/Boolean;
6 (00000022) move-result-object v2
7 (00000024) sget-object v3, Ljava/lang/Boolean;->TRUE Ljava/lang/Boolean;
8 (00000028) invoke-virtual v2, v3, Ljava/lang/Boolean;->equals(Ljava/lang/Object;)Z
9 (0000002e) move-result v2
10 (00000030) if-eqz v2, 31 [ onCreate-BB@0x34 onCreate-BB@0x6e ]
onCreate-BB@0x34 :
11 (00000034) const-string v2, 'Emulator Detected!'
12 (00000038) const-string v3, 'Uninstalling ...'
13 (0000003c) invoke-static v2, v3, Landroid/util/Log;->d(Ljava/lang/String; Ljava/lang/String;)I
14 (00000042) new-instance v1, Landroid/content/Intent;
15 (00000046) const-string v2, 'android.intent.action.UNINSTALL_PACKAGE'
16 (0000004a) invoke-direct v1, v2, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
17 (00000050) const-string v2, 'package:com.versprite.crackme'
18 (00000054) invoke-static v2, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;
19 (0000005a) move-result-object v2
20 (0000005c) invoke-virtual v1, v2, Landroid/content/Intent;->setData(Landroid/net/Uri;)Landroid/content/Intent;
21 (00000062) invoke-virtual v4, v1, Lcom/versprite/crackme/KeyActivity;->startActivity(Landroid/content/Intent;)V
22 (00000068) invoke-virtual v4, Lcom/versprite/crackme/KeyActivity;->finish()V [ onCreate-BB@0x6e ]
onCreate-BB@0x6e :
23 (0000006e) invoke-virtual v4, Lcom/versprite/crackme/KeyActivity;->addListenerOnButton()V
24 (00000074) return-void
***************************************************************************
########## XREF
T: Lcom/versprite/crackme/emulator/Detect; <init> ()V 16
T: Lcom/versprite/crackme/emulator/Detect; detectEmulator ()Ljava/lang/Boolean; 1c
T: Lcom/versprite/crackme/KeyActivity; addListenerOnButton ()V 6e
####################
What do we know about this method so far?
- local registers (non-paramters) v0 .. v4
- v5 android.os.Bundle (argument)
- returns void
-- Method Isolation --
In [30]: onCreate = d.CLASS_Lcom_versprite_crackme_KeyActivity.METHOD_onCreate
In [31]: onCreate.pretty_show()
########## Method Information
Lcom/versprite/crackme/KeyActivity;->onCreate(Landroid/os/Bundle;)V [access_flags=protected]
########## Params
- local registers: v0...v4
- v5: android.os.Bundle
- return: void
####################
***************************************************************************
onCreate-BB@0x0 :
0 (00000000) invoke-super v4, v5, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
1 (00000006) const v2, 2130968599
2 (0000000c) invoke-virtual v4, v2, Lcom/versprite/crackme/KeyActivity;->setContentView(I)V
3 (00000012) new-instance v0, Lcom/versprite/crackme/emulator/Detect;
4 (00000016) invoke-direct v0, Lcom/versprite/crackme/emulator/Detect;-><init>()V
5 (0000001c) invoke-virtual v0, Lcom/versprite/crackme/emulator/Detect;->detectEmulator()Ljava/lang/Boolean;
6 (00000022) move-result-object v2
7 (00000024) sget-object v3, Ljava/lang/Boolean;->TRUE Ljava/lang/Boolean;
8 (00000028) invoke-virtual v2, v3, Ljava/lang/Boolean;->equals(Ljava/lang/Object;)Z
9 (0000002e) move-result v2
10 (00000030) if-eqz v2, 31 [ onCreate-BB@0x34 onCreate-BB@0x6e ]
onCreate-BB@0x34 :
11 (00000034) const-string v2, 'Emulator Detected!'
12 (00000038) const-string v3, 'Uninstalling ...'
13 (0000003c) invoke-static v2, v3, Landroid/util/Log;->d(Ljava/lang/String; Ljava/lang/String;)I
14 (00000042) new-instance v1, Landroid/content/Intent;
15 (00000046) const-string v2, 'android.intent.action.UNINSTALL_PACKAGE'
16 (0000004a) invoke-direct v1, v2, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
17 (00000050) const-string v2, 'package:com.versprite.crackme'
18 (00000054) invoke-static v2, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;
19 (0000005a) move-result-object v2
20 (0000005c) invoke-virtual v1, v2, Landroid/content/Intent;->setData(Landroid/net/Uri;)Landroid/content/Intent;
21 (00000062) invoke-virtual v4, v1, Lcom/versprite/crackme/KeyActivity;->startActivity(Landroid/content/Intent;)V
22 (00000068) invoke-virtual v4, Lcom/versprite/crackme/KeyActivity;->finish()V [ onCreate-BB@0x6e ]
onCreate-BB@0x6e :
23 (0000006e) invoke-virtual v4, Lcom/versprite/crackme/KeyActivity;->addListenerOnButton()V
24 (00000074) return-void
***************************************************************************
########## XREF
T: Lcom/versprite/crackme/emulator/Detect; <init> ()V 16
T: Lcom/versprite/crackme/emulator/Detect; detectEmulator ()Ljava/lang/Boolean; 1c
T: Lcom/versprite/crackme/KeyActivity; addListenerOnButton ()V 6e
####################
3 (00000012) new-instance v0, Lcom/versprite/crackme/emulator/Detect;
4 (00000016) invoke-direct v0, Lcom/versprite/crackme/emulator/Detect;-><init>()V
5 (0000001c) invoke-virtual v0, Lcom/versprite/crackme/emulator/Detect;->detectEmulator()Ljava/lang/Boolean;
6 (00000022) move-result-object v2
- new-instance vx, type
- Instantiates an object type and puts the reference of the newly created instance
- invoke-direct {parameters}, methodtocall
- Invokes the virtual method with parameters without the virtual method resolutions
- invoke-virtual {vx .. vy}, methodtocall
- Invokes method with a range of registers (First parameters is always "this")
- move-result-object vx
- Move the result value of the previous method invocation into vx
So what does this do?
3 (00000012) new-instance v0, Lcom/versprite/crackme/emulator/Detect;
4 (00000016) invoke-direct v0, Lcom/versprite/crackme/emulator/Detect;-><init>()V
5 (0000001c) invoke-virtual v0, Lcom/versprite/crackme/emulator/Detect;->detectEmulator()Ljava/lang/Boolean;
6 (00000022) move-result-object v2
How about this?
onCreate-BB@0x34 :
11 (00000034) const-string v2, 'Emulator Detected!'
12 (00000038) const-string v3, 'Uninstalling ...'
13 (0000003c) invoke-static v2, v3, Landroid/util/Log;->d(Ljava/lang/String; Ljava/lang/String;)I
14 (00000042) new-instance v1, Landroid/content/Intent;
15 (00000046) const-string v2, 'android.intent.action.UNINSTALL_PACKAGE'
16 (0000004a) invoke-direct v1, v2, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
17 (00000050) const-string v2, 'package:com.versprite.crackme'
18 (00000054) invoke-static v2, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;
19 (0000005a) move-result-object v2
20 (0000005c) invoke-virtual v1, v2, Landroid/content/Intent;->setData(Landroid/net/Uri;)Landroid/content/Intent;
21 (00000062) invoke-virtual v4, v1, Lcom/versprite/crackme/KeyActivity;->startActivity(Landroid/content/Intent;)V
22 (00000068) invoke-virtual v4, Lcom/versprite/crackme/KeyActivity;->finish()V [ onCreate-BB@0x6e ]
You can always call source() if you wanna!
In [32]: onCreate.source()
protected void onCreate(android.os.Bundle p5)
{
super.onCreate(p5);
this.setContentView(2130968599);
if (new com.versprite.crackme.emulator.Detect().detectEmulator().equals(Boolean.TRUE)) {
android.util.Log.d("Emulator Detected!", "Uninstalling ...");
android.content.Intent v1_1 = new android.content.Intent("android.intent.action.UNINSTALL_PACKAGE");
v1_1.setData(android.net.Uri.parse("package:com.versprite.crackme"));
this.startActivity(v1_1);
this.finish();
}
this.addListenerOnButton();
return;
}
-- What have we learned so far? --
- We have a class Detect() that has method called detectEmulator()
- If that returns TRUE
- The application will try to uninstall
-- Detect! --
In [33]: d.CLASS_Lcom_versprite_crackme_emulator_Detect.source()
package com.versprite.crackme.emulator;
public class Detect extends android.app.Application {
private Boolean d;
private String[] props;
public Detect()
{
Boolean v0_1 = new String[4];
v0_1[0] = "ro.secure";
v0_1[1] = "ro.product.name";
v0_1[2] = "ro.build.host";
v0_1[3] = "ro.build.tags";
this.props = v0_1;
this.d = Boolean.TRUE;
return;
}
public Boolean detectEmulator()
{
String[] v0 = this.props;
int v5 = v0.length;
int v4 = 0;
while (v4 < v5) {
String v8 = v0[v4];
try {
Class v10 = Class.forName("android.os.SystemProperties");
Class[] v6 = new Class[1];
v6[0] = String;
reflect.Method v3 = v10.getMethod("get", v6);
Object[] v7 = new Object[1];
v7[0] = v8;
boolean v12_8 = new Object[1];
v12_8[0] = v8;
String v9_1 = ((String) v3.invoke(v10, v12_8));
} catch (reflect.InvocationTargetException v1_1) {
v1_1.printStackTrace();
v4++;
} catch (reflect.InvocationTargetException v1_0) {
v1_0.printStackTrace();
} catch (reflect.InvocationTargetException v1_3) {
v1_3.printStackTrace();
} catch (reflect.InvocationTargetException v1_2) {
v1_2.printStackTrace();
}
if ((!v9_1.equals(Integer.valueOf(0))) && ((!v9_1.equals("buildbot.soft.genymobile.com")) && (!v9_1.equals("vbox86p")))) {
} else {
android.util.Log.d("Emulator Detected!", v9_1);
boolean v12_0 = this.d;
}
return v12_0;
}
v12_0 = Boolean.FALSE;
return v12_0;
}
}
In [34]:
-- We need to focus on the detectEmulator() method --
In [34]: detect = d.CLASS_Lcom_versprite_crackme_emulator_Detect.METHOD_detectEmulator
In [35]: detect.source()
public Boolean detectEmulator()
{
String[] v0 = this.props;
int v5 = v0.length;
int v4 = 0;
while (v4 < v5) {
String v8 = v0[v4];
try {
Class v10 = Class.forName("android.os.SystemProperties");
Class[] v6 = new Class[1];
v6[0] = String;
reflect.Method v3 = v10.getMethod("get", v6);
Object[] v7 = new Object[1];
v7[0] = v8;
boolean v12_8 = new Object[1];
v12_8[0] = v8;
String v9_1 = ((String) v3.invoke(v10, v12_8));
} catch (reflect.InvocationTargetException v1_1) {
v1_1.printStackTrace();
v4++;
} catch (reflect.InvocationTargetException v1_0) {
v1_0.printStackTrace();
} catch (reflect.InvocationTargetException v1_3) {
v1_3.printStackTrace();
} catch (reflect.InvocationTargetException v1_2) {
v1_2.printStackTrace();
}
if ((!v9_1.equals(Integer.valueOf(0))) && ((!v9_1.equals("buildbot.soft.genymobile.com")) && (!v9_1.equals("vbox86p")))) {
} else {
android.util.Log.d("Emulator Detected!", v9_1);
boolean v12_0 = this.d;
}
return v12_0;
}
v12_0 = Boolean.FALSE;
return v12_0;
}
This method is using Java Reflection to access the 'android.os.SystemProperties' class and corresponding get() method, to retrieve values from the system property store. The system property store is created by init, the first user-land application during the boot process for Android. The system properties contain configuration data that can be used to easily identify whether or not the system is being 'emulated'.
public Detect()
{
Boolean v0_1 = new String[4];
v0_1[0] = "ro.secure";
v0_1[1] = "ro.product.name";
v0_1[2] = "ro.build.host";
v0_1[3] = "ro.build.tags";
this.props = v0_1;
this.d = Boolean.TRUE;
return;
}
These are the target properties, which are being looped through, and their values inspected. So we really want to understand what happens in order for a jump to this index, to occur:
detectEmulator-BB@0x92 :
41 (00000092) const-string v12, 'Emulator Detected!'
42 (00000096) invoke-static v12, v9, Landroid/util/Log;->d(Ljava/lang/String; Ljava/lang/String;)I
43 (0000009c) iget-object v12, v14, Lcom/versprite/crackme/emulator/Detect;->d Ljava/lang/Boolean; [ detectEmulator-BB@0xa0 ]
The method is specifically checking these values: 'buildbot.soft.genymobile.com' and 'vbox86p'
detectEmulator-BB@0x0 :
0 (00000000) const-string v2, 'buildbot.soft.genymobile.com'
1 (00000004) const-string v11, 'vbox86p'
2 (00000008) iget-object v0, v14, Lcom/versprite/crackme/emulator/Detect;->props [Ljava/lang/String;
3 (0000000c) array-length v5, v0
4 (0000000e) const/4 v4, 0 [ detectEmulator-BB@0x10 ]
The 'source' isn't the most accurate representation of what is going on, and without diving into the byte code line by line, the assumption is the code is looping through the system properties and if a match is found against specific values, then emulation is being detected.
-- Patch it! --
We need to find out where we can patch out the bytecode to always return 'FALSE' back to the calling 'onCreate' method.
onCreate-BB@0x0 :
0 (00000000) invoke-super v4, v5, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
1 (00000006) const v2, 2130968599
2 (0000000c) invoke-virtual v4, v2, Lcom/versprite/crackme/KeyActivity;->setContentView(I)V
3 (00000012) new-instance v0, Lcom/versprite/crackme/emulator/Detect;
4 (00000016) invoke-direct v0, Lcom/versprite/crackme/emulator/Detect;-><init>()V
5 (0000001c) invoke-virtual v0, Lcom/versprite/crackme/emulator/Detect;->detectEmulator()Ljava/lang/Boolean;
6 (00000022) move-result-object v2
7 (00000024) sget-object v3, Ljava/lang/Boolean;->TRUE Ljava/lang/Boolean;
8 (00000028) invoke-virtual v2, v3, Ljava/lang/Boolean;->equals(Ljava/lang/Object;)Z
9 (0000002e) move-result v2
10 (00000030) if-eqz v2, 31 [ onCreate-BB@0x34 onCreate-BB@0x6e ]
What happens if change the instruction 'if-eqz'
to 'if-nez'
?
- if-eqz = is True
- if-nez = is False
In order to do this, we must modify the smali itself!
1.) Drop into the output directory from the apktool
➜ crackme git:(master) ✗ pwd
/Users/rotlogix/BSidesSF-2015/app/crackme
2.) CD into the appropriate smali directory
➜ crackme git:(master) ✗ ls
BuildConfig.smali R$anim.smali R$color.smali R$id.smali R$menu.smali R$style.smali emulator
KeyActivity$1.smali R$attr.smali R$dimen.smali R$integer.smali R$mipmap.smali R$styleable.smali generate
KeyActivity.smali R$bool.smali R$drawable.smali R$layout.smali R$string.smali R.smali
3.) Open up KeyActivity.smali in whatever editor you love to use, and find the onCreate() method
.method protected onCreate(Landroid/os/Bundle;)V
.locals 4
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 24
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 25
const v2, 0x7f040017
invoke-virtual {p0, v2}, Lcom/versprite/crackme/KeyActivity;->setContentView(I)V
.line 27
new-instance v0, Lcom/versprite/crackme/emulator/Detect;
invoke-direct {v0}, Lcom/versprite/crackme/emulator/Detect;-><init>()V
.line 29
.local v0, "detect":Lcom/versprite/crackme/emulator/Detect;
invoke-virtual {v0}, Lcom/versprite/crackme/emulator/Detect;->detectEmulator()Ljava/lang/Boolean;
move-result-object v2
sget-object v3, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
invoke-virtual {v2, v3}, Ljava/lang/Boolean;->equals(Ljava/lang/Object;)Z
move-result v2
if-eqz v2, :cond_0
4.) Modify the 'if-eqz'
instruction to 'if-nez'
invoke-virtual {v2, v3}, Ljava/lang/Boolean;->equals(Ljava/lang/Object;)Z
move-result v2
if-nez v2, :cond_0
.line 30
const-string v2, "Emulator Detected!"
5.) Save the file
We will need to rebuild the APK and sign it with an appropriate key in order to reinstall this back into our emulator.
6.) Build new APK
➜ app git:(master) ✗ java -jar ~/Tools/mobile/android/apktool/apktool_2.0.0rc4.jar b crackme -o modified_crackme.apk
I: Using Apktool 2.0.0-RC4
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Copying raw resources...
I: Building apk file...
7.) Sign new APK
➜ app git:(master) ✗ keytool -genkey -v -keystore crackme.keystore -alias crackme -keyalg RSA -keysize 2048 -validity 10000
➜ app git:(master) ✗ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore crackme.keystore modified_crackme.apk crackme
Make sure you have removed the old application from your emulator!
8.) Install new APK
➜ app git:(master) ✗ adb install modified_crackme.apk
Now when you start the application, you should see the 'Welcome to CrackME!'
!