关于防止android apk被反编译的技术我们前面已经讲了四种。

加壳技术

运行时修改字节码

伪加密

对抗JD-GUI

如果有不明白的可以查看我的博客的前四篇中关于这四种技术的介绍。接下来我们接着介绍另一种防止apk反编译的技术-完整性校验。

 

一、完整性校验原理

所谓完整性校验就是我们用各种算法来计算一个文件的完整性,防止这个文件被修改。其中常用的方法就是计算一个文件的CRC32的值或者计算一个文件的哈希值。我们在防止apk被反编译的方法中也可以采用这种方法。我们知道apk生成的classes.dex主要由java文件生成的,它是整个apk的逻辑实现。所以我们可以对classes.dex文件进行完整性校验,来保证整个程序的逻辑不被修改。如果我们想要保证整个apk文件的完整性,也可以对整个apk文件进行完整性校验。下面我们分别来实现对classes.dex文件和apk文件的完整性校验。

 

二、用crc32对classes.dex文件的完整性进行校验

 

(1)可以打印出来我们的apk生的classes.dex文件的crc32的值,代码如下:

public  class  MainActivity extendsActivity {

  
@Override

  
protected  void  onCreate(BundlesavedInstanceState) {

  
     super .onCreate(savedInstanceState);

  
     setContentView(R.layout.activity_main);

  
     String apkPath = getPackageCodePath();

  
     Long dexCrc = Long.parseLong(getString(R.string.classesdex_crc));

  
     try

  
     {

  
         ZipFile zipfile =  new  ZipFile(apkPath);

  
         ZipEntry dexentry = zipfile.getEntry( "classes.dex" );

  
         Log.i( "verification" , "classes.dexcrc=" +dexentry.getCrc());

  
         if (dexentry.getCrc() != dexCrc){

  
         Log.i( "verification" , "Dexhas been modified!" );

  
         } else {

  
         Log.i( "verification" , "Dex hasn't been modified!" );

  
         }

  
     }  catch  (IOException e) {

  
      // TODO Auto-generated catch block

  
      e.printStackTrace();

  
     }

  
    }

  
}


 

注意:R.string.classesdex_crc的值现在可以是个随机数。

(2)运行程序打印结果,我的apk程序的classes.dex的crc32的值为713769644

(3)将上面程序的classes.dex文件的crc32的值,保存在资源文件字符串中classesdex_crc中(当然也可以保存在服务器上,然后通过网络获取校验),然后再运行上面的apk程序,打印如下:

Dex hasn't beenmodified!

(4)这时我们在上面的代码中随便加一行或者一个空格,然后重新编译运行会看到我们的程序的crc32的值改变了。程序打印如下:

Dex has beenmodified!

 

三、用哈希值对整个apk完整性进行校验

由于我们要对整个apk的完整性进行校验,所以我们的算出哈希值就不能存在资源文件中了因为apk中任何的改动都会引起最终apk生成的哈希值的不同。

(1)首先实现apk中计算自身哈希值的代码,如下:

public  class  MainActivity extendsActivity {

  
@Override

  
protectedvoid onCreate(Bundle savedInstanceState) {

  
      super .onCreate(savedInstanceState);

  
      setContentView(R.layout.activity_main);

  
      String apkPath = getPackageCodePath();

  
      MessageDigest msgDigest =  null ;

  
      try  {

  
         msgDigest = MessageDigest.getInstance( "SHA-1" );

  
         byte [] bytes =  new  byte [ 1024 ];

  
         int  byteCount;

  
         FileInputStream fis =  new  FileInputStream( new  File(apkPath));

  
         while  ((byteCount = fis.read(bytes)) >  0 )

  
         {

  
             msgDigest.update(bytes,  0 , byteCount);

  
         }

  
         BigInteger bi =  new  BigInteger( 1 , msgDigest.digest());

  
         String sha = bi.toString( 16 );

  
         fis.close();

  
         //这里添加从服务器中获取哈希值然后进行对比校验

  
         }  catch  (Exception e) {

  
             e.printStackTrace();

  
         }

  
     }

  
}

(2)用linux下的sha1sum命令计算我们的apk的哈希值,命令如下:

sha1sum verification.apk

(3)将(2)中生成的哈希值存到服务器上,然后在我们的代码中从服务器获取进行完整性比较。

 

上面我们用计算crc32和哈希值的方法分别对classes.dex文件和整个apk完整性进行了校验,当然两个校验方法也可以互换使用。