Android decompilation and Secondary packaging
As an Android developer, it is essential to decompile other people's apk at work. Of course, the main purpose is to learn more, take the leader and make up for yourself. Today I will summarize some knowledge about Android decompilation and secondary packaging. The purpose of this article is to explain the principles and methods of decompilation and secondary packaging through examples, and then serve as the basis for subsequent explanations to prevent secondary packaging and App security, it does not encourage everyone to repackage others' apps to steal the fruits of others' work.
This article first introduces the use of several Android decompilation tools, and then implements the purpose of modifying the apk logic function by modifying the decompilation smali file without the need to know the source code.
There are three decompilation tools commonly used in Android: dex2jar, jd-gui, and apktool. The functions of these tools are as follows:
Dex2jar: Convert the classes. dex file in the apk to a jar file.
Jd-gui: view the jar file converted from dex2jar and display the decompiled Java source code in the form of an interface.
Apktool: decompile and generate the smali bytecode file to extract the resource file in the apk.
To clarify the problem as much as possible, we will implement a very simple example. First, create a project DecompileDemo and define a layout in MainActivity, which contains a Button. Click it to print a piece of log.
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(this); } @Override public void onClick(View v) { Log.d(TAG,"Button is clicked"); }}
Decompress the apk generated by this project compilation, and put classes. dex in the directory of dex2jar, and then execute the command
The class-dex2jar.jar file is generated under the current directory
Then open jd-gui, drag the class-dex2jar.jar file in, you can see the decompiled source code.
We can see that the decompiled code is not much different from the original code. The main difference is that all the original resource references are converted into numbers.
Next we will modify the apk content.
First we copy the apk to the apktool directory and execute the command apktool d app-release.apk.
The generated directory contains the smali folder.
Then find our main class MainActivity. smali. The file content is as follows:
.class public Lcom/viclee/decompiledemo/MainActivity;.super Landroid/support/v7/app/AppCompatActivity;.source "MainActivity.java"# interfaces.implements Landroid/view/View$OnClickListener;?# static fields.field private static final TAG:Ljava/lang/String; = "MainActivity"# instance fields.field private btn:Landroid/widget/Button;# direct methods.method public constructor
()V .locals 0 .prologue .line 9 invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;->
()V return-void.end method# virtual methods.method public onClick(Landroid/view/View;)V .locals 2 .param p1, "v" # Landroid/view/View; .prologue .line 23 const-string v0, "MainActivity" const-string v1, "Button is clicked" invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I .line 24 return-void.end method.method protected onCreate(Landroid/os/Bundle;)V .locals 1 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prologue .line 14 invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V .line 15 const v0, 0x7f040019 invoke-virtual {p0, v0}, Lcom/viclee/decompiledemo/MainActivity;->setContentView(I)V .line 17 const v0, 0x7f0c0050 invoke-virtual {p0, v0}, Lcom/viclee/decompiledemo/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/viclee/decompiledemo/MainActivity;->btn:Landroid/widget/Button; .line 18 iget-object v0, p0, Lcom/viclee/decompiledemo/MainActivity;->btn:Landroid/widget/Button; invoke-virtual {v0, p0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 19 return-void.end method
Lines 36-40 are the locations where logs are printed, and the file content is clear. The meaning of each region is as follows:
. Class name
. Super parent class name
. Source File Name
. Implements interface implemented by this class
. Field member variable
. Method
Create a new project and implement the Code to be replaced in this project. Here we want to replace the place where the log is printed in the original project with a Toast.
Public class MainActivity extends AppCompatActivity {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); showToast ();} public void showToast () {Toast. makeText (this, "I modified it after decompiling. ", Toast. LENGTH_LONG). show ();}}
Then run the apktool command as before. The generated smali file is as follows:
.class public Lcom/viclee/decompiledemo/MainActivity;.super Landroid/support/v7/app/AppCompatActivity;.source "MainActivity.java"# direct methods.method public constructor
()V .locals 0 .prologue .line 7 invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;->
()V return-void.end method# virtual methods.method protected onCreate(Landroid/os/Bundle;)V .locals 1 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prologue .line 10 invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V .line 11 const v0, 0x7f040019 invoke-virtual {p0, v0}, Lcom/viclee/decompiledemo/MainActivity;->setContentView(I)V .line 13 invoke-virtual {p0}, Lcom/viclee/decompiledemo/MainActivity;->showToast()V .line 14 return-void.end method.method public showToast()V .locals 2 .prologue .line 17 const-string v0, "\u6211\u662f\u53cd\u7f16\u8bd1\u540e\u8fdb\u884c\u7684\u4fee\u6539\u3002" const/4 v1, 0x1 invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; move-result-object v0 invoke-virtual {v0}, Landroid/widget/Toast;->show()V .line 18 return-void.end method
In the above Code, lines 33 and 39-56 are the code section of the pop-up Toast. Copy the entire showToast method to the smali file of the original project. Pay special attention to modifying the line number. This line number indicates the line number of the Code in the original Java file, you need to refer to the row numbers of the two smali files to modify. In my opinion, you only need to ensure that the row numbers in the method are not in disorder and that the row numbers between methods do not conflict. Then, you need to replace the code for printing logs in the original project with the code for displaying Toast, that is, change lines 36-40 in the original smali file to lines 33 and 39-56 in the new project. The modified content is as follows, mainly focusing on the differences between lines 36 and lines 75-91 in the following content and the original smali file.
.class public Lcom/viclee/decompiledemo/MainActivity;.super Landroid/support/v7/app/AppCompatActivity;.source "MainActivity.java"# interfaces.implements Landroid/view/View$OnClickListener;# static fields.field private static final TAG:Ljava/lang/String; = "MainActivity"# instance fields.field private btn:Landroid/widget/Button;# direct methods.method public constructor
()V .locals 0 .prologue .line 9 invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;->
()V return-void.end method# virtual methods.method public onClick(Landroid/view/View;)V .locals 2 .param p1, "v" # Landroid/view/View; .prologue .line 23 invoke-virtual {p0}, Lcom/viclee/decompiledemo/MainActivity;->showToast()V .line 24 return-void.end method.method protected onCreate(Landroid/os/Bundle;)V .locals 1 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prologue .line 14 invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V .line 15 const v0, 0x7f040019 invoke-virtual {p0, v0}, Lcom/viclee/decompiledemo/MainActivity;->setContentView(I)V .line 17 const v0, 0x7f0c0050 invoke-virtual {p0, v0}, Lcom/viclee/decompiledemo/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/viclee/decompiledemo/MainActivity;->btn:Landroid/widget/Button; .line 18 iget-object v0, p0, Lcom/viclee/decompiledemo/MainActivity;->btn:Landroid/widget/Button; invoke-virtual {v0, p0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 19 return-void.end method.method public showToast()V .locals 2 .prologue .line 27 const-string v0, "\u6211\u662f\u53cd\u7f16\u8bd1\u540e\u8fdb\u884c\u7684\u4fee\u6539\u3002" const/4 v1, 0x1 invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; move-result-object v0 invoke-virtual {v0}, Landroid/widget/Toast;->show()V .line 28 return-void
Then we need to repackage the modified file directory and run the apktool B app-release command to generate two folders under the app-releae directory: the build folder contains some intermediate files (classes. the dist folder contains the re-packaged apk file.
Remember to sign the generated apk. Otherwise, an error will be reported during installation. Execute the following command line:
Jarsigner-verbose-keystore viclee. keystore-signedjar app-release-signed.apk app-release.apk viclee. keystore
-Verbose outputs Signature Details
-Keystore: Specifies the storage path of the key pair.
-The three parameters after signedjar are the signed apk, unsigned apk, and key pair alias.
After installing the signed apk, click the button and the Toast is displayed. The content is consistent with what we set, indicating that the modification is successful.
We have noticed that the modification of the smali file is not directly modified on the file. After all, it is very difficult to directly modify the smali file because of its poor readability. Our solution is to create a new project and implement the Code that needs to be added. We 'd better combine it into a separate method (for easy replacement), and then decompile the apk generated by packaging the new project, obtain the corresponding smali file, and replace the original smali file with the content. This modification method reduces the difficulty of modification and the risk of making mistakes.
In addition, you can modify the resources after decompiling the apk, modify the decompiled resource files, and repackage, sign, and install the files according to the previous method. The following two pages show the comparison between the modified and modified pages.