Android开发之反编译与防止反编译
防止反编译是每个程序员的必修课,因为当你辛辛苦的研发一个应用,被人家三下五除二给反编译了,是一件多么尴尬的事啊。那么如何防止反编译啊?这里就用Google Android自带的代码混编的方式来防止反编译。孙子兵法中讲得好:“知彼知己百战不殆”,所以在讲解防止反编译之前,先让我们了解一下如何反编译一个应用。
一、反编译Android应用
实验环境:
Windows8.1企业版、dex2jar-0.0.9.9
反编译工具包:
1.将Apk反编译得到Java源代码
具体步骤:
1) 首先将apk文件后缀改为zip并解压,得到其中的classes.dex,它就是java文件编译再通过dx工具打包而成的,将classes.dex复制到dex2jar.bat所在目录dex2jar-0.0.9.9文件夹。
在命令行下定位到dex2jar.bat所在目录,运行
dex2jar.bat classes.dex
如图:
生成classes_dex2jar.jar
如图:
2) 进入jdgui文件夹双击jd-gui.exe,打开上面生成的jar包classes_dex2jar.jar,即可看到源代码了,如下图:
2. 将apk反编译生成程序的源代码和图片、XML配置、语言资源等文件
具体步骤:
1) 下载上述反编译工具包,打开apk2java目录下的apktool1.4.1文件夹,内含三个文件:apktool.jar ,aapt.exe,apktool.bat,
注:里面的apktool_bk.jar是备份的老版本,最好用最新的apktool.jar
在命令行下定位到apktool.bat文件夹,输入以下命令:apktool.bat d -f abc123.apk abc123
如下图:
上图中,apktool.bat 命令行解释:apktool.bat d -f [apk文件 ] [输出文件夹]
<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="com.jph.recorder"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:allowBackup="true">
<activity android:label="@string/app_name" android:name="com.jph.recorder.Recorder">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:label="@string/show_recordFile" android:name="com.jph.recorder.ShowRecordFiles" />
<activity android:theme="@android:style/Theme.Dialog" android:name=".AboutActivity" />
<activity android:label="@string/feedback_label" android:name=".FeedBackActivity" />
<service android:name="com.jph.recorder.RecordService" />
</application>
</manifest>
将反编译完的文件重新打包成apk,很简单,输入apktool.bat b abc123(你编译出来文件夹)即可,命令如下:
打包apk后的文件在目录C:\HelloAndroid下,生成了两个文件夹:
build
dist
其中,打包生成的HelloAndroid.apk,在上面的dist文件夹下,Ok
3. 图形化反编译apk
上述步骤一、二讲述了命令行反编译apk,现在提供一种图形化反编译工具:Androidfby
首先,下载上述反编译工具包,打开Androidfby目录,双击Android反编译工具.exe,就可以浏览打开要反编译的apk文件。
二、防止应用被反编译
先介绍一下什么是代码混淆:
代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为。代码混淆可以用于程序源代码,也可以用于程序编译而成的中间代码。执行代码混淆的程序被称作代码混淆器。目前已经存在许多种功能各异的代码混淆器。
将代码中的各种元素,如变量,函数,类的名字改写成无意义的名字。比如改写成单个字母,或是简短的无意义字母组合,甚至改写成“__”这样的符号,使得阅读的人无法根据名字猜测其用途。重写代码中的部分逻辑,将其变成功能上等价,但是更难理解的形式。比如将for循环改写成while循环,将循环改写成递归,精简中间变量,等等。打乱代码的格式。比如删除空格,将多行代码挤到一行中,或者将一行代码断成多行等等。
混淆前和混淆后反编译出来的代码对比:
提示:有心的朋友可以发现:混淆后生成apk文件比混淆前生成的apk文件要小不少。这样不仅减小了项目的大小而且可以提高代码的执行速度。如下图:
具体步骤:
1) 查看项目中有没有proguard.cfg。
如果没有的话从这下载:
然后将proguard.cfg复制到项目中。
2) 在项目中的project.properties文件中添加:proguard.config=proguard.cfg
3) 然后按照正常的签名对自己的应用进行签名,生成后的apk经过反编译后就会和源代码有很大的不一样。
注意:一定要通过正常的签名方式对应用进行签名,项目bin目录中生成的apk文件是使用系统默认签名的方式,没有达到代码混编的效果的。
如果签名不成功请往下看:
4) 不过这一步你会遇到很多问题,根本就签名不成功。例如:①如果工程引入了android-support-v4的jar类库,那么在工程打包混淆时,就会出现报错提示你:You may need to specify additional library jars (using'-libraryjars')。②引用第三方包等问题
如果工程引入了android-support-v4的jar类库,那你就在proguard.cfg里的后面,添加如下内容:
-libraryjars /android-support-v4.jar
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep public class * extendsandroid.support.v4.**
-keep public class * extendsandroid.app.Fragment
然后你再打包看看,应该可以正常生成apk安装包了。
如果出现:"类1 can't find referenced class 类2" 字面上的意思就是类1找不到类2的引用;它会建议你:"You may need to specify additional library jars (using'-libraryjars').";
需要使用-libraryjars加上项目中使用到的第三方库就OK了。
例如:-libraryjars /android-support-v4.jar
注意:这里引用方式是当前工程的根目录(也可以配置其他目录),也就是说,你要把第三方jar放到当前目录下,否则就会警告说找不到jar文件!
如果出现: can't find superclass or interfaceandroid.os.Parcelable$ClassLoaderCreator,碰到这样的情况,可以使用-dontwarncom.xx.yy.**,不对错误提出警告。
注意:使用这个方式的话,要确保自己没有用到这个库里面的类!否则就会抛ClassNotFoundException!
如果在工程中确实用到了该类,采用上面方式还是不行。这个时候就要再增加一项:-keep class com.xx.yy.** { *;},让当前类不混淆。
总结:
对于引用第三方包的情况,可以采用下面方式避免打包出错:
-libraryjars /aaa.jar
-dontwarn com.xx.yy.**
-keep class com.xx.yy.** { *;}
最后打包成功,祝君成功混淆加密!