Andriod逆向之smali分析

2020-06-09  本文已影响0人  Sharkchilli

概述

本文主要讲述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版本

<?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应用.

上一篇下一篇

猜你喜欢

热点阅读