Android安全专项-Apk加固
Posted Q博士
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android安全专项-Apk加固相关的知识,希望对你有一定的参考价值。
参考文章
Android APK加壳技术方案【1】
Android APK加壳技术方案【2】
Android中的Apk的加固(加壳)原理解析和实现
0x00
原理部分我不献丑了,上面3篇文章说的很清楚,我直接实战,讲述从0开始如何最终实现加固的整个过程,踩了不少坑。
0x01
第一步创建被加固Apk,就是你的源码Apk。你做的工作就是防止这个Apk被破解。这个APK要注意以下几点:
记住你的主Actvitiy名和其他Activity名
从途中可知我们的主Activity为doctorq.com.mysourceapk.MainActivity
还有一个Activity名为doctorq.com.mysourceapk..SubActivity
记住你创建的Application名
从图中可知我们的Application为doctorq.com.mysourceapk.MyApplication
尽量不要添加布局文件
采用的方式和参考文章的做法是一样的,显式添加控件,如下:
TextView content = new TextView(this);
content.setText("I am Source Apk");
content.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(MainActivity.this, SubActivity.class);
startActivity(intent);
}
});
setContentView(content);
Log.i("demo", "app:" + getApplicationContext());
activity的父类都为Activity
继承于AppCompatActivity
在解壳程序中运行的时候报如下的错误,自身运行没啥问题:
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/androidRuntime: FATAL EXCEPTION: main
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: Process: xposed.doctorq.com.decode2, PID: 16721
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: java.lang.NoClassDefFoundError: doctorq/com/mysourceapk/SubActivity
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at doctorq.com.mysourceapk.MainActivity$1.onClick(MainActivity.java:21)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View.performClick(View.java:4444)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View$PerformClick.run(View.java:18440)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:733)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Looper.loop(Looper.java:136)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5001)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: Caused by: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexFile.defineClassNative(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexFile.defineClass(DexFile.java:222)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:215)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.DexPathList.findClass(DexPathList.java:322)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at doctorq.com.mysourceapk.MainActivity$1.onClick(MainActivity.java:21)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View.performClick(View.java:4444)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.view.View$PerformClick.run(View.java:18440)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:733)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.os.Looper.loop(Looper.java:136)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5001)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
03-23 13:50:12.258 16721-16721/xposed.doctorq.com.decode2 E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
效果
这个demo就是主界面上有一个TextView,可以点击跳转到下一个Activity。
这个时候我们能APK文件,这个文件我们第三步需要用。
0x02
第二步解壳程序,也就是源程序的宿主,他也是一个APK,但是这个APK需要注意的地方更多,我踩了很多坑:
修改AndroidManifest.xml
这个文件的修改位置很多,修改后如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xposed.doctorq.com.decode2" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name="xposed.doctorq.com.decode2.ProxyApplication">
<meta-data android:name="APPLICATION_CLASS_NAME" android:value="doctorq.com.mysourceapk.MyApplication"/>
<activity
android:name="doctorq.com.mysourceapk.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="doctorq.com.mysourceapk.SubActivity" >
</activity>
</application>
</manifest>
主要修改位置有以下几点:
添加meta-data信息
这个APPLICATION_CLASS_NAME
指向的是我们源码中的Application
的子类,这也是之前特别提醒的原因
<meta-data android:name="APPLICATION_CLASS_NAME" android:value="doctorq.com.mysourceapk.MyApplication"/>
修改主Activity
我们要讲解壳程序本身的Activity替换成源码的主Activity,这个时候解壳程序里的activity其实是没有用的,删掉也不影响。
<activity
android:name="doctorq.com.mysourceapk.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
添加其他Activity
我们在源码程序的中activity都要在解壳程序的配置文件中配置:
<activity android:name="doctorq.com.mysourceapk.SubActivity" >
</activity>
在ProxyApplication的修改
主要修改就是主Activity的修改:
try {
Object actObj = dLoader.loadClass("doctorq.com.mysourceapk.MainActivity");
Log.i("demo", "actObj:" + actObj);
} catch (Exception e) {
Log.i("demo", "activity:" + Log.getStackTraceString(e));
}
打包
因为你修改的包名啊,activity
名啊,是识别不了的,这个时候可以通过gradle
的assemble
来打包。
这个时候得到我们解壳程序的APK和dex文件,这两个文件我们一会都要用。
0x03
第三步加固工具,这个工具是一个java项目,我们在eclipse中创建:具体的原理是将源码APK加到解壳程序的dex文件后面。这个没什么坑,没啥可讲的,加固成功后,会得到一个产物,我们将这个产物命名为classes.dex,因为一会要替换到解壳APK中的classes.dex文件。
0x04
第四步是替换解壳程序中的classes.dex,这个时候用到WinRAR工具,首先找到解壳程序,然后删除借壳程序中的classes.dex,添加第三部产生的classes.dex文件
0x05
第五步是重签名,因为APK
被修改了,这个时候直接安装,会报无签名的错误,所以这个时候我们用Auto-sign
这个工具去签名,具体做法我在Android安全专项测试之反编译中讲过。
安装完毕后,可以打开我们的解壳程序了,这个时候一定要看清楚我们进的是解壳程序的app,而不是我们之前的源码app:
0x06
0x07
这个demo
中我们的源码中没有布局文件,这在实际项目中是不可能,那么这些布局文件怎么添加,有人提出将所有布局文件添加到解壳程序中,这样就能找到了。
0x08
我们做了这么多,真的加固了么?ok,我们来实验下,我们用apktool来反编译下:
58deMacBook-Pro-7:Auto-sign wuxian$ apktool d testerhome.apk
I: Using Apktool 2.0.3 on testerhome.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/wuxian/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...
实际上是成功的,有的人就会疯了,你不是说加固了,怎么还能被反编译了,我们来看看反编译后的产物:
你会发现,我们看不到源码demo项目中的代码,连包名都没发现,你能看到的只是解壳程序的东西,我们加固的目的是起到了,但是解壳程序能被反编译也是有风险的,毕竟我们的一些核心代码写在了ProxyApplication
中,这又怎么办呢?我暂时也不知道,思考一下吧
以上是关于Android安全专项-Apk加固的主要内容,如果未能解决你的问题,请参考以下文章