Android安全攻防战,反编译与混淆技术彻底解析(上)

原文出处: 郭霖   html

以前一直有犹豫过要不要写这篇文章,毕竟去反编译人家的程序并非什么值得骄傲的事情。不过单纯从技术角度上来说,掌握反编译功能确实是一项很是有用的技能,可能日常不太会用获得,可是一旦真的须要用到的了,而你却不会的话,那就很是头疼了。另外既然别人能够反编译程序,咱们固然有理由应该对程序进行必定程度的保护,所以代码混淆也是咱们必需要掌握的一项技术。那么最近的两篇文章咱们就围绕反编译和混淆这两个主题来进行一次彻底解析。java

反编译

咱们都知道,Android程序打完包以后获得的是一个APK文件,这个文件是能够直接安装到任何Android手机上的,咱们反编译其实也就是对这个APK文件进行反编译。Android的反编译主要又分为两个部分,一个是对代码的反编译,一个是对资源的反编译,咱们立刻来逐个学习一下。linux

在开始学习以前,首先咱们须要准备一个APK文件,为了尊重全部开发者,我就不拿任何一个市面上的软件来演示了,而是本身写一个Demo用来测试。android

这里我但愿代码越简单越好,所以咱们创建一个新项目,在Activity里加入一个按钮,当点击按钮时弹出一个Toast,就这么简单,代码以下所示:git

Javagithub

1编程

2缓存

3架构

4app

5

6

7

8

9

10

11

12

13

14

15

16

public class MainActivity extends AppCompatActivity {

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Button button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                Toast.makeText(MainActivity.this, "you clicked button", Toast.LENGTH_SHORT).show();

            }

        });

    }

 

}

activity_main.xml中的资源以下所示:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

RelativeLayout

    xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin">

 

    Button

        android:id="@+id/button"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Button"/>

 

RelativeLayout>

而后咱们将代码打成一个APK包,并命名成Demo.apk,再把它安装到手机上,结果以下所示:

好的,到这里准备工做就已经基本完成了,接下来就让咱们开始对这个Demo程序进行反编译吧。

反编译代码

要想将APK文件中的代码反编译出来,咱们须要用到如下两款工具:

将这两个工具都下载好并解压,而后咱们就开始对Demo程序进行反编译。解压dex2jar压缩包后,你会发现有不少个文件,以下图所示:

其中咱们要用到的是d2j-dex2jar.bat这个文件,固然若是你是linux或mac系统的话就要用d2j-dex2jar.sh这个文件。

而后咱们将Demo.apk文件也进行解压,若是不知道怎么直接解压的能够先将文件重命名成Demo.zip,而后用解压软件打开。解压以后你会发现里面有一个classes.dex文件,以下图所示:

这个classes.dex文件就是存放全部java代码的地方了,咱们将它拷贝到dex2jar解压后的目录下,并在cmd中也进入到一样的目录,而后执行:

Java

1

d2j-dex2jar classes.dex

执行结果以下图所示:

没有报任何错误,这就说明咱们已经转换成功了。如今观察dex2jar目录,你会发现多了一个文件,以下图所示:

能够看到,classes-dex2jar.jar这个文件就是咱们借助工具以后成功转换出来的jar文件了。可是对于咱们而言,jar文件也不是可读的,所以这里还须要再借助一下jd-gui这个工具来将jar文件转换成java代码。

下面就很简单了,使用jd-gui工具打开classes-dex2jar.jar这个文件,结果以下图所示:

OK,因而可知,咱们的代码反编译工做已经成功了,MainActivity中的代码很是清晰,基本已经作到了90%以上的还原工做。可是若是想要作到100%的代码还原仍是很是有难度的,由于像setContentView()方法传入的参数,其实就是一个资源的id值而已,那么这里反编译也就只能将相应的id值进行还原,而没法变成像R.layout.activity_main这样直观的代码展现。

另外,除了MainActivity以外,还有不少其它的代码也被反编译出来了,由于当前项目有引用support-v4和support-v7的包,这些引用的library也会做为代码的一部分被打包到classes.dex文件当中,所以反编译的时候这些代码也会一块儿被还原。

好的,学完了反编译代码,接下来咱们看一下如何反编译资源。

反编译资源

其实细心的朋友可能已经观察到了,刚才Demo.apk的解压目录当中不是已经有资源文件了吗,有AndroidManifest.xml文件,也有res目录。进入res目录当中,内容以下图所示:

这不是全部资源文件都在这里了么?其实这些资源文件都是在打包的时候被编译过了,咱们直接打开的话是看不到明文的,不信的话咱们打开AndroidManifest.xml文件来瞧一瞧,内容以下图所示:

能够看到,这代码是彻底无法阅读的。固然若是你去打开activity_main.xml看看,结果也不会好到哪儿去:

因而可知,直接对APK包进行解压是没法获得它的原始资源文件的,所以咱们还须要对资源进行反编译才行。

要想将APK文件中的资源反编译出来,又要用到另一个工具了:

关于这个工具的下载我还要再补充几句,咱们须要的就是apktool.bat和apktool.jar这两个文件。目前apktool.jar的最新版本是2.0.3,这里我就下载最新的了,而后将apktool_2.0.3.jar重命名成apktool.jar,并将它们放到同一个文件夹下就能够了,以下图所示:

接下来的工做就很简单了,咱们将Demo.apk拷贝到和这两个文件一样的目录当中,而后cmd也进入到这个目录下,并在cmd中执行以下命令:

Java

1

apktool d Demo.apk

其中d是decode的意思,表示咱们要对Demo.apk这个文件进行解码。那除了这个基本用法以外,咱们还能够再加上一些附加参数来控制decode的更多行为:

  • -f 若是目标文件夹已存在,则强制删除现有文件夹(默认若是目标文件夹已存在,则解码失败)。

  • -o 指定解码目标文件夹的名称(默认使用APK文件的名字来命名目标文件夹)。

  • -s 不反编译dex文件,也就是说classes.dex文件会被保留(默认会将dex文件解码成smali文件)。

  • -r 不反编译资源文件,也就是说resources.arsc文件会被保留(默认会将resources.arsc解码成具体的资源文件)。

经常使用用法就这么多了,那么上述命令的执行结果以下图所示:


这就说明反编译资源已经成功了。
固然即便你在和我执行如出一辙的操做,也有可能会在这里反编译失败,好比说会报以下错误:
这里写图片描述

出现这个错误的缘由颇有多是你以前使用过apktool的老版本进行过反编译操做,而后apktool就会在你系统的C:UsersAdministratorapktoolframework这个目录下生成一个名字为1.apk的缓存文件,将这个缓存文件删除掉,而后再从新执行反编译命令应该就能够成功了。

如今你会发如今当前目录下多了一个Demo文件夹,这个文件夹中存放的就是反编译的结果了。咱们能够打开AndroidManifest.xml来瞧一瞧,以下图所示:

怎么样?这样就彻底能看得懂了吧,而后能够再到res/layout中看一下activity_main.xml文件,以下图所示:

能够看到,activity_main.xml中的内容基本和源代码中的内容是一致的,外层是一个RelativeLayout,里面则是一个Button。你能够再到其它目录中去看一看别的资源,基本上都是能够正常还原的,这样咱们就把反编译资源的方法也已经掌握了。

从新打包

那么对于反编译出来的文件夹,咱们能不能从新把它打包成APK文件呢?答案是确定的,只不过我实在想不出有什么义正言辞的理由可让咱们这么作。有的人会说汉化,没错,汉化的方式确实就是将一个APK进行反编译,而后翻译其中的资源再从新打包,可是无论怎么说这仍然是将别人的程序进行破解,因此我并不认为这是什么光荣的事情。那么咱们就不去讨论自己这件事情的对或错,这里只是站在技术的角度来学习一下从新打包的相关知识。

首先咱们来看一下经过apktool反编译后的包目录状况,以下图所示:

其中,original文件夹下存放的是未经反编译过、原始的AndroidManifest.xml文件,res文件夹下存放的是反编译出来的全部资源,smali文件夹下存放的是反编译出来的全部代码,AndroidManifest.xml则是通过反编译还原后的manifest文件。这里值得一提的是smali文件夹,若是你进入到这个文件夹中你会发现它的目录结构和咱们源码中src的目录结构是几乎同样的,主要的区别就是全部的java文件都变成了smali文件。smali文件其实也是真正的源代码,只不过它的语法和java彻底不一样,它有点相似于汇编的语法,是Android虚拟机所使用的寄存器语言,语法结构大概以下所示:

看上去有点晕头转向是吗?可是若是你一旦可以看得懂smali文件的话,那么你就能够作很恐怖的事情了——你能够随意修改应用程序内的逻辑,将其进行破解!

不过我对这种黑技术并无什么太大的兴趣,所以我也没有去作具体研究,但即便是这样,也已经能够对程序的逻辑作必定程度的修改了。好比说当咱们点击按钮时会弹出you clicked button这样一句Toast,逻辑是写在MainActivity按钮点击事件的匿名类当中的,所以这段代码反编译以后必定就会在MainActivity$1.smali这个文件当中,让咱们打开瞧一瞧,部分代码以下所示:

虽然说多数的代码我是看不懂的,但其中第47行实在太明显了,Toast显示的内容不就是在这里定义的么,那么若是咱们想把Demo程序hack掉,就能够将这段字符串给改掉,好比说我把它改为Your app is been hacked

关于smali的语法,网上的资料也很是多,若是你对这门技术十分感兴趣的话能够直接上网去搜,这里我只是简单介绍一下,就再也不深刻讲解相关知识了。

改了一处代码后咱们再来改一处资源吧,好比这里想要把Demo的应用图标给换掉,那么首先咱们要准备好一张新的图片,以下图所示:

而后从AndroidManifest.xml文件中能够看出,应用图标使用的是ic_launcher.png这张图片,那么咱们将上面篮球这张图片命名成ic_launcher.png,而后拷贝到全部以res/mipmap开头的文件夹当中完成替换操做。

在作了两处改动以后,咱们如今来把反编译后的Demo文件夹从新打包成APK吧,其实很是简单,只须要在cmd中执行以下命令:

Java

1

apktool b Demo -o New_Demo.apk

其中b是build的意思,表示咱们要将Demo文件夹打包成APK文件,-o用于指定新生成的APK文件名,这里新的文件叫做New_Demo.apk。执行结果以下图所示:

如今你会发如今同级目录下面生成了一个新的APK文件:

不过不要高兴得太早了,目前这个New_Demo.apk仍是不能安装的,由于它尚未进行签名。那么若是这是别人的程序的话,咱们从哪儿能拿到它原来的签名文件呢?很显然,这是根本没有办法拿到的,所以咱们只能拿本身的签名文件来对这个APK文件从新进行签名,但同时也代表咱们从新打包出来的软件就是个十足的盗版软件。这里你们学学技术就行了,但愿不要有任何人去作什么坏事情。

那么这里我就用一个以前生成好的签名文件了,使用Android Studio或者Eclipse均可以很是简单地生成一个签名文件。

有了签名文件以后在cmd中执行签名命令就能够进行签名了,命令格式以下:

Java

1

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 签名文件名 -storepass 签名密码 待签名的APK文件名 签名的别名

其中jarsigner命令文件是存放在jdk的bin目录下的,须要将bin目录配置在系统的环境变量当中才能够在任何位置执行此命令。

签名以后的APK文件如今已经能够安装到手机上了,不过在此以前Android还极度建议咱们对签名后的APK文件进行一次对齐操做,由于这样可使得咱们的程序在Android系统中运行得更快。对齐操做使用的是zipalign工具,该工具存放于/build-tools/目录下,将这个目录配置到系统环境变量当中就能够在任何位置执行此命令了。命令格式以下:

Java

1

zipalign 4 New_Demo.apk New_Demo_aligned.apk

其中4是固定值不能改变,后面指定待对齐的APK文件名和对齐后的APK文件名。运行这段命令以后就会生成一个New_Demo_aligned.apk文件,以下所示:


这个New_Demo_aligned.apk就是咱们从新打包签名对齐后的文件了,如今把它安装到手机上,效果以下图所示:

能够看到,应用图标已经成功改为了篮球,另外点击按钮后弹出的Toast的提示也变成了咱们修改后的文字,说明从新打包操做确实已经成功了。

http://cxy.liuzhihengseo.com/467.html

问啊-定制化IT教育平台,牛人一对一服务,有问必答,开发编程社交头条 官方网站:www.wenaaa.com 下载问啊APP,参与官方悬赏,赚百元现金。QQ群290551701 汇集不少互联网精英,技术总监,架构师,项目经理!开源技术研究,欢迎业内人士,大牛及新手有志于从事IT行业人员进入!

相关文章
相关标签/搜索