Android APP加固与脱壳基础----加固与脱壳简介

先从DEX文件格式开始分析,因为dex是安卓应用程序编译后的结果,直接与Android虚拟机进行交互的文件。Android APP加固与脱壳基础----加固与脱壳简介_第1张图片
有关DEX文件的介绍可以参照我之前写的这篇文章。

看这个图片很复杂,其实对于初学者来说,只要了解到这一点就行了:

Android应用的Java代码,所有的数据格式、数据、算法都是经过转化,变成了以上的格式存储,储存的是具体内容的偏移地址。

比如索引区的string_ids,描述了所有程序中的字符串,格式也很简单,只有一个偏移量地址,用文件偏移地址来记录、描述字符串的内容。文件偏移地址和编程经常会用到的内存地址区别,我们了解内存地址,因为是在程序运行的时候,会用到,但是此时的android应用是保存在dex文件中的,所以继续我们成为文件偏移地址,并用来记录描述的。

type_ids,描述了所有的数据类型,包括class类型,数组类型和基本类型。

言而总之,程序被分区分块的进行转换和保存了。

dex文件和加固有什么关系?

如果dex文件未加密,未混淆等安全加固,我们可以通过apktool或者jeb拿到汇编源代码或源代码,之前也介绍过。

dex文件的混淆加密

混淆和加密主要是为了隐藏dex文件中关键的代码,力度从轻到重:静态变量的隐藏、函数的重复定义、函数的隐藏、以及整个类的隐藏。混淆后的dex文件依旧可以通过dex2jar jeb等工具反编译成Java源码,但是里面的关键代码已经看不见了。

四种混淆加密的实现方式都是通过修改class_def结构体字段实现的。
在这里插入图片描述

1、静态变量隐藏

static_values_off保存了每个类中静态变量值的偏移量,指向data区的一个列表,格式为encode_array_item,如果没有此项内容,此值为0,所以要实现静态变量赋值隐藏只需要将static_cales_off值修改为0即可。

2、函数重复定义

class_def -> class_data -> virtual_methods -> code_ff表示的是某个类中某个函数的代码偏移地址。

这里提一点,Java中所有函数实现都是虚函数,这一点和C++是不一样的,所以所有这里修改的都是virtual_methods中的code_off。

大概的原理和实现方式就是,读取第一个函数的代码偏移地址,将接下来的函数偏移地址都修改为第一的值。

根据文件偏移量确定函数的,这样就实现了函数重复定义。

Android APP加固与脱壳基础----加固与脱壳简介_第2张图片

3、函数隐藏

class_def -> class_data -> virtual_methods_size和class_def -> class_data -> direct_methods_size记录了类定义中函数的个数,如果没有定义函数则该值为0.所以只要将该值改为0,函数定义就会被隐藏。

老规矩,代码先不管。
Android APP加固与脱壳基础----加固与脱壳简介_第3张图片

4、类定义隐藏

手段比较重的隐藏是直接隐藏了类的所有东西,包括成员变量,成员函数,静态变量,静态函数。

在class_def -> class_data_off保存了具体类定义的偏移地址,也就是class_def -> class_data的地址,把该值为0即可实现隐藏。

APK加固

Android APP加固与脱壳基础----加固与脱壳简介_第4张图片
需要:

  • 需要加密的APK
  • 壳程序APK
  • 加密工具(将Dex合并成新的Dex)

源APK经过加密,然后用壳APK(没错,壳也是APK)的dex和源APK的dex文件进行融合,得到一个全新的dex,然后再打包成新的APK,这个新的APK已经不是传统意义的APK了,他的主要工作是:负责解密源Apk,然后加载Apk,让它正常运行起来。

源APK和壳Dex合并成新的Dex

我们主要看head头,因为head头可以用来校验整个包的完整性和安全性。
Android APP加固与脱壳基础----加固与脱壳简介_第5张图片

  • checksum

    文件校验码,使用alder32算法校验文件除去magic, checksum外余下的所有文件区域,用于检查文件错误。破解后如果提示"文件已损坏",就是这个地方数据出了问题。

  • signature

    使用SHA-1算法hash除去magic, checksum和signature外余下的所有文件区域,用于唯一识别本文件。

  • File_size

    Dex文件的大小。

    因为将一个文件(加密之后的源Apk)写入到Dex中,那么肯定需要修改文件校验码(checksum)、signature,因为他是检查文件和签名是否有错误,还有就是需要修改dex文件的大小。

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

    所以修改之后得到新的Dex文件样式如下:
    Android APP加固与脱壳基础----加固与脱壳简介_第6张图片

(1)源程序项目(需要加密的Apk)

(2)脱壳项目(解密源Apk和加载Apk,其实就是壳APK)

(3)对源Apk进行加密和脱壳项目的Dex的合并

加密代码:

Android APP加固与脱壳基础----加固与脱壳简介_第7张图片
Android APP加固与脱壳基础----加固与脱壳简介_第8张图片
Android APP加固与脱壳基础----加固与脱壳简介_第9张图片
Android APP加固与脱壳基础----加固与脱壳简介_第10张图片

APK脱壳

Android APP加固与脱壳基础----加固与脱壳简介_第11张图片
1、从脱壳Apk获取到Dex文件

2、从脱壳Dex中得到源Apk文件

3、解密源程序Apk

4、加载解密之后的源程序Apk

5、找到源程序的Application程序,让其运行。

两种思路:

一、替换LoadedApk中的mClassLoader

加载一个Activity肯定不像加载一般的类那样,因为activity作为系统的组件有自己的声明周期,所以不能像其他类一样自定义一个DexClassLoader类加载器来加载插件中的Activity。它有专门的启动流程这里不做过多描述,只需要知道加载Activity的时候,有一个很重要的类:LoadedApk.Java
Android APP加固与脱壳基础----加固与脱壳简介_第12张图片
这个类是负责加载一个Apk程序的,其内部有一个mClassLoader变量,是负责加载一个Apk程序的,只要获取到这个类加载器就可以获取到APK内容了,所以还得获取一个LoadedApk对象。再去看一下另外一个类ActivityThread.java的源码
Android APP加固与脱壳基础----加固与脱壳简介_第13张图片
ActivityThread类中有一个自己的static对象,然后还有一个ArrayMap存放Apk包名和LoadedApk映射关系的数据结构,那么分析清楚了,下面通过反射来获取mClassLoader对象就可以拿到想要的Apk包了。
Android APP加固与脱壳基础----加固与脱壳简介_第14张图片

合并PathClassLoader和DexClassLoader中的dexElements数组

PathClassLoader和DexClassLoader类的父加载器是BootClassLoader,他们的父类是BaseDexClassLoader。里面有一个DexPathList对象,在来看一下DexPathList.java源码:
Android APP加固与脱壳基础----加固与脱壳简介_第15张图片
首先看一下这个类的描述,还有一个Elements数组,这个变量是专门存放加载的dex文件的路径的,系统默认的类加载器是PathClassLoader,一个程序加载之后会释放一个dex出来,这时候会将dex路径放到里面,

当然DexClassLoader也是一样的,可以将DexClassLoader中的dexElements和PathClassLoader中的dexElements进行合并,然后在设置给PathClassLoader中。
Android APP加固与脱壳基础----加固与脱壳简介_第16张图片
Android APP加固与脱壳基础----加固与脱壳简介_第17张图片

refer:

https://www.jianshu.com/p/6a504c7928da

你可能感兴趣的:(安卓逆向,移动安全,APP加固与脱壳)