Android APK加壳技术方案

               

本文章由Jack_Jia编写,转载请注明出处。  
文章链接:
http://blog.csdn.net/jiazhijun/article/details/8678399
作者:Jack_Jia    邮箱: [email protected]


一、什么是加壳?

       加壳是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作。大多数病毒就是基于此原理。PC EXE文件加壳的过程如下:


     


二、加壳作用

       加壳的程序可以有效阻止对程序的反汇编分析,以达到它不可告人的目的。这种技术也常用来保护软件版权,防止被软件破解。


三、Android Dex文件加壳原理

       PC平台现在已存在大量的标准的加壳和解壳工具,但是Android作为新兴平台还未出现APK加壳工具。Android Dex文件大量使用引用给加壳带来了一定的难度,但是从理论上讲,Android APK加壳也是可行的。

       在这个过程中,牵扯到三个角色:

           1、加壳程序:加密源程序为解壳数据、组装解壳程序和解壳数据

           2、解壳程序:解密解壳数据,并运行时通过DexClassLoader动态加载

           3、源程序:需要加壳处理的被保护代码

       阅读该文章,需要您对DEX文件结构有所了解,您可以通过以下网址了解相关信息:

        http://blog.csdn.net/jiazhijun/article/details/8664778


       根据解壳数据在解壳程序DEX文件中的不同分布,本文将提出两种Android Dex加壳的实现方案。


    (一)解壳数据位于解壳程序文件尾部


              该种方式简单实用,合并后的DEX文件结构如下。




          加壳程序工作流程:

                  1、加密源程序APK文件为解壳数据

                  2、把解壳数据写入解壳程序Dex文件末尾,并在文件尾部添加解壳数据的大小。

                  3、修改解壳程序DEX头中checksum、signature 和file_size头信息。

                  4、修改源程序AndroidMainfest.xml文件并覆盖解壳程序AndroidMainfest.xml文件。


          解壳DEX程序工作流程:

                  1、读取DEX文件末尾数据获取借壳数据长度。

                  2、从DEX文件读取解壳数据,解密解壳数据。以文件形式保存解密数据到a.APK文件

                  3、通过DexClassLoader动态加载a.apk。


(二)解壳数据位于解壳程序文件头


          该种方式相对比较复杂, 合并后DEX文件结构如下:




          加壳程序工作流程:

                  1、加密源程序APK文件为解壳数据

                  2、计算解壳数据长度,并添加该长度到解壳DEX文件头末尾,并继续解壳数据到文件头末尾。

                       (插入数据的位置为0x70处

                  3、修改解壳程序DEX头中checksum、signature、file_size、header_size、string_ids_off、type_ids_off、proto_ids_off、field_ids_off、

              method_ids_off、class_defs_off和data_off相关项。  分析map_off 数据,修改相关的数据偏移量。  

                  4、修改源程序AndroidMainfest.xml文件并覆盖解壳程序AndroidMainfest.xml文件。


          解壳DEX程序工作流程:

                  1、从0x70处读取解壳数据长度。

                  2、从DEX文件读取解壳数据,解密解壳数据。以文件形式保存解密数据到a.APK

                  3、通过DexClassLoader动态加载a.APK。


   四、加壳及脱壳代码实现


          http://blog.csdn.net/jiazhijun/article/details/8809542


一、序言


        在上篇“Android APK加壳技术方案”(http://blog.csdn.net/jiazhijun/article/details/8678399)博文中,根据加壳数据在解壳程序Dex文件所处的位置,我提出了两种Android Dex加壳技术实现方案,本片博文将对方案1代码实现进行讲解。博友可以根据方案1的代码实现原理对方案2自行实现。

       在方案1的代码实现过程中,各种不同的问题接踵出现,最初的方案也在不同问题的出现、解决过程中不断的得到调整、优化。

       本文的代码实现了对整个APK包的加壳处理。加壳程序不会对源程序有任何的影响。


二、代码实现


     本程序基于Android2.3代码实现,因为牵扯到系统代码的反射修改,本程序不保证在其它android版本正常工作,博友可以根据实现原理,自行实现对其它Android版本的兼容性开发。


     1、 加壳程序流程及代码实现

                  1、加密源程序APK为解壳数据

                  2、把解壳数据写入解壳程序DEX文件末尾,并在文件尾部添加解壳数据的大小。

                  3、修改解壳程序DEX头中checksum、signature 和file_size头信息。


       代码实现如下:

[java]  view plain copy
  1. package com.android.dexshell;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.security.MessageDigest;  
  8. import java.security.NoSuchAlgorithmException;  
  9. import java.util.zip.Adler32;  
  10.   
  11. public class DexShellTool {  
  12.     /** 
  13.      * @param args 
  14.      */  
  15.     public static void main(String[] args) {  
  16.         // TODO Auto-generated method stub  
  17.         try {  
  18.             File payloadSrcFile = new File("g:/payload.apk");  
  19.             File unShellDexFile = new File("g:/unshell.dex");  
  20.             byte[] payloadArray = encrpt(readFileBytes(payloadSrcFile));  
  21.             byte[] unShellDexArray = readFileBytes(unShellDexFile);  
  22.             int payloadLen = payloadArray.length;  
  23.             int unShellDexLen = unShellDexArray.length;  
  24.             int totalLen = payloadLen + unShellDexLen +4;  
  25.             byte[] newdex = new byte[totalLen];  
  26.             //添加解壳代码  
  27.             System.arraycopy(unShellDexArray, 0, newdex, 0, unShellDexLen);  
  28.             //添加加密后的解壳数据  
  29.             System.arraycopy(payloadArray, 0, newdex, unShellDexLen,  
  30.                     payloadLen);  
  31.             //添加解壳数据长度  
  32.             System.arraycopy(intToByte(payloadLen), 0, newdex, totalLen-44);  
  33.                         //修改DEX file size文件头  
  34.             fixFileSizeHeader(newdex);  
  35.             //修改DEX SHA1 文件头  
  36.             fixSHA1Header(newdex);  
  37.             //修改DEX CheckSum文件头  
  38.             fixCheckSumHeader(newdex);  
  39.   
  40.   
  41.             String str = "g:/classes.dex";  
  42.             File file = new File(str);  
  43.             if (!file.exists()) {  
  44.                 file.createNewFile();  
  45.             }  
  46.               
  47.             FileOutputStream localFileOutputStream = new FileOutputStream(str);  
  48.             localFileOutputStream.write(newdex);  
  49.             localFileOutputStream.flush();  
  50.             localFileOutputStream.close();  
  51.   
  52.   
  53.         } catch (Exception e) {  
  54.             // TODO Auto-generated catch block  
  55.             e.printStackTrace();  
  56.         }  
  57.     }  
  58.       
  59.     //直接返回数据,读者可以添加自己加密方法  
  60.     private static byte[] encrpt(byte[] srcdata){  
  61.         return srcdata;  
  62.     }  
  63.   
  64.   
  65.     private static void fixCheckSumHeader(byte[] dexBytes) {  
  66.         Adler32 adler = new Adler32();  
  67.         adler.update(dexBytes, 12, dexBytes.length - 12);  
  68.         long value = adler.getValue();  
  69.         int va = (int) value;  
  70.         byte[] newcs = intToByte(va);  
  71.         byte[] recs = new byte[4];  
  72.         for (int i = 0; i < 4; i++) {  
  73.             recs[i] = newcs[newcs.length - 1 - i];  
  74.             System.out.println(Integer.toHexString(newcs[i]));  
  75.         }  
  76.         System.arraycopy(recs, 0, dexBytes, 84);  
  77.         System.out.println(Long.toHexString(value));  
  78.         System.out.println();  
  79.     }  
  80.   
  81.   
  82.     public static byte[] intToByte(int number) {  
  83.         byte[] b = new byte[4];  
  84.         for (int i = 3; i >= 0; i--) {  
  85.             b[i] = (byte) (number % 256);  
  86.             number >>= 8;  
  87.         }  
  88.         return b;  
  89.     }  
  90.   
  91.   
  92.     private static void fixSHA1Header(byte[] dexBytes)  
  93.             throws NoSuchAlgorithmException {  
  94.         MessageDigest md = MessageDigest.getInstance("SHA-1");  
  95.         md.update(dexBytes, 32, dexBytes.length - 32);  
  96.         byte[] newdt = md.digest();  
  97.         System.arraycopy(newdt, 0

猜你喜欢

转载自blog.csdn.net/qq_44910516/article/details/89397927