经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
安卓应用加固之四代加壳保护技术详解
来源:cnblogs  作者:Paladin2wink  时间:2019/8/2 8:32:58  对本文有异议

#0x00 前言

安卓应用加固技术是伴随安卓应用破解技术一同发展起来的。

安卓应用加固技术的发展可以划分为以下几代技术:

第一代壳:Dex混淆、Dex加密、资源加密、反调试及自定义DexClassLoader

第二代壳:Dex抽取与so加固、Dex Method代码抽取、Dex动态加载及so加固

第三代壳:Dex动态解密及so混淆、Dex Method代码动态解密及so代码膨胀混淆

第四代壳:代码虚拟化保护(O-LLVM技术)

 

#0x01 第一代壳

一、Dex混淆

1.代码混淆

即将源程序代码中的类名、方法名修改为a、b、c()的形式,让破解这不能通过类名、方法名轻易地寻找/猜测到函数所实现的功能,增加逆向分析的难度

 

2.编译期混淆

若APK在开发时使用的是LLVM编译套件进行编译,则可以在编译期间对代码进行混淆。分为前端混淆IR混淆

前端混淆:指编译器前端在进行原生代码分析时采取的混淆技术

IR混淆:指在编译原生代码时对生成的中间代码IR进行混淆的技术

 

3.二进制混淆

在生成APK文件后,提取出其中的二进制文件,对二进制文件再进行混淆。典型的技术有Dex二次混淆,即对生成的Dex文件进行反编译后,再进行混淆。使得Dex的执行流程被混淆和字符串被混淆。

 

  1. 1 //以字符串混淆为例
  2. 2
  3. 3 //混淆前
  4. 4 void methodA()
  5. 5 {
  6. 6 clz.method1("abc");
  7. 7 clz.method3(clz.method2("def"),"ghi");
  8. 8 }
  9. 9
  10. 10 //使用ProGuard进行代码混淆后的反汇编代码可能如下
  11. 11 void methodA()
  12. 12 {
  13. 13 a.a("abc");
  14. 14 a.aaa(a.aa("def"),"ghi");
  15. 15 }
  16. 16
  17. 17 //使用DexGuard进行代码混淆后的反汇编代码可能如下,b.a()方法
  18. 18 void methodA()
  19. 19 {
  20. 20 a.a(b.a("xxxxxxxxx"));
  21. 21 a.aaa(a.aa(b.a("yyyyyyyyy")),b.a("zzzzzzzzz"));
  22. 22 }

 

 

二、Dex加密

 Dex加密指将APK的DEX文件进行加密,在运行时再解密加载到内存中执行,防止Dex文件被逆向的一种保护技术。

Dex加密APK的执行流程如下图

 

加固过程

1.需要编写三个项目:

(1)源APK(真正的APK程序)

(2)加壳程序(Java项目,用于对源APK文件进行加密,并将加密后的源APK与解密dex进行合并)

(3)脱壳程序(Android项目,用于对加密后的源dex文件进行解密,并将其加载到内存中去)

2.加壳程序将源APK加密成所有操作系统都不能正确读取的APK文件。

3.加壳程序再提取出解密APK的classes.dex文件,将解密apk的dex文件与加密后的源apk进行合并,得到新的dex文件

4.并在新dex文件的末尾添加一个长度为4位的字段,用于标识加密apk的大小

5.修改新dex文件的头部三个字段:checksum,signature,file_size,以保证新dex文件的正确性

 

Dex加密流程如下图

 

 

加壳程序主要逻辑代码分析:

  1. 1 public static void main(String args[])
  2. 2 {
  3. 3 try
  4. 4 {
  5. 5 //---------获取文件
  6. 6 //获取需要加密的源apk程序
  7. 7 File payloadSrcFile = new File("xxxx/abc.apk");
  8. 8 System.out.println("SrcAPK size:"+payloadSrcFile.length());
  9. 9 //获取脱壳(解密)程序的DEX文件,需要提前把脱壳程序的DEX文件解压出来
  10. 10 File unshellDexFile = new File("yyyy/classes.dex");
  11. 11
  12. 12 //---------加密源apk文件
  13. 13 /*
  14. 14 以二进制形式读取apk,并加密,存到payloadArray数组中
  15. 15 readFileBytes是以二进制形式读取文件
  16. 16 encrpt()是自定义的对二进制流加密的函数
  17. 17 */
  18. 18 byte[] payloadArray = encrpt(readFileBytes(payloadSrcFile));
  19. 19 //以二进制形式读取脱壳dex
  20. 20 byte[] unshellDexArray = readFileBytes(unshellDexFile);
  21. 21
  22. 22 //---------合并
  23. 23 //***1.计算出新Dex文件的总长度
  24. 24 int payloadLen = payloadArray.length(); //加密APK的长度
  25. 25 int unshellDexLen = unshellDexArray.length(); //脱壳Dex的长度
  26. 26 int totalLen = payloadLen+unshellDexLen=4 //新的Dex文件长度,最后+4是为了用于存储payloadLen值的
  27. 27 //***2.定义新dex文件
  28. 28 //先定义新dex文件的长度
  29. 29 byte[] newDex = new byte[totalLen];
  30. 30 //***3.开始合并
  31. 31 //将脱壳dex文件的内容写入新dex
  32. 32 System.arraycopy(unshellDexArray,0,newDex,0,unshellDexLen);
  33. 33 //再将加密后的源APK内容连接在后面
  34. 34 /*
  35. 35 arraycopy(arr1,x,arr2,y,m)表示将数组arr1从索引为x开始的元素,复制m个元素到数组arr2中去,从arr2的y索引开始粘贴
  36. 36 */
  37. 37 System.arraycopy(payloadArray,0,newDex,unshellDexLen,payloadLen);
  38. 38 //最后将将加密后的apk长度记录在新dex文件末尾
  39. 39 /*
  40. 40 intToByte()将int类型数据转换成Byte
  41. 41 total是int类型的,newDex是Byte类型
  42. 42 total是脱壳dex长度+加密apk长度+4,所以,最后是从newDex的第total-4索引开始写入payload的长度
  43. 43 一个byte是1个字节,即8位;一个int是4个字节,即32位;所以最后的4表示写入intToByte(payloadLen)的4个元素
  44. 44 */
  45. 45 System.arraycopy(intToByte(payloadLen),0,newDex,totalLen-4,4);
  46. 46
  47. 47 //---------修改新dex文件的头部信息
  48. 48 //修改file_size字段
  49. 49 fixFileSizeHeader(newDex);
  50. 50 //修改signature字段
  51. 51 fixSHA1Header(newDex);
  52. 52 //修改checksum字段
  53. 53 fixCheckSumHeader(newDex);
  54. 54 //---------生成新dex文件
  55. 55 //定义要生成文件的路径及名称并创建空文件
  56. 56 String str = "zzzz/classes.dex";
  57. 57 File file = new File(str);
  58. 58 if (!file.exists())
  59. 59 {
  60. 60 file.createNewFile();
  61. 61 }
  62. 62 //将合并好的数据写入文件
  63. 63 FileOutputStream localFileOutputStream = new FileOutputStream(str);
  64. 64 localFileOutputStream.write(newDex);
  65. 65 localFileOutputStream.flush();
  66. 66 localFileOutputStream.close();
  67. 67 }catch (Exception e) {
  68. 68 e.printStackTrace();
  69. 69 }
  70. 70 }
  71. 71
  72. 72 //加密函数encrpt()的定义
  73. 73 private static byte[] encrpt(byte data[])
  74. 74 {
  75. 75 //加密算法实现,这里就不写了
  76. 76 return data;
  77. 77 }
View Code

 

 

脱壳流程如下图:

 

 

脱壳程序主要逻辑代码分析:

 

 

 

#0x02 第二代壳

 

 

 

 

#0x03 第三代壳

 

 

 

 

 

#0x04 第四代壳

 

原文链接:http://www.cnblogs.com/victor-paladin/p/11283472.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号