Introduction
For Android engineers, understanding how to decompile can enhance their understanding of the Android system and also consider how to protect their APK from being decompiled.
For the general public, many ready-made tools can help us easily decompile APKs and see Java source code, satisfying our curiosity.
This article only introduces the use of some tools, suitable for beginners to watch. If you want to understand more underlying knowledge, you can refer to the extended reading attached at the end of the article.
Preparations
First, we need an APK to be cracked. Simply build one with any tool you are familiar with.
The structure is very simple, just a MainActivity
and two TextViews
.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text = (TextView)findViewById(R.id.text);
text.setText("Taiwan No1");
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
After installing it on the phone, you will see this screen:
Hands-on
Okay, this is the APK we want to test.
Then you need some very useful tools:
I won’t go into how to install them. You can read the documentation or search the internet for a bunch of answers.
apktool
is used to unpack the APK, which can decompile the APK and see the smali
files and resource
.
dex2jar
can convert the APK to a jar, and then use jd-gui
to view the Java code.
Then we open the terminal, go to the directory of the demo APK just now, and execute apktool d APKNAME.apk
After execution, a APKNAME
folder will be automatically generated, which contains the decompiled things.
.
├── AndroidManifest.xml
├── apktool.yml
├── original
├── res
└── smali
One of the more noteworthy folders is the smali
folder, which is actually your source code, just in a different format. You can find your MainActivity.java
in the smali
folder, with the following contents: (It may look strange, but if you look closely, you’ll find that it’s not that difficult to understand.)
.class public Lapktest/huli/com/apkdecompile/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"
# direct methods
.method public constructor <init>()V
.locals 0
.prologue
.line 8
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
return-void
.end method
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 2
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 12
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 13
const v1, 0x7f040019
invoke-virtual {p0, v1}, Lapktest/huli/com/apkdecompile/MainActivity;->setContentView(I)V
.line 14
const v1, 0x7f0c0050
invoke-virtual {p0, v1}, Lapktest/huli/com/apkdecompile/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/TextView;
.line 15
.local v0, "text":Landroid/widget/TextView;
const-string v1, "Taiwan No1"
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 16
return-void
.end method
You can compare this with the Java code you wrote earlier and see that it’s just a different format.
setContentView(R.layout.activity_main);
Is actually equivalent to:
.line 13
const v1, 0x7f040019
invoke-virtual {p0, v1}, Lapktest/huli/com/apkdecompile/MainActivity;->setContentView(I)V
You may wonder where 0x7f040019
comes from. In fact, you can find the answer in the res/values/public.xml
file:
<public type="layout" name="activity_main" id="0x7f040019" />
At this point, you should have a rough idea of the Android compilation process:
- Compress and process all resource files and package them together to generate an
id-to-memory-location mapping
table. - Replace all
R.xx.xxx
in the code with actual memory locations using the table generated earlier. - Convert Java code to smali code (similar to converting C code to assembly code).
Modification
In the smali
code above, there is the following section:
.line 15
.local v0, "text":Landroid/widget/TextView;
const-string v1, "Taiwan No1"
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
Let’s replace Taiwan No1
with T@iw@n n0!
.
Do you remember the other TextView
that used R.string.hello_world
?
In res/values/strings.xml
, you can find the definition of this string:
<string name="hello_world">Hello world!</string>
Change it to:
<string name="hello_world">HELLO WORLD</string>
After making sure everything has been changed, you can “assemble” the code again.
Do you remember the decompilation command we used earlier? apktool d APK_NAME.apk
Here, d
means decompile
, so if you want to reverse assemble it, it’s b
, build
.
apktool b APK_NAME
After executing it, you can find an apk in APK_NAME/dist
.
Note that this apk has not been signed, so it cannot be installed.
You can generate a keystore or find an existing one to sign it.jarsigner -verbose -digestalg SHA1 -keystore ~/KEY.keystore APK_NAME.apk KEY_ALIAS
After installation, you will see this screen:
Yes! It’s that simple. An apk has been modified like this.
But smali
code is hard to understand. Can we directly see the java code?
This is where the recommended tools dex2jar
and jd-gui
come in handy.
The former can turn an apk into a jar, and the latter can open a jar and display the java code.
The combination of the two allows you to see the original code directly.
After downloading dex2jar
, there will be a bunch of shell scripts. dex2jar
is the one we want.
./d2j-dex2jar.sh app.apk
After execution, there will be a jar. Open it with jd-gui, and you will see your code at a glance.
Summary
People who have not touched decompilation may be surprised: What! It’s so easy to modify an apk!
Yes, it’s that simple, and this is just a very basic example.
In fact, you can also add new code and resources (images, sounds, etc.).
That is to say, you can not only modify but also extend the original apk.
But there are also methods to prevent unscrupulous people from decompiling apk.
For example, shell, obfuscation, dynamic loading, etc.
I will introduce them later if there is a chance.
Further reading
- Android Decompilation and Anti-Decompilation
- [Android] Code Obfuscation (ProGuard) and Decompilation
- [Android] Decompilation Cracking Android’s apk installation file
- Common tools and usage methods for decompilation
- Smali–Dalvik virtual machine instruction language–>[android_smali syntax learning one]
- android decompilation-smali syntax
Comments