如何彻底防止反编译,dex加密怎么做

**面试官: 如何彻底防止反编译,dex加密怎么做 **
心理分析:面试官想知道你是否有过对dex加固相关的经验,该题想考的是dex加固流程,dex编码有没有了解
**求职者:**应该从dex加固流程 ,从项目中开始,dex加固--打包--验证 说起 。接下来给大家讲解dex原理分析
原理解析
下面看一下Android中加壳的原理: [
如何彻底防止反编译,dex加密怎么做

文章插图
 
在加固过程中需要三个对象:
  • 需要加密的APK(源程序APK)
  • 壳程序APK(负责解密APK工作)
  • 加密工具(将源APK进行加密和壳程序的DEX合并)
主要步骤 用加密算法对源程序APK进行加密,再将其与壳程序APK的DEX文件合并生成新的DEX文件,最后替换壳程序中的原DEX文件即可 。得到新的APK也叫做脱壳程序APK,它已经不是一个完整意义上的APK程序了,它的主要工作是:负责解密源程序APK,然后加载APK,让其正常运行起来 。在这个过程中需要了解的知识是:如何将源程序APK和壳程序APK进行合并 这需要了解DEX文件的格式,下面简单介绍一下:
addressnamesize/bytevalue0magic[8]80x6465 780a 3033 35008checksum40xc136 5e17csignature[20]2020file_size40x02e424header_size40x7028endian_tag40x123456782Clink_size40x0030link_off40x0034map_off40x024438string_ids_size40x0e3cstring_ids_off40x7040type_ids_size40x0744type_ids_off40xa848proto_ids_size40x034Cproto_ids_off40xc450field_ids_size40x0154field_ids_off40xe858method_ids_size40x045Cmethod_ids_off40xf060class_defs_size40x0164class_defs_off40x011068data_size40x01b46Cdata_off40x0130
现在只要关注其中三个部分:
  • checksum(文件校验码)使用alder32算法校验文件,除去magic、checksum外余下的所有文件区域,用于检查文件错误 。
  • signature 使用SHA-1算法hash出去magic、checksum和signature外余下的所有文件区域,用于唯一识别本文件 。
  • file_size DEX文件大小 。
【如何彻底防止反编译,dex加密怎么做】我们需要将加密之后的源程序APK文件写入到DEX中,那么就需要修改checksum,因为它的值和文件内容有关 。signature也是一样,也是唯一识别文件的算法,还有DEX文件的大小 。还需要一个操作,就是标注加密之后的源程序APK文件的大小,因为运行解密的时候,需要知道APK的大小,才能正确得到源程序APK 。这个值直接放到文件的末尾就可以了 。修改之后的DEX文件的格式如下:
如何彻底防止反编译,dex加密怎么做

文章插图
 
知道了原理,下面就是代码实现了 。这里有三个工程:
  • 源程序项目(需要加密的APK)
  • 壳项目(解密源程序APK和加载APK)
  • 对源APK进行加密和壳项目的DEX的合并
项目案例
下面先来看一下源程序 1.需要加密的源程序项目:SourceApk [
如何彻底防止反编译,dex加密怎么做

文章插图
 
需要一个Application类,这个到后面说为什么需要: MyApplication.JAVA
package com.example.sourceapk;public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Log.i("demo", "source apk onCreate:" + this); }}就是打印一下onCreate方法 。MainActivity.java
package com.example.sourceapk;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);TextView content = new TextView(this); content.setText("I am Source Apk"); content.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { Intent intent = new Intent(MainActivity.this, SubActivity.class); startActivity(intent); }}); setContentView(content);Log.i("demo", "app:"+getApplicationContext());}}2.加壳程序项目:DexPackTool
如何彻底防止反编译,dex加密怎么做

文章插图
 
加壳程序其实就是一个Java工程,它的工作就是加密源程序APK,然后将其写入到壳程序的DEX文件里,修改文件头,得到一个新的DEX文件 。看一下代码:
package com.example.packdex;public class mymain { public static void main(String[] args) { try { File payloadSrcFile = new File("files/SourceApk.apk"); // 需要加壳的源程序 System.out.println("apk size:"+payloadSrcFile.length()); File packDexFile = new File("files/SourceApk.dex"); // 壳程序dex byte[] payloadArray = encrpt(readFileBytes(payloadSrcFile)); // 以二进制形式读出源apk,并进行加密处理 byte[] packDexArray = readFileBytes(packDexFile); // 以二进制形式读出dex /* 合并文件 */ int payloadLen = payloadArray.length; int packDexLen = packDexArray.length; int totalLen = payloadLen + packDexLen + 4; // 多出4字节是存放长度的 byte[] newdex = new byte[totalLen]; // 申请了新的长度 // 添加解壳代码 System.arraycopy(packDexArray, 0, newdex, 0, packDexLen); // 先拷贝dex内容 // 添加加密后的解壳数据 System.arraycopy(payloadArray, 0, newdex, packDexLen, payloadLen); // 再在dex内容后面拷贝apk的内容 // 添加解壳数据长度 System.arraycopy(intToByte(payloadLen), 0, newdex, totalLen-4, 4); // 最后4字节为长度 // 修改DEX file size文件头 fixFileSizeHeader(newdex); // 修改DEX SHA1 文件头 fixSHA1Header(newdex); // 修改DEX CheckSum文件头 fixCheckSumHeader(newdex); String str = "files/classes.dex"; // 创建一个新文件 File file = new File(str); if (!file.exists()) { file.createNewFile(); }FileOutputStream localFileOutputStream = new FileOutputStream(str); localFileOutputStream.write(newdex); // 将新计算出的二进制dex数据写入文件 localFileOutputStream.flush(); localFileOutputStream.close(); } catch (Exception e) { e.printStackTrace(); } }// 直接返回数据,读者可以添加自己加密方法 private static byte[] encrpt(byte[] srcdata){ for (int i = 0; i < srcdata.length; i++) { srcdata[i] = (byte)(0xFF ^ srcdata[i]); } return srcdata; } ...}


推荐阅读