上一篇博客,介绍了反编译后如何修改资源文件,修改资源文件几乎不会设计Java源代码的修改,只需要修改xml文件。接下来的博客,将会介绍和总结一下,如何修改原有的逻辑和功能代码。与修改资源文件不同,修改原有的功能逻辑代码将涉及到smali代码的修改。smali的语法我个人认为不需要完全掌握,我也只是研究了那么几天时间。
我们还是用上一篇博客用到的apk。先看一下我们上次修改的样子:
接下来,看一下,如何实现在反编译后的源代码中增加Toast显示。我们要实现的修改是:点击按钮1,弹出Toast(You clicked button one.)。
一、为Button1注册OnclickListener
首先,我们回忆一下,在Java代码中为按钮增加点击事件时是如何操作的?
(1)定义一个Button,Java代码如下:
private Button btn1;
(2)在注册监听器前,先findViewById,否则空指针,Java代码如下:
btn1 = findViewById(R.id.btn_1);
(3)注册监听器,做自己想做的操作,Java代码如下:
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
在反编译后的smali源码中,我们仍然需要按照这些步骤为Button增加点击事件。那么,我们如何操作呢?很简单,让我们一步一步来。首先,在Android Killer中打开MainActivity的smali代码:
.class public Ltudu/mreversedemo/MainActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "MainActivity.java"
# direct methods
.method public constructor <init>()V
.locals 0
.line 6
invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V
return-void
.end method
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 0
.line 10
invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const p1, 0x7f09001b
.line 11
invoke-virtual {p0, p1}, Ltudu/mreversedemo/MainActivity;->setContentView(I)V
return-void
.end method
(1)定义一个Button对象
打开MainActivity.smali文件,在# direct methods这一段注释上面增加如下smali代码。这段代码的意意思是,声明一个private的变量btn1,类型是Button。这里需要注意的是:Lxxx/xxx/xxx,定义Object前面是需要使用L:
.field private btn1:Landroid/widget/Button;
(2)findViewById
我在代码中使用“#”增加了部分注释,在return-void之前增加如下smali代码:
# button的findviewbyid start
const p1, 0x7f070022
invoke-virtual {p0, p1}, Ltudu/mreversedemo/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object p1
check-cast p1, Landroid/widget/Button;
iput-object p1, p0, Ltudu/mreversedemo/MainActivity;->btn1:Landroid/widget/Button;
#button的findviewbyid end
注意:这里的“0x7f070022”,是在R$id.smali和public.xml中的id,可以搜索“btn_1”,查找这个id,搜索结果如下图所示:
(3)注册监听器
在上一步findViewById增加的代码下面,增加如下代码。下面这段代码就是注册OnClickListener监听器:
#注册监听器 start
iget-object p1, p0, Ltudu/mreversedemo/MainActivity;->btn1:Landroid/widget/Button;
new-instance v0, Ltudu/mreversedemo/MainActivity$1;
invoke-direct {v0, p0}, Ltudu/mreversedemo/MainActivity$1;-><init>(Ltudu/mreversedemo/MainActivity;)V
invoke-virtual {p1, v0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
#注册监听器end
在注册监听器代码中,我们可以看到MainActivity$1,这是我们接下来需要新增加的一个smali文件。这里需要注意的是,因为我们为Button增加了监听器,也就是OnClickListener接口,我们需要对MainActivity的OnCreate方法稍作修改。需要把.locals 1修改为.locals 2。关于.locals,我在这里暂时不详细解释。这里比较通俗的的原则就是:我们的MainActivityXXX定义了几个,.locals就必须大于等于几。
.locals 2
(4)增加MainActivity$1.smali文件
那么,如何增加一个文件?其实我们在上一篇博客已经说过。复制MainActivity.smali,并且命名为MainActivity$1。回到Android Killer,点击刷新按钮,如下所示: MianActivity$1这个文件的作用是:实现我们的OnClickListener接口。接下来我们要在OncClick方法中弹Toast,也是在这个文件中去实现。MainActivity$1的代码如下:
.class Ltudu/mreversedemo/MainActivity$1;
.super Ljava/lang/Object;
.source "MainActivity.java"
# interfaces
.implements Landroid/view/View$OnClickListener;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Ltudu/mreversedemo/MainActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Ltudu/mreversedemo/MainActivity;
# direct methods
.method constructor <init>(Ltudu/mreversedemo/MainActivity;)V
.locals 0
iput-object p1, p0, Ltudu/mreversedemo/MainActivity$1;->this$0:Ltudu/mreversedemo/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 0
return-void
.end method
(5)增加Toast代码
接下来,在MainActivity$1中实现我们弹Toast的需求。修改onClick中的代码如下:
.locals 2
iget-object p1, p0, Ltudu/mreversedemo/MainActivity$1;->this$0:Ltudu/mreversedemo/MainActivity;
const-string v0, "You clicked button one."
const/4 v1, 0x0
invoke-static {p1, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object p1
invoke-virtual {p1}, Landroid/widget/Toast;->show()V
return-void
通过以上五个步骤,我们完成了点击Button弹出Toast的修改,我们是通过修改反编译后的smali代码完成的。保存我们的所有修改,编译并且运行一下apk,看一下效果: