欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

安卓应用加固之四代加壳保护技术详解

程序员文章站 2022-06-23 23:12:55
#0x00 前言 安卓应用加固技术是伴随安卓应用破解技术一同发展起来的。 安卓应用加固技术的发展可以划分为以下几代技术: 第一代壳:Dex混淆、Dex加密、资源加密、反调试及自定义DexClassLoader 第二代壳:Dex抽取与so加固、Dex Method代码抽取、Dex动态加载及so加固 第 ......

#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 //以字符串混淆为例
 2 
 3 //混淆前
 4 void methoda()
 5 {
 6     clz.method1("abc");
 7     clz.method3(clz.method2("def"),"ghi");
 8 }
 9 
10 //使用proguard进行代码混淆后的反汇编代码可能如下
11 void methoda()
12 {
13     a.a("abc");
14     a.aaa(a.aa("def"),"ghi");
15 }
16 
17 //使用dexguard进行代码混淆后的反汇编代码可能如下,b.a()方法
18 void methoda()
19 {
20     a.a(b.a("xxxxxxxxx"));
21     a.aaa(a.aa(b.a("yyyyyyyyy")),b.a("zzzzzzzzz"));
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 public static void main(string args[])
 2 {
 3     try
 4     {
 5         //---------获取文件
 6         //获取需要加密的源apk程序
 7         file payloadsrcfile = new file("xxxx/abc.apk");
 8         system.out.println("srcapk size:"+payloadsrcfile.length());
 9         //获取脱壳(解密)程序的dex文件,需要提前把脱壳程序的dex文件解压出来
10         file unshelldexfile = new file("yyyy/classes.dex");
11 
12         //---------加密源apk文件
13         /*
14         以二进制形式读取apk,并加密,存到payloadarray数组中
15         readfilebytes是以二进制形式读取文件
16         encrpt()是自定义的对二进制流加密的函数
17         */
18         byte[] payloadarray = encrpt(readfilebytes(payloadsrcfile));
19         //以二进制形式读取脱壳dex
20         byte[] unshelldexarray = readfilebytes(unshelldexfile);
21 
22         //---------合并
23         //***1.计算出新dex文件的总长度
24         int payloadlen = payloadarray.length();    //加密apk的长度
25         int unshelldexlen = unshelldexarray.length();    //脱壳dex的长度
26         int totallen = payloadlen+unshelldexlen=4    //新的dex文件长度,最后+4是为了用于存储payloadlen值的
27         //***2.定义新dex文件
28         //先定义新dex文件的长度
29         byte[] newdex = new byte[totallen];
30         //***3.开始合并
31         //将脱壳dex文件的内容写入新dex
32         system.arraycopy(unshelldexarray,0,newdex,0,unshelldexlen);
33         //再将加密后的源apk内容连接在后面
34         /*
35         arraycopy(arr1,x,arr2,y,m)表示将数组arr1从索引为x开始的元素,复制m个元素到数组arr2中去,从arr2的y索引开始粘贴
36         */
37         system.arraycopy(payloadarray,0,newdex,unshelldexlen,payloadlen);
38         //最后将将加密后的apk长度记录在新dex文件末尾
39         /*
40         inttobyte()将int类型数据转换成byte
41         total是int类型的,newdex是byte类型
42         total是脱壳dex长度+加密apk长度+4,所以,最后是从newdex的第total-4索引开始写入payload的长度
43         一个byte是1个字节,即8位;一个int是4个字节,即32位;所以最后的4表示写入inttobyte(payloadlen)的4个元素
44         */
45         system.arraycopy(inttobyte(payloadlen),0,newdex,totallen-4,4);
46 
47         //---------修改新dex文件的头部信息
48         //修改file_size字段
49         fixfilesizeheader(newdex);
50         //修改signature字段
51         fixsha1header(newdex);
52         //修改checksum字段
53         fixchecksumheader(newdex);
54         //---------生成新dex文件
55         //定义要生成文件的路径及名称并创建空文件
56         string str = "zzzz/classes.dex";
57         file file = new file(str);
58         if (!file.exists())
59         {
60             file.createnewfile();
61         }
62         //将合并好的数据写入文件
63         fileoutputstream localfileoutputstream = new fileoutputstream(str);
64         localfileoutputstream.write(newdex);
65         localfileoutputstream.flush();
66         localfileoutputstream.close();
67     }catch (exception e) {
68         e.printstacktrace();
69     }
70 }
71     
72 //加密函数encrpt()的定义
73 private static byte[] encrpt(byte data[]) 
74 {
75     //加密算法实现,这里就不写了
76         return data;
77 }

 

 

脱壳流程如下图:

安卓应用加固之四代加壳保护技术详解

 

 

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

 

 

 

#0x02 第二代壳

 

 

 

 

#0x03 第三代壳

 

 

 

 

 

#0x04 第四代壳