易语言教程_易语言源码_易语言写挂_易语言论坛_看流星社区

 找回密码
 注册
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
查看: 457|回复: 0

Android开发学习之路--逆向分析反编译

[复制链接]
发表于 2017-6-2 13:52:07 | 显示全部楼层 |阅读模式
  一般情况下我们想要了解别人的app怎么实现这个动画,这个效果的时候,总是会想到反编译一下,看下布局,看下代码实现。对,这对于有经验的玩家确实手到擒来了,但是初学者,根本就不知道怎么反编译,怎么看代码,甚至不知道什么是反编译。那就学一下吧。

简单写一个app

  先简单写个app用作后面的反编译,当然可以直接拿现有的比较成熟的app,但是没有源码我们没办法好好比较了。好了,比较简单就直接上代码了,这里用了下databinding,具体以后也会写文章具体讲解databinding的。

xml界面代码:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data class="MainDataBinding">
    </data>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello Decompilation:"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/et_account"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:gravity="center"
            android:hint="@string/account"/>

        <EditText
            android:id="@+id/et_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:hint="@string/password"/>

        <Button
            android:id="@+id/bt_login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@string/login"
            android:textAllCaps="false" />
    </LinearLayout>
</layout>

java代码:

package com.jared.decompilationstudy;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import com.jared.decompilationstudy.databinding.MainDataBinding;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private MainDataBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(MainActivity.this, R.layout.activity_main);

        binding.btLogin.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_login:
                if (checkInfo()) {
                    Toast.makeText(MainActivity.this, getResources().getString(R.string.login_ok),Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, getResources().getString(R.string.login_failure),Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    private boolean checkInfo() {
        if (!"admin".equals(binding.etAccount.getText().toString()))
            return false;
        if (!"123456".equals(binding.etPassword.getText().toString()))
            return false;
        return true;
    }
}

  其实主要实现就是一个简单的登录界面,判断用户名为admin,密码为123456才会显示登录成功。后面也会通过反编译之后重新打包破解之。那就继续吧。

Apktool工具–反编译资源

  apktool工具是反编译资源用的,当然你也可以把apk的后缀名改为zip,然后解压文件,但是直接解压出来的文件只有图片资源可用,其他的都是乱码,为了查看layout等资源,所以我们就需要apktool工具了。
  下载地址:http://ibotpeaches.github.io/Apktool/install/

  apktool工具主要有三个文件,分别是aapt,apktool,apktools.jar。以mac为例,将三个文件拷贝到/usr/local/bin/目录下,必要的情况下设置可执行权限。之后在终端可以执行apktool,有如下信息表示ok。

Apktool v2.1.1 - a tool for reengineering Android apk files
with smali v2.1.2 and baksmali v2.1.1
Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
Updated by Connor Tumbleson <connor.tumbleson@gmail.com>

usage: apktool
-advance,--advanced   prints advance information.
-version,--version    prints the version then exits
usage: apktool if|install-framework [options] <framework.apk>
-p,--frame-path <dir>   Stores framework files into <dir>.
-t,--tag <tag>          Tag frameworks using <tag>.
usage: apktool d[ecode] [options] <file_apk>
-f,--force              Force delete destination directory.
-o,--output <dir>       The name of folder that gets written. Default is apk.out
-p,--frame-path <dir>   Uses framework files located in <dir>.
-r,--no-res             Do not decode resources.
-s,--no-src             Do not decode sources.
-t,--frame-tag <tag>    Uses framework files tagged by <tag>.
usage: apktool b[uild] [options] <app_path>
-f,--force-all          Skip changes detection and build all files.
-o,--output <dir>       The name of apk that gets written. Default is dist/name.apk
-p,--frame-path <dir>   Uses framework files located in <dir>.

For additional info, see: http://ibotpeaches.github.io/Apktool/
For smali/baksmali info, see: https://github.com/JesusFreke/smali

  至于没有成功的,这里也不讲解了,相信google会给你答案。

  接着我们开始反编译资源了。先把之前的Android代码打包成decompilation.apk。执行如下命令:

apktool d decompilation.apk
I: Using Apktool 2.1.1 on decompilation.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/jared/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

  有时候会出现问题类似如下:

Exception in thread "main" brut.androlib.err.UndefinedResObject: resource spec: 0x01010462

  原因可能你的apktool版本很老,下载最新的,还有就是需要删除下/Users/用户名/Library/apktool/framework/1.apk

  反编译成功后,会在同级目录下生成decompilation,cd进入decompilation目录,ls查看内容如下,有AndroidManifest.xml文件,res下就是我们需要的资源文件了,smali就是Dalvik的一些指令代码,之后有机会再学习学习。

->decompilation ls
AndroidManifest.xml original            smali
apktool.yml         res                 unknown

  我们看下AndroidManifest.xml的内容:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jared.decompilationstudy" platformBuildVersionCode="23" platformBuildVersionName="6.0-2438415">
       <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme ="@style/AppTheme">
           <activity android:name="com.jared.decompilationstudy.MainActivity">
               <intent-filter>
                   <action android:name="android.intent.action.MAIN"/>
                   <category android:name="android.intent.category.LAUNCHER"/>
               </intent-filter>
           </activity>
      </application>
  </manifest>

  在对比下源码Manifest.xml的内容:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jared.decompilationstudy">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

  基本上保持了一致,这里我们没法看Java源码,只是资源,那可以看源码吗?答案是肯定的,接着学习吧。

dex2jar&jd-gui工具–反编译源码

  dex2jar是把dex文件反编译为jar文件,jd-gui是将jar文件转换为java代码。
  dex2jar下载地址:http://sourceforge.net/projects/dex2jar/files/
  jd-gui下载地址:http://jd.benow.ca/

  dex2jar下载后是一个目录,内容如下:

➜  dex2jar-2.0 ls
classes-dex2jar.jar            d2j-jar2jasmin.bat
classes.dex                    d2j-jar2jasmin.sh
d2j-baksmali.bat               d2j-jasmin2jar.bat
d2j-baksmali.sh                d2j-jasmin2jar.sh
d2j-dex-recompute-checksum.bat d2j-smali.bat
d2j-dex-recompute-checksum.sh  d2j-smali.sh
d2j-dex2jar.bat                d2j-std-apk.bat
d2j-dex2jar.sh                 d2j-std-apk.sh
d2j-dex2smali.bat              d2j_invoke.bat
d2j-dex2smali.sh               d2j_invoke.sh
d2j-jar2dex.bat                lib
d2j-jar2dex.sh

  这里我们需要的是d2j-dex2jar.sh脚本。至于jd-gui的话,就是安装好就行了,和一般的ide差不多的。

  下面就开始反编译源码了。首先需要把decompilation.apk改为decompilation.zip,然后解压缩得到classes.dex文件。然后把classes.dex拷贝到dex2jar目录下:

➜  dex2jar-2.0 cp ../apk/decompilation2/classes.dex .
➜  dex2jar-2.0 ls
classes-dex2jar.jar            d2j-jar2jasmin.bat
classes.dex                    d2j-jar2jasmin.sh
d2j-baksmali.bat               d2j-jasmin2jar.bat
d2j-baksmali.sh                d2j-jasmin2jar.sh
d2j-dex-recompute-checksum.bat d2j-smali.bat
d2j-dex-recompute-checksum.sh  d2j-smali.sh
d2j-dex2jar.bat                d2j-std-apk.bat
d2j-dex2jar.sh                 d2j-std-apk.sh
d2j-dex2smali.bat              d2j_invoke.bat
d2j-dex2smali.sh               d2j_invoke.sh
d2j-jar2dex.bat                lib
d2j-jar2dex.sh

  开始反编译了,执行如下所示:

➜  dex2jar-2.0 ./d2j-dex2jar.sh classes.dex --force
dex2jar classes.dex -> ./classes-dex2jar.jar
➜  dex2jar-2.0 ls
classes-dex2jar.jar

  执行完后就生成了classes-dex2jar.jar文件。接着我们用jd-gui看下源码,打开jd-gui软件,打开classes-dex2jar.jar文件如下所示:


  这个时候你可能会非常爽,可以看到源码了,当然也会fuck,辛辛苦苦写的代码就这样被盗了。其实一般app都会做混淆的,看得不是那么容易的,这里没有做混淆就很直白了。好了,基本上一个app的反编译分析也基本上到此结束了。

破解apk,重新打包

  这里仅当做技术学习,毕竟别人也是辛辛苦苦写的代码,好了,继续吧。
  上面已经反编译了资源,我们回到decompilation目录下,这里有smali目录,主要是一个davik指令的代码。

decompilation ls
AndroidManifest.xml original            smali
apktool.yml         res                 unknown
➜  decompilation  cd smali
➜  smali ls
android com
➜  smali cd com
➜  com ls
android jared
➜  com cd jared/decompilationstudy/
➜  decompilationstudy ls
BR.smali           R$bool.smali       R$integer.smali    R$styleable.smali
BuildConfig.smali  R$color.smali      R$layout.smali     R.smali
MainActivity.smali R$dimen.smali      R$mipmap.smali     databinding
R$anim.smali       R$drawable.smali   R$string.smali
R$attr.smali       R$id.smali         R$style.smali

  那我们要怎么破解呢?逐个击破吧,先看“登录成功”和“登录失败”,我们已“登录成功”为破解的开始吧:

➜  decompilation grep -nr "登录成功" res
res/values/strings.xml:39:    <string name="login_ok">登录成功</string>

  可以得知这个string的name为login_ok。然后我们继续查找这个login_ok怎么来的?

➜  decompilationstudy grep -nr 'login_ok' .
./R$string.smali:88:.field public static final login_ok:I = 0x7f060024
➜  decompilationstudy grep -nr '0x7f060024' .
./MainActivity.smali:117:    const v1, 0x7f060024
./R$string.smali:88:.field public static final login_ok:I = 0x7f060024

  可以得知login的I=0X7F060024,然后查找这个得到两个地方调用,一个是MainActivity.smali,后一个是string本身。显然我们的这个是在MainActivity.smali的第117行调用了。那我们继续去看看吧:

  这里需要一点汇编基础才能看的懂代码了。

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

    .prologue
    const/4 v2, 0x0

    .line 25
    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    packed-switch v0, :pswitch_data_0

    .line 34
    :goto_0
    return-void

    .line 27
    :pswitch_0
    invoke-direct {p0}, Lcom/jared/decompilationstudy/MainActivity;->checkInfo()Z

    move-result v0

    if-eqz v0, :cond_0

    .line 28
    invoke-virtual {p0}, Lcom/jared/decompilationstudy/MainActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v0

    const v1, 0x7f060024

    invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;

    move-result-object v0

    invoke-static {p0, v0, 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

    goto :goto_0

    .line 30
    :cond_0
    invoke-virtual {p0}, Lcom/jared/decompilationstudy/MainActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v0

    const v1, 0x7f060023

    invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;

    move-result-object v0

    invoke-static {p0, v0, 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

    goto :goto_0

    .line 25
    nop

    :pswitch_data_0
    .packed-switch 0x7f0b005a
        :pswitch_0
    .end packed-switch
.end method

  可以看出来这是一个onclick方法,有一个checkInfo方法,看这行代码,if-eqz v0, :cond_0,意思是v0为0就跳转到cond_0。很显然cond_0就是登陆失败了,也就是checkInfo返回了true和false分别跳转到对应的方法中。寻着这个,我们看下checkInfo的代码:

.method private checkInfo()Z
    .locals 3

    .prologue
    const/4 v0, 0x0

    .line 37
    const-string v1, "admin"

    iget-object v2, p0, Lcom/jared/decompilationstudy/MainActivity;->binding:Lcom/jared/decompilationstudy/databinding/MainDataBinding;

    iget-object v2, v2, Lcom/jared/decompilationstudy/databinding/MainDataBinding;->etAccount:Landroid/widget/EditText;

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

    move-result-object v2

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

    move-result-object v2

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

    move-result v1

    if-nez v1, :cond_1

    .line 41
    :cond_0
    :goto_0
    return v0

    .line 39
    :cond_1
    const-string v1, "123456"

    iget-object v2, p0, Lcom/jared/decompilationstudy/MainActivity;->binding:Lcom/jared/decompilationstudy/databinding/MainDataBinding;

    iget-object v2, v2, Lcom/jared/decompilationstudy/databinding/MainDataBinding;->etPassword:Landroid/widget/EditText;

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

    move-result-object v2

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

    move-result-object v2

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

    move-result v1

    if-eqz v1, :cond_0

    .line 41
    const/4 v0, 0x1

    goto :goto_0
.end method

  首先赋值v0为0x0,const/4 v0, 0x0,接着看下代码:const-string v1, “admin”,很明显是常量赋值,接着往下看:if-nez v1, :cond_1,如果结果不为0就跳转到cond_1,继续看:const-string v1, “123456”。也是常量赋值123456,然后结果为0跳转到cond_0,否则执行,const/4 v0, 0x1,goto :goto_0,就是v0赋值为1,跳转到goto_0。

  综上分析,可以得出主要的关键点是v0寄存器了,checkInfo返回的值为v0,那么如果我们把v0的初始值赋值为0x1,那么不就永远返回true了,不管什么账号登录都是ok的了。修改28行代码为:const/4 v0, 0x1。不容易啊,终于改好了,那么接着我们看看是不是如我们所愿呢?
  修改完了代码,我们把修改好的代码打包吧,执行命令如下:

➜  apk apktool b decompilation -o decompilation2.apk
I: Using Apktool 2.1.1
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...
I: Copying unknown files/dir...

   打包完的代码是没有签名的,没办法在手机上安装的,那么接下来我们开始重签名吧。

➜  apk keytool -genkey -v -keystore Android.keystore -alias android.keystore -keyalg RSA -validity 20000
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  1
您的组织单位名称是什么?
  [Unknown]:  1
您的组织名称是什么?
  [Unknown]:  1
您所在的城市或区域名称是什么?
  [Unknown]:  1
您所在的省/市/自治区名称是什么?
  [Unknown]:  1
该单位的双字母国家/地区代码是什么?
  [Unknown]:  1
CN=1, OU=1, O=1, L=1, ST=1, C=1是否正确?
  [否]:  y

正在为以下对象生成 2,048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 20,000 天):
         CN=1, OU=1, O=1, L=1, ST=1, C=1
输入 <android.keystore> 的密钥口令
        (如果和密钥库口令相同, 按回车):
[正在存储Android.keystore]

  这里偷懒了,就随便填写了内容,接着用jarsigner签名:

➜  jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore Android.keystore -storepass 123456 decompilation2.apk Android.keystore
   正在添加: META-INF/MANIFEST.MF
   正在添加: META-INF/ANDROID_.SF
   正在添加: META-INF/ANDROID_.RSA
   …………
    正在签名: com/android/databinding/library/baseAdapters/com.android.databinding.library.baseAdapters-br.bin
  正在签名: com/android/databinding/library/baseAdapters/com.android.databinding.library.baseAdapters-layoutinfo.bin
  正在签名: com/android/databinding/library/baseAdapters/com.android.databinding.library.baseAdapters-setter_store.bin
jar 已签名。

警告:
未提供 -tsa 或 -tsacert, 此 jar 没有时间戳。如果没有时间戳, 则在签名者证书的到期日期 (2071-05-29) 或以后的任何撤销日期之后, 用户可能无法验证此 jar。

  大工搞成,接着安装到手机上通过adb install decompilation2.apk。

  见证奇迹的时刻到了:

  破解成功了,你也可以试试。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|看流星社区  |网站地图

GMT+8, 2018-6-25 20:13 易语言论坛 易语言导航

Powered by 看流星社区 X3.2

©2011-2016 最好的辅助编程技术论坛

快速回复 返回顶部 返回列表