Chinaunix首页 | 论坛 | 博客
  • 博客访问: 424062
  • 博文数量: 205
  • 博客积分: 5630
  • 博客等级: 大校
  • 技术积分: 1945
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-06 20:28
文章分类

全部博文(205)

文章存档

2016年(1)

2015年(6)

2014年(9)

2013年(10)

2012年(53)

2011年(25)

2010年(87)

2009年(14)

分类: Android平台

2013-12-02 10:41:35

我们知道,利用apktool可以将apk反编译为smali文件,利用 dex2jar也可以将apk反编译为jar文件。这样的话,破解者就可以根据关键代码(比如资源文件中的字符串),修改代码,然后再利用apktool 重新编译,并运行signapk.bat重新签名打包为己所用,而你辛辛苦苦几个月的努力一下回到解放前!

那么,怎样防止破解呢?其实之前介绍的利用proguard进行代码混淆就是一种方式,它可以有效增加利用dex2jar反编译后破解的难度。另外,也可以通过检测调试器、模拟器、签名的hash值和classes.dex文件的crc值来确定确认apk文件的完整性。

检测调试器

我们发布时将AndroidManifest.xml文件中的application的android:debuggable属性设为false,程序运行时再去检测:

点击(此处)折叠或打开

  1. public void checkDebug(){
  2.  if((getApplicationInfo().flags&=ApplicationInfo.FLAG_DEBUGGABLE)!=0){
  3.      android.os.Process.killProcess(android.os.Process.myPid());
  4.  }
  5. }


此外,Android SDK还提供了一个专门检测debugger是否连接的方法:



android.os.Debug.isDebuggerConnected(); 


这样就不用在AndroidManifest.xml里配置字段了。

检测模拟器

通过dab shell getprop可以发现模拟器客真机这几个属性不一致:
ro.product.model: 模拟器中为”sdk”,真机中为具体型号;
ro.build.tags: 模拟器中为”test-keys”,真机中为”release-keys”;
ro.kernel.qemu: 模拟器中为”1”,真机中不存在;
下面以第三个字段为例做检测:


点击(此处)折叠或打开

  1. public boolean isRunningInEmulator(){
  2.     boolean qemuKernel=false;
  3.     Process process=null;
  4.      DataOutpusStream os=null;
  5.      try{
  6.          process=Runtime.getRuntime().exec("get prop ro.kernel.qemu");
  7.          os=new DataOutputStream(process.getOutputStream()); 
  8.          BufferedReader in=new BufferedReader( new InputStreamReader(process.getInputStream(), "GBK"));
  9.         os.writeBytes("exit\n");
  10.          os.flush();
  11.          process.waitFor();
  12.         qemuKernel=(Integer.valueOf(in.readLine())==1);
  13.     }catch(Exception e){
  14.          e.printStackTrace();      
  15.          }finally{
  16.             try{
  17.              if(os!=null){
  18.                  os.close();
  19.              } 
  20.         }catch(Exception e){
  21.             e.printStackTrace(); 
  22.         }
  23.      }
  24.      return qemuKernel;
  25. }


检查签名的hash值

Android的PackageManager类提供了读取签名信息方法:


点击(此处)折叠或打开

  1. public int getSignature(Context context, String packageName){
  2.     PackageManager pm=context.getPackageManager();
  3.     PackageInfo pi=null; int sig=0; 
  4.     try{
  5.         pi=pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
  6.          Signature[] s=pi.signatures;
  7.         sig=s[0].hashCode();
  8.     }catch(Exception e){
  9.      sig=0; e.printStackTrace();
  10.     }
  11.     return sig;
  12. }

打包发布前我们将这个hash值保存在server端,程序运行时再去比对。

检查classes.dex文件CRC值

apk文件本质上是zip压缩文件,而Android SDK自带了读取zip压缩包CRC值的API:


点击(此处)折叠或打开

  1. public long getDexCrc(Context context){ 
  2.     long crc=0;
  3.      ZipFile zf;
  4.      try{
  5.          zf=new ZipFile(context.getApplicationContext().getPackageCodePath()); 
  6.          ZipEntry ze=zf.getEntry("classes.dex");
  7.          crc=ze.getCrc();
  8.      }catch(Exception e){
  9.          e.printStackTrace();
  10.      }
  11.      return cry; 
  12. }

打包发布前我们也可以将这个crc值保存在server端,程序运行时再去比对。
将以上几种方式结合起来,就可以大大增强apk文件的破解难度。

最后,网上有些大神说还可以通过对apktool和dex2jar等反编译工具进行压力测试,以得到错误信息,而这些工具是开源的,这样我们就可以顺藤摸瓜地找到这些工具本身的漏洞,进而在我们的代码中加以利用,达到釜底抽薪的作用。例如对dex2jar运行这个批处理:


1 
for %%i in (*.apk) do dex2jar %%i
这种思路理论上是行得通的,但我没有亲测过,这里就不再多说了。


阅读(1166) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~