天天看点

Android逆向分析之APKTool

由于刚踏入Android逆向分析领域,因此有许多的不懂,所以得不断地去学习。

因为是入门,我又有一定的Android应用开发基础,所以先从一些简单工程的反编译开始入手,先了解一些反编译所用到的工具。

上一次写博客,记录了反编译工具dex2jar和jd-gui 的使用,这次继续记录另一款比较强大的反编译工具APKTool。

该工具的使用方法很简单,只需要在dos控制台里输入apktool  d  xxx.apk 则可以在当前文件夹生成一个装有该APK的smali文件夹。

通过记事本可打开smali文件,可以看到一套以smali语法写的编码,实际上就是android虚拟机Dalvik的汇编语言。

算了,本人语言表达技术不好,还是直接上图清晰明了:

第一步,编写一个简单的应用工程,并打包APK,用于下面的反编译(直接用上一次博客中用到的登录界面应用):

MainActivity.java:

public class MainActivity extends Activity {

    private final String ACCOUNT="samuel";
    private final String PASSWORD="123456";
    private EditText etAccount, etPassword;
    private Button btnLogin;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etAccount=(EditText)findViewById(R.id.et_account);

        etPassword=(EditText)findViewById(R.id.et_password);

        btnLogin=(Button)findViewById(R.id.btn_login);

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isOK(etAccount.getText().toString(), etPassword.getText().toString())){
                    Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                }

            }
        });
    }

    private boolean isOK(String account, String password){
        if(account.equals(ACCOUNT) && password.equals(PASSWORD))
            return true;
        else
            return false;
    }

}
           

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_centerInParent="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="帐号:"/>

            <EditText
                android:id="@+id/et_account"
                android:layout_width="100dp"
                android:layout_height="wrap_content" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="密码:"/>

            <EditText
                android:id="@+id/et_password"
                android:layout_width="100dp"
                android:layout_height="wrap_content" />

        </LinearLayout>

        <Button
            android:id="@+id/btn_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="登录"/>

    </LinearLayout>

</RelativeLayout>
           

第二步,下载APKTool,下面底部附有下载连接:

Android逆向分析之APKTool

第三步,dos下cd到APKTool的位置,再输入apktool  d  login.apk,回车进入反编译,完了后在当前文件夹下生成login文件夹,该文件夹里有smali文件:

Android逆向分析之APKTool
Android逆向分析之APKTool
Android逆向分析之APKTool
Android逆向分析之APKTool

第四步,用记事本打开login->smali中的LoginActivity.smali:

.class public Lcom/samuelzhan/logintest/LoginActivity;
.super Landroid/app/Activity;


# instance fields
.field private final a:Ljava/lang/String;

.field private final b:Ljava/lang/String;

.field private c:Landroid/widget/EditText;

.field private d:Landroid/widget/EditText;

.field private e:Landroid/widget/Button;


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

    invoke-direct {p0}, Landroid/app/Activity;-><init>()V

    const-string v0, "samuel"

    iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->a:Ljava/lang/String;

    const-string v0, "123456"

    iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->b:Ljava/lang/String;

    return-void
.end method

.method static synthetic a(Lcom/samuelzhan/logintest/LoginActivity;)Landroid/widget/EditText;
    .locals 1

    iget-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->c:Landroid/widget/EditText;

    return-object v0
.end method

.method static synthetic a(Lcom/samuelzhan/logintest/LoginActivity;Ljava/lang/String;Ljava/lang/String;)Z
    .locals 1

    invoke-direct {p0, p1, p2}, Lcom/samuelzhan/logintest/LoginActivity;->a(Ljava/lang/String;Ljava/lang/String;)Z

    move-result v0

    return v0
.end method

.method private a(Ljava/lang/String;Ljava/lang/String;)Z
    .locals 1

    const-string v0, "samuel"

    invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-eqz v0, :cond_0

    const-string v0, "123456"

    invoke-virtual {p2, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-eqz v0, :cond_0

    const/4 v0, 0x1

    :goto_0
    return v0

    :cond_0
    const/4 v0, 0x0

    goto :goto_0
.end method

.method static synthetic b(Lcom/samuelzhan/logintest/LoginActivity;)Landroid/widget/EditText;
    .locals 1

    iget-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->d:Landroid/widget/EditText;

    return-object v0
.end method


# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 2

    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    const v0, 0x7f040019

    invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->setContentView(I)V

    const v0, 0x7f0c0050

    invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->c:Landroid/widget/EditText;

    const v0, 0x7f0c0051

    invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->d:Landroid/widget/EditText;

    const v0, 0x7f0c0052

    invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/Button;

    iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->e:Landroid/widget/Button;

    iget-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->e:Landroid/widget/Button;

    new-instance v1, Lcom/samuelzhan/logintest/a;

    invoke-direct {v1, p0}, Lcom/samuelzhan/logintest/a;-><init>(Lcom/samuelzhan/logintest/LoginActivity;)V

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

    return-void
.end method
           

对比一下MainActivity.java里的源代码,其实Dalvik汇编语言还是比较好理解的。

第五步,修改smali文件,让登录系统无论帐号密码是否正确,均可以实现登录成功,即破解:

Android逆向分析之APKTool

修改返回值,让它只返回0x1,即true

Android逆向分析之APKTool

第六步,重新打包:

在dos下,cd到apktool.jar当前的位置,输入apktool  b  <刚刚反编译生成文件夹的路径>

Android逆向分析之APKTool

反编译后和打包后的login文件夹会多出两个文件夹,dist里有打包后的apk

Android逆向分析之APKTool
Android逆向分析之APKTool

第七步,因为反编译后签名被破坏,需要重新签名才能在手机上安装:

签名工具很多,我这里使用的是Auto-sign,下面附加下载

Android逆向分析之APKTool

用记事本打开批处理文件Sign.bat,并修改

Android逆向分析之APKTool

修改后保存,并运行Sign.bat文件

Android逆向分析之APKTool

多出一个已签名的APK,至此反编译修改smali文件重新打包的工作基本已完成,现在验证一下,是否输入任意的帐号密码也能显示登录成功。

效果图:

Android逆向分析之APKTool

本来输入的帐号密码应该是 samuel   123456,现在随便输入都可以显示“登录成功”提示字符,说明破解成功了~

工具下载:APKTool & Auto-sign

继续阅读