上一篇博客,介紹了反編譯後如何修改資源文件,修改資源文件幾乎不會設計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,看一下效果: