美文网首页
Andriod逆向之smali分析

Andriod逆向之smali分析

作者: Sharkchilli | 来源:发表于2020-06-09 19:27 被阅读0次

    概述

    本文主要讲述Andriod中java层的逆向分析,这里我们只讨论简单的一些基本技术,对加固或代码混淆在以后涉及。

    实验目的

    通过本文来了解apk的反编译回编译Smali汇编中代码插桩绕过java层检测进行登录。

    前置条件

    阅读本文你需要掌握以下知识:

    实验环境

    Android4.0.3(x86) 虚拟机(这里我们暂时不对so层进行分析,所以不在乎CPU是哪个平台)
    apktool.jar
    Apk上上签
    cm.apk (这个是自己编写的一个简单的demo程序读者也可以自己编写)
    链接:https://pan.baidu.com/s/1jI8_bxmTaGL4ESO2JdNEYQ
    提取码:ya9j

    cm程序体验

    使用adb命令安装程序进入虚拟机

    adb install cm.apk
    

    运行后如下图:


    image.png

    输入密码点击确定,正确的话提示正确,否则提示错误。我们的目的就是去绕过这个检测。

    反编译

    使用以下命令反编译apk:

    apktool.jar d cm.apk
    

    d后面跟上你的apk,命令执行完之后目录下出现和apk同名文件夹,进入结构如下:


    image.png

    如果缺少太多文件请更换apktool版本

    • 目录介绍
      original:签名信息
      res:资源文件,我们在xml定义的字符串,样式也在里面
      smali:java代码反编译后得到的smali代码
      AndroidManifest.xml:清单文件
      apktool.yml:apktool生成的

    • smali代码
      进入smali文件夹里面有两个文件夹
      android:系统生成的smali代码
      com:这个就对应了android项目中创建的包名(我们编写的业务代码逻辑都在这里面),所以我们主要对它进行分析

    • 清单文件

    <?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test1">
        <application android:allowBackup="true" android:debuggable="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme">
            <activity android:label="@string/app_name" android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
        </application>
    </manifest>
    

    从清单文件中可以知道我们分析的app中只有一个activity就是MainActivity,它也是入口activity,所有我们直接进到smali\com\example\test1\MainActivity.smali
    (这里注意MainActivity$1.smali是MainActivity类中的匿名类也会生成为一个单独的smali文件后面的数字随着匿名内部类的数量依次递增)
    MainActivity.smali(里面内容过多我这里只截取关键代码)

    # direct methods
    .method public constructor <init>()V
        .locals 1
    
        .prologue
        const/4 v0, 0x0
    
        .line 15
        invoke-direct {p0}, Landroid/support/v7/app/ActionBarActivity;-><init>()V
    
        .line 20
        iput-object v0, p0, Lcom/example/test1/MainActivity;->pswd1:Ljava/lang/String;
    
        .line 21
        iput-object v0, p0, Lcom/example/test1/MainActivity;->result1:Ljava/lang/String;
    
        .line 22
        iput-object v0, p0, Lcom/example/test1/MainActivity;->result2:Ljava/lang/String;
        #new MainActivity$1 这个匿名内部类就是onclick类的实例对象
        .line 57
        new-instance v0, Lcom/example/test1/MainActivity$1;
    
        invoke-direct {v0, p0}, Lcom/example/test1/MainActivity$1;-><init>(Lcom/example/test1/MainActivity;)V
        # 放入到this中
        iput-object v0, p0, Lcom/example/test1/MainActivity;->listener:Landroid/view/View$OnClickListener;
    
        .line 15
        return-void
    .end method
    
    
    # virtual methods
    .method protected onCreate(Landroid/os/Bundle;)V
        .locals 4
        .param p1, "savedInstanceState"    # Landroid/os/Bundle;
    
        .prologue
        .line 26
        invoke-super {p0, p1}, Landroid/support/v7/app/ActionBarActivity;->onCreate(Landroid/os/Bundle;)V
        
        .line 27
        const v2, 0x7f030018
    
        invoke-virtual {p0, v2}, Lcom/example/test1/MainActivity;->setContentView(I)V
    
        .line 28
        const v2, 0x7f05003d
    
        invoke-virtual {p0, v2}, Lcom/example/test1/MainActivity;->findViewById(I)Landroid/view/View;
    
        move-result-object v2
    
        check-cast v2, Landroid/widget/EditText;
    
        iput-object v2, p0, Lcom/example/test1/MainActivity;->Pswd:Landroid/widget/EditText;
    
        .line 29
        const v2, 0x7f05003e
    
        invoke-virtual {p0, v2}, Lcom/example/test1/MainActivity;->findViewById(I)Landroid/view/View;
    
        move-result-object v2
    
        check-cast v2, Landroid/widget/Button;
    
        iput-object v2, p0, Lcom/example/test1/MainActivity;->bt:Landroid/widget/Button;
        #将button放入到v2
        .line 30
        iget-object v2, p0, Lcom/example/test1/MainActivity;->bt:Landroid/widget/Button;
        #将listener放入到v3
        iget-object v3, p0, Lcom/example/test1/MainActivity;->listener:Landroid/view/View$OnClickListener;
        #设置点击事件
        invoke-virtual {v2, v3}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
    
        .line 31
        const-string v0, "12345678"
    
        .line 32
        .local v0, "key":Ljava/lang/String;
        iget-object v1, p0, Lcom/example/test1/MainActivity;->pswd1:Ljava/lang/String;
    
        .line 34
        .local v1, "text":Ljava/lang/String;
    
        #插桩代码 弹出Toast 打印Shark Chilli Log
        const-string v0, "Shark Chilli Log"
        
        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
        return-void
    .end method
    

    我们在OnCreate方法最后面加上了我们的插桩代码~
    关键代码做了注释,从上面可以看出我们的关键逻辑在MainActivity$1这个OnClickListener匿名内部类里面的Onclick函数:

    MainActivity$1.smali

    
    # virtual methods
    .method public onClick(Landroid/view/View;)V
        .locals 5
        .param p1, "v"    # Landroid/view/View;
    
        .prologue
        const/4 v4, 0x1
    
        .line 60
        invoke-virtual {p1}, Landroid/view/View;->getId()I
    
        move-result v1
    
        packed-switch v1, :pswitch_data_0
    
        .line 88
        :goto_0
        return-void
    
        .line 65
        :pswitch_0
        iget-object v1, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
    
        iget-object v2, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
    
        invoke-static {v2}, Lcom/example/test1/MainActivity;->access$0(Lcom/example/test1/MainActivity;)Landroid/widget/EditText;
    
        move-result-object v2
    
        invoke-virtual {v2}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    
        move-result-object v2
    
        invoke-interface {v2}, Landroid/text/Editable;->toString()Ljava/lang/String;
    
        move-result-object v2
    
        invoke-static {v1, v2}, Lcom/example/test1/MainActivity;->access$1(Lcom/example/test1/MainActivity;Ljava/lang/String;)V
    
        .line 68
        :try_start_0
        iget-object v1, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
    
        iget-object v2, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
    
        invoke-static {v2}, Lcom/example/test1/MainActivity;->access$2(Lcom/example/test1/MainActivity;)Ljava/lang/String;
    
        move-result-object v2
    
        const-string v3, "poi7y6gt"
        #DES加密 将输入的密码加密
        invoke-static {v2, v3}, Lcom/example/test1/DES;->encryptDES(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    
        move-result-object v2
        # access$3里面就一句 iput-object p1, p0, Lcom/example/test1/MainActivity;->result1:Ljava/lang/String;
        invoke-static {v1, v2}, Lcom/example/test1/MainActivity;->access$3(Lcom/example/test1/MainActivity;Ljava/lang/String;)V
        :try_end_0
        .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
    
        .line 76
        :goto_1
        #this$0就是MainActivity的实例对象                    
        iget-object v1, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
        #调用MainActivity;->access$4方法    invoke-direct {p0}, Lcom/example/test1/MainActivity;->check()Z
        invoke-static {v1}, Lcom/example/test1/MainActivity;->access$4(Lcom/example/test1/MainActivity;)Z
        #结果放入v1
        move-result v1
        #等于0则跳转到 我们改成if-nez不等于0则跳转就所有密码都能过去了
        if-eqz v1, :cond_0
    
        .line 78
        iget-object v1, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
    
        const-string v2, "\u606d\u559c\u8fc7\u5173"
    
        invoke-static {v1, v2, v4}, 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 70
        :catch_0
        move-exception v0
    
        .line 72
        .local v0, "e":Ljava/lang/Exception;
        invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V
    
        goto :goto_1
    
        .line 82
        .end local v0    # "e":Ljava/lang/Exception;
        :cond_0
        iget-object v1, p0, Lcom/example/test1/MainActivity$1;->this$0:Lcom/example/test1/MainActivity;
    
        const-string v2, "\u5bc6\u7801\u9519\u8bef"
    
        invoke-static {v1, v2, v4}, 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 60
        :pswitch_data_0
        .packed-switch 0x7f05003e
            :pswitch_0
        .end packed-switch
    .end method
    
    

    在上面修改了if-eqz v1, :cond_0if-nez v1, :cond_0就可以绕过检测了,我们可以看到起加密算法的主要逻辑是在Lcom/example/test1/MainActivity;->check()Z中。并且这个应该是一个DES加密,我们暂时不对加密算法讨论。

    修改代码后,进行回编译

    apktool.jar b cm
    

    在cm目录中会出现dist目录,里面就是我们回编译的apk


    image.png

    使用上上签进行签名(你也可以使用jar文件签名,这里为了方便使用了上上签):

    签名后生成了cm_Signed.apk


    image.png

    丢进android中运行

     adb install cm_Signed.apk
    

    运行后进入后:

    image.png

    填写任意密码效果如下:


    image.png

    尾言

    到此为止我们就成功的绕过了密码验证,这里的加密方法是在java中所以轻松的绕过它,但是大部分情况加密可能写在so层,所以我们需要进入到so层对代码分析。
    接下来几天我将结合静态分析动态调试,分析一个so层加密的Android应用.

    相关文章

      网友评论

          本文标题:Andriod逆向之smali分析

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