以前一直有犹豫过要不要写这篇文章,毕竟去反编译人家的程序并非什么值得骄傲的事情。不过单纯从技术角度上来说,掌握反编译功能确实是一项很是有用的技能,可能日常不太会用获得,可是一旦真的须要用到的了,而你却不会的话,那就很是头疼了。另外既然别人能够反编译程序,咱们固然有理由应该对程序进行必定程度的保护,所以代码混淆也是咱们必需要掌握的一项技术。那么最近的两篇文章咱们就围绕反编译和混淆这两个主题来进行一次彻底解析。 java
咱们都知道,Android程序打完包以后获得的是一个APK文件,这个文件是能够直接安装到任何Android手机上的,咱们反编译其实也就是对这个APK文件进行反编译。Android的反编译主要又分为两个部分,一个是对代码的反编译,一个是对资源的反编译,咱们立刻来逐个学习一下。
在开始学习以前,首先咱们须要准备一个APK文件,为了尊重全部开发者,我就不拿任何一个市面上的软件来演示了,而是本身写一个Demo用来测试。
这里我但愿代码越简单越好,所以咱们创建一个新项目,在Activity里加入一个按钮,当点击按钮时弹出一个Toast,就这么简单,代码以下所示: linux
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中的资源以下所示: android
<?xml version="1.0" encoding="utf-8"?> <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,再把它安装到手机上,结果以下所示: git
要想将APK文件中的代码反编译出来,咱们须要用到如下两款工具: github
将这两个工具都下载好并解压,而后咱们就开始对Demo程序进行反编译。解压dex2jar压缩包后,你会发现有不少个文件,以下图所示: 缓存
d2j-dex2jar classes.dex
执行结果以下图所示: app
其实细心的朋友可能已经观察到了,刚才Demo.apk的解压目录当中不是已经有资源文件了吗,有AndroidManifest.xml文件,也有res目录。进入res目录当中,内容以下图所示: ide
关于这个工具的下载我还要再补充几句,咱们须要的就是apktool.bat和apktool.jar这两个文件。目前apktool.jar的最新版本是2.0.3,这里我就下载最新的了,而后将apktool_2.0.3.jar重命名成apktool.jar,并将它们放到同一个文件夹下就能够了,以下图所示: 工具
apktool d Demo.apk
其中d是decode的意思,表示咱们要对Demo.apk这个文件进行解码。那除了这个基本用法以外,咱们还能够再加上一些附加参数来控制decode的更多行为: 布局
经常使用用法就这么多了,那么上述命令的执行结果以下图所示:
那么对于反编译出来的文件夹,咱们能不能从新把它打包成APK文件呢?答案是确定的,只不过我实在想不出有什么义正言辞的理由可让咱们这么作。有的人会说汉化,没错,汉化的方式确实就是将一个APK进行反编译,而后翻译其中的资源再从新打包,可是无论怎么说这仍然是将别人的程序进行破解,因此我并不认为这是什么光荣的事情。那么咱们就不去讨论自己这件事情的对或错,这里只是站在技术的角度来学习一下从新打包的相关知识。
首先咱们来看一下经过apktool反编译后的包目录状况,以下图所示:
而后从AndroidManifest.xml文件中能够看出,应用图标使用的是ic_launcher.png这张图片,那么咱们将上面篮球这张图片命名成ic_launcher.png,而后拷贝到全部以res/mipmap开头的文件夹当中完成替换操做。
在作了两处改动以后,咱们如今来把反编译后的Demo文件夹从新打包成APK吧,其实很是简单,只须要在cmd中执行以下命令:
apktool b Demo -o New_Demo.apk
其中b是build的意思,表示咱们要将Demo文件夹打包成APK文件,-o用于指定新生成的APK文件名,这里新的文件叫做New_Demo.apk。执行结果以下图所示:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 签名文件名 -storepass 签名密码 待签名的APK文件名 签名的别名
其中jarsigner命令文件是存放在jdk的bin目录下的,须要将bin目录配置在系统的环境变量当中才能够在任何位置执行此命令。
签名以后的APK文件如今已经能够安装到手机上了,不过在此以前Android还极度建议咱们对签名后的APK文件进行一次对齐操做,由于这样可使得咱们的程序在Android系统中运行得更快。对齐操做使用的是zipalign工具,该工具存放于<Android SDK>/build-tools/<version>目录下,将这个目录配置到系统环境变量当中就能够在任何位置执行此命令了。命令格式以下:
zipalign 4 New_Demo.apk New_Demo_aligned.apk
其中4是固定值不能改变,后面指定待对齐的APK文件名和对齐后的APK文件名。运行这段命令以后就会生成一个New_Demo_aligned.apk文件,以下所示:
好的,咱们把反编译代码、反编译资源、从新打包这三大主题的内容都已经掌握了,关于反编译相关的内容就到这里,下篇文章会介绍Android代码混淆方面的相关技术,敬请期待。