反编译
我们都知道,程序打完包之后得到的是一个APK文件,这个文件是可以直接安装到任何Android手机上的,我们反编译其实也就是对这个APK文件进行反编译。Android的反编译主要又分为两个部分,一个是对代码的反编译,一个是对资源的反编译,我们马上来逐个学习一下。
在开始学习之前,首先我们需要准备一个APK文件,为了尊重所有开发者,我就不拿任何一个市面上的软件来演示了,而是自己写一个Demo用来测试。 这里我希望代码越简单越好,因此我们建立一个新项目,在Activity里加入一个按钮,当点击按钮时弹出一个Toast,就这么简单,代码如下所示: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(); } }); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
activity_main.xml中的资源如下所示:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
然后我们将代码打成一个APK包,并命名成Demo.apk,再把它安装到手机上,结果如下所示:
反编译代码
要想将APK文件中的代码反编译出来,我们需要用到以下两款工具:
- dex2jar 这个工具用于将dex文件转换成jar文件 下载地址:
- jd-gui 这个工具用于将jar文件转换成java代码 下载地址:
将这两个工具都下载好并解压,然后我们就开始对Demo程序进行反编译。解压dex2jar压缩包后,你会发现有很多个文件,如下图所示:
d2j-dex2jar classes.dex
- 1
- 1
执行结果如下图所示:
反编译资源
其实细心的朋友可能已经观察到了,刚才Demo.apk的解压目录当中不是已经有资源文件了吗,有AndroidManifest.xml文件,也有res目录。进入res目录当中,内容如下图所示:
- apktool 这个工具用于最大幅度地还原APK文件中的9-patch图片、布局、字符串等等一系列的资源。 下载地址:
关于这个工具的下载我还要再补充几句,我们需要的就是apktool.bat和apktool.jar这两个文件。目前apktool.jar的最新版本是2.0.3,这里我就下载最新的了,然后将apktool_2.0.3.jar重命名成apktool.jar,并将它们放到同一个文件夹下就可以了,如下图所示:
apktool d Demo.apk
- 1
- 1
其中d是decode的意思,表示我们要对Demo.apk这个文件进行解码。那除了这个基本用法之外,我们还可以再加上一些附加参数来控制decode的更多行为:
- -f 如果目标文件夹已存在,则强制删除现有文件夹(默认如果目标文件夹已存在,则解码失败)。
- -o 指定解码目标文件夹的名称(默认使用APK文件的名字来命名目标文件夹)。
- -s 不反编译dex文件,也就是说classes.dex文件会被保留(默认会将dex文件解码成smali文件)。
- -r 不反编译资源文件,也就是说resources.arsc文件会被保留(默认会将resources.arsc解码成具体的资源文件)。
常用用法就这么多了,那么上述命令的执行结果如下图所示:
C:\Users\Administrator\apktool\framework
这个目录下生成一个名字为1.apk
的缓存文件,将这个缓存文件删除掉,然后再重新执行反编译命令应该就可以成功了。 现在你会发现在当前目录下多了一个Demo文件夹,这个文件夹中存放的就是反编译的结果了。我们可以打开AndroidManifest.xml来瞧一瞧,如下图所示:
重新打包
那么对于反编译出来的文件夹,我们能不能重新把它打包成APK文件呢?答案是肯定的,只不过我实在想不出有什么义正言辞的理由可以让我们这么做。有的人会说汉化,没错,汉化的方式确实就是将一个APK进行反编译,然后翻译其中的资源再重新打包,但是不管怎么说这仍然是将别人的程序进行破解,所以我并不认为这是什么光荣的事情。那么我们就不去讨论本身这件事情的对或错,这里只是站在技术的角度来学习一下重新打包的相关知识。
首先我们来看一下通过apktool反编译后的包目录情况,如下图所示:you clicked button
这样一句Toast,逻辑是写在MainActivity按钮点击事件的匿名类当中的,因此这段代码反编译之后一定就会在MainActivity$1.smali这个文件当中,让我们打开瞧一瞧,部分代码如下所示: Your app is been hacked
。 关于smali的语法,网上的资料也非常多,如果你对这门技术十分感兴趣的话可以直接上网去搜,这里我只是简单介绍一下,就不再深入讲解相关知识了。改了一处代码后我们再来改一处资源吧,比如这里想要把Demo的应用图标给换掉,那么首先我们要准备好一张新的图片,如下图所示:
然后从AndroidManifest.xml文件中可以看出,应用图标使用的是ic_launcher.png这张图片,那么我们将上面篮球这张图片命名成ic_launcher.png,然后拷贝到所有以res/mipmap开头的文件夹当中完成替换操作。
在做了两处改动之后,我们现在来把反编译后的Demo文件夹重新打包成APK吧,其实非常简单,只需要在cmd中执行如下命令:apktool b Demo -o New_Demo.apk
- 1
- 1
其中b是build的意思,表示我们要将Demo文件夹打包成APK文件,-o用于指定新生成的APK文件名,这里新的文件叫作New_Demo.apk。执行结果如下图所示:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 签名文件名 -storepass 签名密码 待签名的APK文件名 签名的别名
- 1
- 1
其中jarsigner命令文件是存放在jdk的bin目录下的,需要将bin目录配置在系统的环境变量当中才可以在任何位置执行此命令。
签名之后的APK文件现在已经可以安装到手机上了,不过在此之前Android还极度建议我们对签名后的APK文件进行一次对齐操作,因为这样可以使得我们的程序在Android系统中运行得更快。对齐操作使用的是zipalign工具,该工具存放于<Android SDK>/build-tools/<version>
目录下,将这个目录配置到系统环境变量当中就可以在任何位置执行此命令了。命令格式如下: zipalign 4 New_Demo.apk New_Demo_aligned.apk
- 1
- 1
其中4是固定值不能改变,后面指定待对齐的APK文件名和对齐后的APK文件名。运行这段命令之后就会生成一个New_Demo_aligned.apk文件,如下所示:
好的,我们把反编译代码、反编译资源、重新打包这三大主题的内容都已经掌握了,关于反编译相关的内容就到这里,下篇文章会介绍Android代码混淆方面的相关技术,感兴趣的朋友请继续阅读: 。