Android 反編譯之修改Smali 文件輸出日志

本篇是Android反編譯系列的 第五篇, 前四篇的地址在這里
第一篇 Apktool安裝
第二篇 Apktool 基本使用方法
第三篇 App漢化與二次簽名
第四篇 修改Smali文件,定位關(guān)鍵點(diǎn)


承接上篇Android反編譯之修改Smali文件,本篇主要分析如何在 Smali文件中輸出日志,幫助我們理解App 業(yè)務(wù)處理邏輯。

1.我們先寫(xiě)這樣一個(gè)簡(jiǎn)單的demo

smaliLogDemoApp.gif

順便安利一下Android 上gif 截圖的軟件LICEcap,免費(fèi)開(kāi)源,秋百萬(wàn)大神推薦

App 登陸界面,對(duì)用戶名和密碼做簡(jiǎn)單的邏輯驗(yàn)證,同時(shí)有一個(gè)FloatingActionBar,點(diǎn)擊之后顯示Snackbar。

我們現(xiàn)在要做的,在登陸驗(yàn)證的方法里,添加日志輸出,分別輸出登陸成功,登陸失敗。在FloatingActionBar 的響應(yīng)事件中,添加日志輸出。

2.反編譯SmaliLogDemo

demo 比較簡(jiǎn)單,我這里直接給出反編譯之后的 Smali 文件。

.class public Lcom/imesong/smalilogdemo/MainActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "MainActivity.java"


# instance fields
.field private login:Landroid/widget/Button;

.field private nameEdit:Landroid/support/v7/widget/AppCompatEditText;

.field private passwdEdit:Landroid/support/v7/widget/AppCompatEditText;


# direct methods
.method public constructor <init>()V
    .locals 0

    .prologue
    .line 16
    invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V

    return-void
.end method

.method static synthetic access$000(Lcom/imesong/smalilogdemo/MainActivity;)Landroid/support/v7/widget/AppCompatEditText;
    .locals 1
    .param p0, "x0"    # Lcom/imesong/smalilogdemo/MainActivity;

    .prologue
    .line 16
    iget-object v0, p0, Lcom/imesong/smalilogdemo/MainActivity;->nameEdit:Landroid/support/v7/widget/AppCompatEditText;

    return-object v0
.end method

.method static synthetic access$100(Lcom/imesong/smalilogdemo/MainActivity;)Landroid/support/v7/widget/AppCompatEditText;
    .locals 1
    .param p0, "x0"    # Lcom/imesong/smalilogdemo/MainActivity;

    .prologue
    .line 16
    iget-object v0, p0, Lcom/imesong/smalilogdemo/MainActivity;->passwdEdit:Landroid/support/v7/widget/AppCompatEditText;

    return-object v0
.end method

.method static synthetic access$200(Lcom/imesong/smalilogdemo/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z
    .locals 1
    .param p0, "x0"    # Lcom/imesong/smalilogdemo/MainActivity;
    .param p1, "x1"    # Ljava/lang/String;
    .param p2, "x2"    # Ljava/lang/String;

    .prologue
    .line 16
    invoke-direct {p0, p1, p2}, Lcom/imesong/smalilogdemo/MainActivity;->isLogingInfoValid(Ljava/lang/String;Ljava/lang/String;)Z

    move-result v0

    return v0
.end method

.method private isLogingInfoValid(Ljava/lang/String;Ljava/lang/String;)Z
    .locals 4
    .param p1, "name"    # Ljava/lang/String;
    .param p2, "passwd"    # Ljava/lang/String;

    .prologue
    const/4 v3, 0x0

    .line 59
    const/4 v0, 0x0

    .line 60
    .local v0, "isValid":Z
    invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z

    move-result v1

    if-nez v1, :cond_0

    invoke-static {p2}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z

    move-result v1

    if-eqz v1, :cond_1

    .line 61
    :cond_0
    const/4 v0, 0x0

    .line 62
    const-string v1, "\u7528\u6237\u540d\u3001\u5bc6\u7801\u4e0d\u80fd\u4e3a\u7a7a"

    invoke-static {p0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v1

    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    .line 69
    :goto_0
    return v0
    
    .line 63
    :cond_1
    invoke-virtual {p2}, Ljava/lang/String;->length()I

    move-result v1

    const/4 v2, 0x6

    if-ge v1, v2, :cond_2

    .line 64
    const/4 v0, 0x0

    .line 65
    const-string v1, "\u5bc6\u7801\u957f\u5ea6\u5c0f\u4e8e6"

    invoke-static {p0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v1

    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    goto :goto_0

    .line 67
    :cond_2
    const/4 v0, 0x1

    goto :goto_0
.end method


# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 4
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    .prologue
    .line 24
    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

    .line 25
    const v2, 0x7f040019

    invoke-virtual {p0, v2}, Lcom/imesong/smalilogdemo/MainActivity;->setContentView(I)V

    .line 26
    const v2, 0x7f0c0069

    invoke-virtual {p0, v2}, Lcom/imesong/smalilogdemo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v1

    check-cast v1, Landroid/support/v7/widget/Toolbar;

    .line 27
    .local v1, "toolbar":Landroid/support/v7/widget/Toolbar;
    invoke-virtual {p0, v1}, Lcom/imesong/smalilogdemo/MainActivity;->setSupportActionBar(Landroid/support/v7/widget/Toolbar;)V

    .line 29
    const v2, 0x7f0c006a

    invoke-virtual {p0, v2}, Lcom/imesong/smalilogdemo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/support/design/widget/FloatingActionButton;

    .line 30
    .local v0, "fab":Landroid/support/design/widget/FloatingActionButton;
    new-instance v2, Lcom/imesong/smalilogdemo/MainActivity$1;

    invoke-direct {v2, p0}, Lcom/imesong/smalilogdemo/MainActivity$1;-><init>(Lcom/imesong/smalilogdemo/MainActivity;)V

    invoke-virtual {v0, v2}, Landroid/support/design/widget/FloatingActionButton;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    .line 38
    const v2, 0x7f0c006b

    invoke-virtual {p0, v2}, Lcom/imesong/smalilogdemo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v2

    check-cast v2, Landroid/support/v7/widget/AppCompatEditText;

    iput-object v2, p0, Lcom/imesong/smalilogdemo/MainActivity;->nameEdit:Landroid/support/v7/widget/AppCompatEditText;

    .line 39
    const v2, 0x7f0c006c

    invoke-virtual {p0, v2}, Lcom/imesong/smalilogdemo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v2

    check-cast v2, Landroid/support/v7/widget/AppCompatEditText;

    iput-object v2, p0, Lcom/imesong/smalilogdemo/MainActivity;->passwdEdit:Landroid/support/v7/widget/AppCompatEditText;

    .line 41
    const v2, 0x7f0c006d

    invoke-virtual {p0, v2}, Lcom/imesong/smalilogdemo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v2

    check-cast v2, Landroid/widget/Button;

    iput-object v2, p0, Lcom/imesong/smalilogdemo/MainActivity;->login:Landroid/widget/Button;

    .line 43
    iget-object v2, p0, Lcom/imesong/smalilogdemo/MainActivity;->login:Landroid/widget/Button;

    new-instance v3, Lcom/imesong/smalilogdemo/MainActivity$2;

    invoke-direct {v3, p0}, Lcom/imesong/smalilogdemo/MainActivity$2;-><init>(Lcom/imesong/smalilogdemo/MainActivity;)V

    invoke-virtual {v2, v3}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    .line 56
    return-void
.end method

代碼沒(méi)有混淆,看起來(lái)很清楚。類名 是 MainActivity.java,有三個(gè)成員變量,一個(gè) Button,兩個(gè) AppCompatEditText。下面還有 isLogingInfoValid 方法,有兩個(gè)參數(shù),分別是 name 和 passwd。最后的是 onCreate 方法。不過(guò),大致瀏覽之后,好像沒(méi)有發(fā)現(xiàn) FloatingActionBar 的蹤跡啊,不要著急,我們先把登陸邏輯判斷的日志處理好,回過(guò)頭來(lái)再查找 FloatingActionBar 也不遲。

我們先分析 isLogingInfValid 的處理邏輯。

方法第一行 .logcals ,表示使用4個(gè)寄存器,.param p1 表示形參 name, .param p2 表示形參 passwd。緊接著 .prologue 表示方法執(zhí)行開(kāi)始

#定義變量 v3,并賦值為0 
#smali 中注釋使用#
const/4 v3,0x0

#定義Boolean變量 isValid,默認(rèn)為false
.local v0,"isValid":Z

#調(diào)用TextUtils.isEmpty(string) 方法
#invoke-static ,調(diào)用一個(gè)static的靜態(tài)方法
#{p1} 是 static 方法的入?yún)?#Landroid/text/TextUtils 是這個(gè)方法的決定路徑,L表示這是一個(gè)Object,Smali中只有兩種類型 基礎(chǔ)類型和引用類型(Object,使用L表示)
#->這個(gè)表示調(diào)用isEmpty 方法,熟悉腳本語(yǔ)言的開(kāi)發(fā),應(yīng)該很熟悉,小括號(hào)中定義入?yún)⒌念愋?,使?';' 結(jié)尾
#最后的 **Z** 表示代表返回值為Boolean 類型。
#這樣完成了TextUtils.isEmpty(name) 方法的調(diào)用
invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z

#將結(jié)果賦值給 v1
move-result v1

#如果 v1 != 0 跳轉(zhuǎn)到 :cond_0
#如果 v1==true 跳轉(zhuǎn)到 :cond_0,如果是 false ,接著往下走
if-nez v1, :cond_0

#賦值 v0 == 0
:cond_0 
const/4 v0, 0x0
#下面緊接著定義 變量 v1,調(diào)用 Toast.make(context,"string",Toast.SHORT).show();方法
#之后執(zhí)行:goto_0 返回 v0 的值。
#這個(gè)邏輯走下來(lái),說(shuō)明如果第一個(gè)參數(shù),用戶名為null,直接彈出Toast,返回false,符合我們都看到的現(xiàn)象。

如果要在用戶名為空的時(shí)候添加一條日志怎么添加呢?下面我們看下如何添加日志。

1.修改寄存器數(shù)量
如果要添加日志,我們要輸出我們想要顯示的信息,這些也是要申請(qǐng)寄存器存放。
.logcal 4 修改為 .logcal 5

2.新增變量,定義我們要輸出的信息
為了方便,這里講 Tag 和信息定義相同,如果不想定義一致,可以再增加一個(gè)寄存器。

const-string v4 ,"nameNull"

3.調(diào)用Log.d("info","info");方法。

#注意參數(shù),返回值必須完全正確
invoke-static {v4,v4};Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

這樣我們就完成了name 為空時(shí)的日志添加。我們重新打包,簽名,運(yùn)行看下結(jié)果。

apktool b smalilogdemo -o smalilogdemo_unsigned.apk

執(zhí)行之后,卻遇到下面的問(wèn)題

I: Using Apktool 2.0.3
I: Checking whether sources has changed...
I: Checking whether resources has changed...
I: Building resources...
/Users/ericsong/Documents/android_decode/crack/smalilogdemo/res/layout-v21/abc_screen_toolbar.xml:5: error: No resource identifier found for attribute 'touchscreenBlocksFocus' in package 'android'

layout-v21 里面有個(gè)屬性,我們現(xiàn)在的framework-resource 不支持,簡(jiǎn)單粗暴的解決方法,刪除 layout-v21 文件夾。刪除掉這些異常的Resource 文件之后,我們就可以正常打包了。

暫時(shí)沒(méi)有找到比較好的回編譯的方法,如果有新的發(fā)現(xiàn),會(huì)及時(shí)更新

如果每個(gè)想要添加日志的地方,都這樣修改,感覺(jué)還是很繁瑣,能不能偷懶下,把日志輸出的Smali 語(yǔ)法封裝成一個(gè)文件,我們只需要調(diào)用這個(gè)文件就可以了呢?這樣當(dāng)然是可以的。

下面貼出 LogUtil.smali 文件

.class public LLogUtil;
.super Ljava/lang/Object;
.source "LLogUtil.java"
.method public static d(Ljava/lang/String;)V
    .locals 1
    .prologue
    const-string v0,"SmaliLogDemo"
    invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
 .end method

 .method public static d()V
    .locals 1
    .prologue
    const-string v0,"SmaliLogDemo"
    invoke-static {v0,v0},Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
 .end method
 
 .method public static e(Ljava/lang/String;)V
    .locals 1
    .prologue
    const-string v0, "SmaliLogDemo"
    invoke-static {v0, p0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method
.method public static I(I)V
    .locals 2
 
    .prologue
 
    const-string v0, "SmaliLogDemo_I"
 
    invoke-static {p0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
 
    move-result-object v1
 
    invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
 
    return-void
.end method

#打印Long 參數(shù)
.method public static d(J)V
    .locals 2 
    .prologue
    const-string v0, "SmaliLogDemo_Long"
    invoke-static {p0, p1}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;
    move-result-object v1
    invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method


#無(wú)參數(shù) System.out.println("SmaliLogDemo_out")
.method public static p()V
    .locals 2
    .prologue
    const-string v0,"SmaliLogDemo_out"
    sget-object v1,Ljava/lang/System;->out:Ljava/io/PrintStream;
    invoke-virtual {v1,v0},Ljava/io/PrintStream;->println(Ljava/langString;)V
    return-void
.end method

#打印boolean
.method public static p(Z)V
    .locals 2
    .prologue
    const-string v0,"SmaliLogDemo_out_boolean"
    sget-object v1,Ljava/lang/System;->out:Ljava/io/PrintStream;
    invoke-virtual {v1,p0},Ljava/io/PrintStream;->println(Z)V
    return-void
.end method

現(xiàn)在的封裝,基本上滿足日常的需求,后面會(huì)持續(xù)完善。

我們?cè)俳o出添加日志之后,MainActivity 中 isLogingInfoValid() 的代碼

.method private isLogingInfoValid(Ljava/lang/String;Ljava/lang/String;)Z
    .locals 5
    .param p1, "name"    # Ljava/lang/String;
    .param p2, "passwd"    # Ljava/lang/String;

    .prologue
    const/4 v3, 0x0
    const-string v4,"isLogingInfoValid"
    invoke-static {v4},LLogUtil;->d(Ljava/lang/String;)V
    .line 58
    const/4 v0, 0x0

    .line 59
    .local v0, "isValid":Z
    invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z

    move-result v1

    if-nez v1, :cond_0

    invoke-static {p2}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z

    move-result v1

    if-eqz v1, :cond_1

    .line 60
    :cond_0
    const/4 v0, 0x0
    const-string v4,"isLogingInfoValid11111111111"
    invoke-static {v4},LLogUtil;->d(Ljava/lang/String;)V
    .line 61
    const-string v1, "\u7528\u6237\u540d\u3001\u5bc6\u7801\u4e0d\u80fd\u4e3a\u7a7a"

    invoke-static {p0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v1

    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    .line 68
    :goto_0
    return v0

    .line 62
    :cond_1
    invoke-virtual {p2}, Ljava/lang/String;->length()I

    move-result v1

    const/4 v2, 0x6

    if-ge v1, v2, :cond_2

    .line 63
    const/4 v0, 0x0
    const-string v4,"isLogingInfoValid2222222222222"
    invoke-static {v4},LLogUtil;->d(Ljava/lang/String;)V
    .line 64
    const-string v1, "\u5bc6\u7801\u957f\u5ea6\u5c0f\u4e8e6"

    invoke-static {p0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v1

    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    goto :goto_0

    .line 66
    :cond_2
    const-string v4,"isLogingInfoValid33333333333"
    invoke-static {v4},LLogUtil;->d(Ljava/lang/String;)V
    const/4 v0, 0x1

    goto :goto_0
.end method

里面一共打印了四組日志。

我們?cè)倏聪?onClick 響應(yīng)事件中的日志信息。

# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 4
    .param p1, "v"    # Landroid/view/View;

    .prologue
    .line 47
    iget-object v0, p0, Lcom/imesong/smalilogdemo/MainActivity$2;->this$0:Lcom/imesong/smalilogdemo/MainActivity;

    iget-object v1, p0, Lcom/imesong/smalilogdemo/MainActivity$2;->this$0:Lcom/imesong/smalilogdemo/MainActivity;

    # getter for: Lcom/imesong/smalilogdemo/MainActivity;->nameEdit:Landroid/support/v7/widget/AppCompatEditText;
    invoke-static {v1}, Lcom/imesong/smalilogdemo/MainActivity;->access$000(Lcom/imesong/smalilogdemo/MainActivity;)Landroid/support/v7/widget/AppCompatEditText;

    move-result-object v1

    invoke-virtual {v1}, Landroid/support/v7/widget/AppCompatEditText;->getText()Landroid/text/Editable;

    move-result-object v1

    invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String;

    move-result-object v1

    iget-object v2, p0, Lcom/imesong/smalilogdemo/MainActivity$2;->this$0:Lcom/imesong/smalilogdemo/MainActivity;

    # getter for: Lcom/imesong/smalilogdemo/MainActivity;->passwdEdit:Landroid/support/v7/widget/AppCompatEditText;
    invoke-static {v2}, Lcom/imesong/smalilogdemo/MainActivity;->access$100(Lcom/imesong/smalilogdemo/MainActivity;)Landroid/support/v7/widget/AppCompatEditText;

    move-result-object v2

    invoke-virtual {v2}, Landroid/support/v7/widget/AppCompatEditText;->getText()Landroid/text/Editable;

    move-result-object v2

    invoke-virtual {v2}, Ljava/lang/Object;->toString()Ljava/lang/String;

    move-result-object v2

    # invokes: Lcom/imesong/smalilogdemo/MainActivity;->isLogingInfoValid(Ljava/lang/String;Ljava/lang/String;)Z
    invoke-static {v0, v1, v2}, Lcom/imesong/smalilogdemo/MainActivity;->access$200(Lcom/imesong/smalilogdemo/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z

    move-result v0

    if-eqz v0, :cond_0

    .line 48
    const-string v3,"commit onclick"
    invoke-static {v3},LLogUtil;->e(Ljava/lang/String;)V
    iget-object v0, p0, Lcom/imesong/smalilogdemo/MainActivity$2;->this$0:Lcom/imesong/smalilogdemo/MainActivity;

    const-string v1, "\u767b\u9646\u6210\u529f"

    const/4 v2, 0x0

    invoke-static {v0, v1, v2}, 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 53
    :cond_0
    return-void
.end method

最后 看下 效果圖

smaliLogDemoAppLog.gif

關(guān)于SmaliLogDemo 的理解,就到這里,最后附上 項(xiàng)目代碼和Smali 文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,021評(píng)論 25 709
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語(yǔ)言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲(chóng)de夢(mèng)閱讀 100,658評(píng)論 9 468
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,272評(píng)論 6 342
  • 社會(huì)可以是美好的,可以是殘酷的。但如果只有一個(gè)選項(xiàng)那它一定是殘酷的。 勝利者鑄造的浮光掠影海市蜃樓不過(guò)是表象。弱肉...
    為念心安閱讀 439評(píng)論 0 1
  • 前言 之前寫(xiě)了一篇文章是關(guān)于自定義控件的。在學(xué)習(xí)自定義view的時(shí)候順便把安卓的touch system(安卓觸摸...
    Zane96閱讀 1,312評(píng)論 0 1

友情鏈接更多精彩內(nèi)容