美文网首页跟着小强学Android反编译Android开发Android Tech
Android 反编译之修改Smali 文件输出日志

Android 反编译之修改Smali 文件输出日志

作者: imesong | 来源:发表于2016-03-01 11:54 被阅读4990次

    本篇是Android反编译系列的 第五篇, 前四篇的地址在这里
    第一篇 Apktool安装
    第二篇 Apktool 基本使用方法
    第三篇 App汉化与二次签名
    第四篇 修改Smali文件,定位关键点


    承接上篇Android反编译之修改Smali文件,本篇主要分析如何在 Smali文件中输出日志,帮助我们理解App 业务处理逻辑。

    1.我们先写这样一个简单的demo

    smaliLogDemoApp.gif

    顺便安利一下Android 上gif 截图的软件LICEcap,免费开源,秋百万大神推荐

    App 登陆界面,对用户名和密码做简单的逻辑验证,同时有一个FloatingActionBar,点击之后显示Snackbar。

    我们现在要做的,在登陆验证的方法里,添加日志输出,分别输出登陆成功,登陆失败。在FloatingActionBar 的响应事件中,添加日志输出。

    2.反编译SmaliLogDemo

    demo 比较简单,我这里直接给出反编译之后的 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
    

    代码没有混淆,看起来很清楚。类名 是 MainActivity.java,有三个成员变量,一个 Button,两个 AppCompatEditText。下面还有 isLogingInfoValid 方法,有两个参数,分别是 name 和 passwd。最后的是 onCreate 方法。不过,大致浏览之后,好像没有发现 FloatingActionBar 的踪迹啊,不要着急,我们先把登陆逻辑判断的日志处理好,回过头来再查找 FloatingActionBar 也不迟。

    我们先分析 isLogingInfValid 的处理逻辑。

    方法第一行 .logcals ,表示使用4个寄存器,.param p1 表示形参 name, .param p2 表示形参 passwd。紧接着 .prologue 表示方法执行开始

    #定义变量 v3,并赋值为0 
    #smali 中注释使用#
    const/4 v3,0x0
    
    #定义Boolean变量 isValid,默认为false
    .local v0,"isValid":Z
    
    #调用TextUtils.isEmpty(string) 方法
    #invoke-static ,调用一个static的静态方法
    #{p1} 是 static 方法的入参
    #Landroid/text/TextUtils 是这个方法的决定路径,L表示这是一个Object,Smali中只有两种类型 基础类型和引用类型(Object,使用L表示)
    #->这个表示调用isEmpty 方法,熟悉脚本语言的开发,应该很熟悉,小括号中定义入参的类型,使用 ';' 结尾
    #最后的 **Z** 表示代表返回值为Boolean 类型。
    #这样完成了TextUtils.isEmpty(name) 方法的调用
    invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
    
    #将结果赋值给 v1
    move-result v1
    
    #如果 v1 != 0 跳转到 :cond_0
    #如果 v1==true 跳转到 :cond_0,如果是 false ,接着往下走
    if-nez v1, :cond_0
    
    #赋值 v0 == 0
    :cond_0 
    const/4 v0, 0x0
    #下面紧接着定义 变量 v1,调用 Toast.make(context,"string",Toast.SHORT).show();方法
    #之后执行:goto_0 返回 v0 的值。
    #这个逻辑走下来,说明如果第一个参数,用户名为null,直接弹出Toast,返回false,符合我们都看到的现象。
    

    如果要在用户名为空的时候添加一条日志怎么添加呢?下面我们看下如何添加日志。

    1.修改寄存器数量
    如果要添加日志,我们要输出我们想要显示的信息,这些也是要申请寄存器存放。
    .logcal 4 修改为 .logcal 5

    2.新增变量,定义我们要输出的信息
    为了方便,这里讲 Tag 和信息定义相同,如果不想定义一致,可以再增加一个寄存器。

    const-string v4 ,"nameNull"
    
    

    3.调用Log.d("info","info");方法。

    #注意参数,返回值必须完全正确
    invoke-static {v4,v4};Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    

    这样我们就完成了name 为空时的日志添加。我们重新打包,签名,运行看下结果。

    apktool b smalilogdemo -o smalilogdemo_unsigned.apk
    

    执行之后,却遇到下面的问题

    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 里面有个属性,我们现在的framework-resource 不支持,简单粗暴的解决方法,删除 layout-v21 文件夹。删除掉这些异常的Resource 文件之后,我们就可以正常打包了。

    暂时没有找到比较好的回编译的方法,如果有新的发现,会及时更新

    如果每个想要添加日志的地方,都这样修改,感觉还是很繁琐,能不能偷懒下,把日志输出的Smali 语法封装成一个文件,我们只需要调用这个文件就可以了呢?这样当然是可以的。

    下面贴出 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 参数
    .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
    
    
    #无参数 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
    
    

    现在的封装,基本上满足日常的需求,后面会持续完善。

    我们再给出添加日志之后,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
    
    

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

    我们再看下 onClick 响应事件中的日志信息。

    # 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

    关于SmaliLogDemo 的理解,就到这里,最后附上 项目代码和Smali 文件

    相关文章

      网友评论

      • fa3af8e8e1c8:作者你好,我是一个逆向爱好者。请问可以加个QQ请教一下吗?谢谢啦!!!我QQ:81681140
      • 欧巴冰冰:一起讨论下

      本文标题:Android 反编译之修改Smali 文件输出日志

      本文链接:https://www.haomeiwen.com/subject/ldnmkttx.html