复制代码

10. Android加固原理(基础篇)

什么是加壳

移动平台攻防技术的发展基本是沿着PC端发展轨迹在进行,从windows平台的加壳脱壳反调试到Andriod的平台apk加固,反调试代码混淆等。

加壳是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作。大多数病毒就是基于此原理。

PC EXE文件加壳的过程如下:

apk常见加固方式

代码层级加密

(1)代码混淆

代码混淆是一种常用的加密方式。本质是把工程中原来的有具体含义的类名、变量名、方法名,修改成让人看不懂的名字。常见的代码混淆工具proguard(有兴趣的可以自己看一下该工具:http://t.cn/ELjgHdi)。该加密方式只是对工程提供了最小的保护,并不是说不能逆向破解;只是说难度增加,需要耐心。

(2)Dex文件加密

dex是Android工程中的代码资源文件,通过dex可以反编译出java代码。dex的加壳是常见的加密方式。通过对dex文件加密拼接加壳,可以有效的对工程代码进行保护。apk工程在安装成功后,app启动时会有dex解密的过程,然后重新加载解密后的dex文件。

Jni层级加密

这种加密方式也就是本文分享的加密方式。基本原理是在jni层, 使用DexClassLoader动态加载技术完成对加密classex.dex的动态加载,dex文件可以附属在assert或raw目录。

 

Android Dex文件加固原理

Android应用打包加载流程

具体过程与描述请移步我上一篇文章:Android加载流程(打包与启动)

Dex文件格式

什么是DEX文件

Dex文件是可以直接在Dalvik虚拟机中加载运行的文件,包含应用程序的全部操作指令以及运行时数据

Dalvik是一种针对嵌入式设备而特殊设计的java虚拟机,所以dex文件与标准的class文件在结构设计上有着本质的区别

Java代码通过Java编译器(javac)编译成java字节码,即.class文件,通过Android的dx工具转换成Dalvik字节码,即.dex文件。目的是其中各个类能够共享数据,在一定程度上降低了冗余,同时也是文件结构更加经凑,实验表明,dex文件是传统jar文件大小的50%左右

Dex文件结构

Dex文件整体结构如下:

Dex文件整体结构说明(这里使用crackme0502的classes.dex):

数据名称解释
dex_header dex文件头部记录整个dex文件的相关属性
string_ids 字符串数据索引,记录了每个字符串在数据区的偏移量
type_ids 类似数据索引,记录了每个类型的字符串索引
proto_ids 原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表
field_ids 字段数据索引,记录了所属类,类型以及方法名
method_ids 类方法索引,记录方法所属类名,方法声明以及方法名等信息
class_def 类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量
data 数据区,保存了各个类的真是数据
link_data 静态链接数据区

下面是DEX文件头的内容:  

  

  结合上面两张图进行分析:

字段名称说明
magic

表示这是一个有效的DEX文件,固定值为"64 65 78 0a 30 33 35 00",转换为字符串格式为"dex.035"。

checksum

checksum是校验码字段,占4bytes,主要用来检查从该字段(不包含checksum字段,也就是从12bytes开始算起)

开始到文件末尾,这段数据是否完整,也就是完整性校验。它使用alder32算法校验。
signature
signature是SHA-1签名字段,占20bytes,作用跟checksum一样,也是做完整性校验。之所以有两个完整性校验字段,
是由于先使用checksum字段校验可以先快速检查出错的dex文件,然后才使用第二个计算量更大的校验码进行计算检查。
fileSize 占4bytes,记录了包括DexHeader在内的整个Dex文件的大小
headerSize 记录了DexHeader结构本身占用的字节数
endianTag 指定了DEX运行环境的CPU字节序
... ...

  我们只需要关注 checksumsignaturefileSize 这三个字段,因为将一个文件(加密之后的源Apk)写入到Dex中,那么肯定需要修改文件校验码(checksum),因为他是检查文件是否有错误。那么signature也是一样,也是唯一识别文件的算法。还有就是需要修改dex文件的大小。

  不过这里还需要一个操作,就是标注一下我们加密的Apk的大小,因为我们在脱壳的时候,需要知道Apk的大小,才能正确的得到Apk。那么这个值放到哪呢?这个值直接放到文件的末尾就可以了。

  所以总结一下我们需要做:修改Dex的三个文件头,将源Apk的大小追加到壳dex的末尾就可以

Application类的使用

Application类比程序中的其他类启动的都要早,因此在分析Android程序中,需要先查看该程序是否具有Application类,如果有,就要看看它的oncreate()方法是否做了一些影响逆向分析的初始化工作

Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象,用来存储系统的一些信息。Android系统自动会为每个程序运行时创建一个Application类的对象且只创建一个,所以Application可以说是单例(singleton)模式的一个类。

通常我们是不需要指定一个Application的,系统会自动帮我们创建,如果需要创建自己的Application,创建一个类继承Application并在AndroidManifest.xml文件中的application标签中进行注册(只需要给application标签增加name属性,并添加自己的 Application的名字即可)。

<application
        android:name="CustomApplication">
</application>

启动Application时,系统会创建一个PID,即进程ID,所有的Activity都会在此进程上运行。那么我们在Application创建的时候初始化全局变量,同一个应用的所有Activity都可以取到这些全局变量的值,换句话说,我们在某一个Activity中改变了这些全局变量的值,那么在同一个应用的其他Activity中值就会改变。

Application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以可以通过Application来进行一些,如:数据传递、数据共享和数据缓存等操作。

Android加固原理

Dex文件整体加固原理如下:

该过程涉及到三个对象,分别为

  1.源程序

    源程序也就是我们的要加固的对象,这里面主要修改的是原apk文件中的classes.dex文件和AndroidManifest.xml文件。

  2.壳程序

    壳程序主要用于解密经过加密了的dex文件,并加载解密后的原dex文件,并正常启动原程序。

  3. 加密程序

    加密程序主要是对原dex文件进行加密,加密算法可以是简单的异或操作、反转、rc4、des、rsa等加密算法。

    该加固过程可以分为如下4个阶段:

      (1) 加密阶段

      (2)合成新的dex文件

      (3)修改原apk文件并重打包签名

      (4)运行壳程序加载原dex文件

加密阶段

  加密阶段主要是讲把原apk文件中提取出来的classes.dex文件通过加密程序进行加密。加密的时候如果使用des对称加密算法,则需要注意处理好密钥的问题。同样的,如果采用非对称加密,也同样存在公钥保存的问题。

合成新的dex文件

 这一阶段主要是讲上一步生成的加密的dex文件和我们的壳dex文件合并,将加密的dex文件追加在壳dex文件后面,并在文件末尾追加加密dex文件的大小数值

  在壳程序里面,有个重要的类:ProxyApplication类,该类继承Application类,也是应用程序最先运行的类。所以,我们就是在这个类里面,在原程序运行之前,进行一些解密dex文件和加载原dex文件的操作。
 

修改原apk文件并重打包签名

  在这一阶段,我们首先将apk解压,会看到如下图的6个文件和目录。其中,我们需要修改的只有2个文件,分别是classes.dex和AndroidManifest.xml文件,其他文件和文件加都不需要改动。

  首先,我们把解压后apk目录下原来的classes.dex文件替换成我们在上一步合成的新的classes.dex文件。然后,由于我们程序运行的时候,首先加载的其实是壳程序里的ProxyApplication类。所以,我们需要修改AndroidManifest.xml文件,指定application为ProxyApplication,这样才能正常找到识别ProxyApplication类并运行壳程序。

运行壳程序加载原dex文件

  Dalvik虚拟机会加载我们经过修改的新的classes.dex文件,并最先运行ProxyApplication类。在这个类里面,有2个关键的方法:attachBaseContextonCreate方法。ProxyApplication显示运行attachBaseContext再运行onCreate方法。

  在attachBaseContext方法里,主要做两个工作:

    1. 读取classes.dex文件末尾记录加密dex文件大小的数值,则加密dex文件在新classes.dex文件中的位置为:len(新classes.dex文件) – len(加密dex文件大小)。然后将加密的dex文件读取出来,解密并保存到资源目录下

    2. 然后使用自定义的DexClassLoader加载解密后的原dex文件

  在onCreate方法中,主要做两个工作:

    1. 通过反射修改ActivityThread类,并将Application指向原dex文件中的Application

    2. 创建原Application对象,并调用原Application的onCreate方法启动原程序

加壳代码实现

  加壳程序项目  

  

  核心代码  

  

常见加固平台

  梆梆加固,爱加密,360加固,腾讯加固

  市面上常见的加固工具加固之后,他会把你的dex,so 加密存在apk中,然后运行过程会先运行壳的代码,壳的代码再把原来的这个dex、so 解出来加载,不同的厂商有自己的方案,略有差距,但目前多数都是这个思路.

App加固的利弊

  正面:

    1.保护自己核心代码算法,提高破解/盗版/二次打包的难度

    2.缓解代码注入/动态调试/内存注入攻击

  负面:

    1.影响兼容性

    2.影响程序运行效率.

    3.部分流氓、病毒也会使用加壳技术来保护自己

    4.部分应用市场会拒绝加壳后的应用上架

App安全未来展望

App安全总结

结尾

本文参考与 https://www.jianshu.com/p/4ff48b761ff6 ,在细节上为了方便理解,略有改动和补充。

手机挖矿

从源码到apk

Dex文件格式详解

浅谈安卓app加固那点事

Android APK加壳技术方案【1】

Android APK加壳技术方案【2】

ANDROID原理解密之APK生成过程

Android签名机制之—签名验证过程详解

 

posted @ 2019-11-10 21:43  bmjoker  阅读(5465)  评论(0编辑  收藏  举报