Android apk如何加固防止被破解(防止逆向编译)

来源:互联网 发布:java从入门到精通下载 编辑:程序博客网 时间:2024/05/17 03:10

防破解技术主要有四种实现方式: 
1.代码混淆(ProGuard)技术 
2.签名比对技术 
3.NDK .so 动态库技术 
4.动态加载技术 
5.第三方平台加密以及检测漏洞

这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。

  • 第一种: 代码混淆技术(ProGuard) 该技术主要是进行代码混淆,降低代码逆向编译后的可读性,但该技术无法防止加壳技术进行加壳(加入吸费、广告、病毒等代码),而且只要是细心的人,依然可以对代码依然可以对代码进行逆向分析,所以该技术并没有从根本解决破解问题,只是增加了破解难度。
  • 第二种: 签名比对技术 该技术主要防止加壳技术进行加壳,但代码逆向分析风险依然存在。而且该技术并不能根本解决被加壳问题,如果破解者将签名比对代码注释掉,再编译回来,该技术就被破解了。
  • 第三种: NDK .so动态库技术,该技术实现是将重要核心代码全部放在C文件中,利用NDK技术,将核心代码编译成.so动态库,再用JNI进行调用。该技术虽然能将核心代码保护起来,但被加壳风险依然存在。
  • 第四种: 动态加载技术,该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。
  • 第五种: 第三方平台使用

    主要讲解第四种方法,该技术可以有效的防止逆向分析、被破解、被加壳等问题,动态加载技术分为以下几步:

  • 将核心代码编译成dex文件的Jar包

  • 对jar包进行加密处理
  • 在程序主入口利用NDK进行解密
  • 再利用ClassLoader将jar包进行动态加载
  • 利用反射技术将ClassLoader 设置成系统的ClassLoader。

主要优点有: 
       1.核心代码在被加密的jar中,所以破解者无法解压出class文件,如果加密秘钥被破解者拿到,那将是另外一层面的安全问题了。 
      2.该技术也可以有效防止加壳技术,代码是动态加载上来的,破解者的壳程序无法加入到已加密的jar包中,及时破解者注入壳程序入口,壳程序因为不在ClassLoader 的jar包中,所以也无法被执行起来,除非破解者替换ClassLoader的jar包,关掉NDK解密代码.但这种安装到手机上,已经不在是我们的应用,用户一定会将其卸载掉。

所以综合起来比较,第四种动态加载技术是最安全的,但效率问题,本人并没做严格测试,粗略实验了一下,效率并没有明显降低。

//   1.Jar包加密加密解密文件//  public static boolean enOrDecryptFile(byte[] paramArrayOfByte,          String sourceFilePath, String destFilePath,int mode){      File sourceFile = new File(sourceFilePath);      File destFile = new File(destFilePath);      CipherOutputStream cout = null;      FileInputStream in  = null;      FileOutputStream out = null;      if (sourceFile.exists() && sourceFile.isFile()) {          if (!destFile.getParentFile().exists()) {              destFile.getParentFile().mkdirs();          }          try {              destFile.createNewFile();              in = new FileInputStream(sourceFile);              out = new FileOutputStream(destFile);              // 获取密钥//              init();              SecretKeySpec secretKeySpec = new SecretKeySpec(defPassword, "AES");              Cipher cipher;              cipher = Cipher.getInstance("AES");              cipher.init(mode, secretKeySpec);              cout = new CipherOutputStream(out, cipher);              byte[] cache = new byte[CACHE_SIZE];              int nRead = 0;              while ((nRead = in.read(cache)) != -1) {                  cout.write(cache, 0, nRead);                  cout.flush();              }          }catch (IOException e) {              e.printStackTrace();              return false;          } catch (NoSuchAlgorithmException e) {              e.printStackTrace();              return false ;          } catch (NoSuchPaddingException e) {              e.printStackTrace();              return false ;          }catch (InvalidKeyException e) {              e.printStackTrace();              return false;          }finally{                  if(cout != null){                      try {                          cout.close();                      } catch (IOException e) {                          e.printStackTrace();                      }                  }                  if(out != null){                      try {                          out.close();                      } catch (IOException e) {                          e.printStackTrace();                      }                  }                  if(in != null){                      try {                          in.close();                      } catch (IOException e) {                          e.printStackTrace();                      }                  }          }          return true;      }      return false;  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

jar用SDK\platform-tools\下的dx命令进行dex格式转化

dx   --dex    --output=生成的目标文件的地址(绝对路径)     需要转化的jar文件(绝对路径)                       例如:dx --dex --output=H:\classdex.jar     H:\dujinyang-KARL.jar
  • 1
  • 2
  • 1
  • 2

然后再用加密工具将生成jar文件进行加密处理

最后通过代码动态加载:

File file = new File("/data/data/" + base.getPackageName() + "/.cache/");          if (!file.exists()) {              file.mkdirs();          }          try {              Runtime.getRuntime().exec("chmod 755 " + file.getAbsolutePath()).waitFor();          } catch (InterruptedException e1) {              // TODO Auto-generated catch block              e1.printStackTrace();          } catch (IOException e1) {              // TODO Auto-generated catch block              e1.printStackTrace();          }          Util.copyJarFile(this);          Object currentActivityThread = RefInvoke.invokeStaticMethod(                  "android.app.ActivityThread", "currentActivityThread",                  new Class[] {}, new Object[] {});          String packageName = getPackageName();          HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect(                  "android.app.ActivityThread", currentActivityThread,                  "mPackages");          WeakReference wr = (WeakReference) mPackages.get(packageName);          MyClassLoader dLoader = new MyClassLoader("/data/data/"                  + base.getPackageName() + "/.cache/classdex.jar", "/data/data/"                  + base.getPackageName() + "/.cache", "/data/data/"                  + base.getPackageName() + "/.cache/", base.getClassLoader());          try {              Class<?>  class1 = dLoader.loadClass("com.example.test.TestActivity");              Log.i("b364","----------->class1: "+class1);          } catch (ClassNotFoundException e){              Log.i("b364","----------->class not found Exception!");              e.printStackTrace();          }          Log.i("b364","------>PackageInfo: "+wr.get());          // DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath,          // libPath, (ClassLoader) RefInvoke.getFieldOjbect(          // "android.app.LoadedApk", wr.get(), "mClassLoader"));          RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader",                  wr.get(), dLoader);  
0 0
原创粉丝点击