您好,欢迎来到源码搜藏网!分享精神,快乐你我!
[加入VIP] 设为首页 | 收藏本站 | 网站地图 | Sitemap | TAG标签
  • 首 页
  • 在线工具
  • jquery手册
  • 当前位置:首页 > 安卓源码 > 技术博客 >

    Android开发中加固原理研究

    时间:2018-01-09 23:02 来源:互联网 作者:源码搜藏 浏览:收藏 挑错 推荐 打印

    一、DEX文件格式分析 1、文件布局 文档可以参考官方文档: http://source.android.com/devices/tech/dalvik/dex-format.html image dex 文件可以分为3个模块,头文件(header)、索引区(xxxx_ids)、数据区(data)。头文件概况的描述了整个 dex 文件的分布,包括

    一、DEX文件格式分析

    1、文件布局

    文档可以参考官方文档:http://source.android.com/devices/tech/dalvik/dex-format.html

     
    Android开发中加固原理研究
    image

    dex 文件可以分为3个模块,头文件(header)、索引区(xxxx_ids)、数据区(data)。头文件概况的描述了整个 dex 文件的分布,包括每一个索引区的大小跟偏移。索引区表示每个数据的标识,主要是指向数据区的偏移。

     
    Android开发中加固原理研究
    image

    010Editor 中除了数据区(data)没有显示出来,其他区段都有显示,另外 link_data 在模板中被定为 map_list

    2、文件头header

     
    Android开发中加固原理研究
    image
    • magic: 这个是固定值,用于识别 dex 文件。转化为字符串为 "dex 035", 中间是一个换行,后面035是版本号。

    • checksum: ****文件校验码,使用 alder32 算法校验文件除去 maigc、checksum 外余下的所有文件区域,用于检 查文件错误。

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

    • file_size: dex ****文件大小

    • header_size: header 区域的大小,目前是固定为 0x70

    • endian_tag: 大小端标签,dex 文件格式为小端,固定值为 0x12345678 常量

    • map_off: map_item 的偏移地址,该 item 属于 data 区里的内容,值要大于等于 data_off 的大小,处于 dex 文件的末端。

    • 其他元素都是成对出现的。_off 表示元素的偏移量,_size 表示元素的个数

    3、索引区——string_ids

    string_ids 区段描述了 dex 文件中所有的字符串。格式很简单只有一个偏移量,偏移量指向了 string_data 区段的一个字符串:

     
    Android开发中加固原理研究
    image

    其中 data 保存的就是字符串的值。string_ids 是比较关键的,后续的区段很多都是直接指向 string_ids 的 index。在写工具进行比较的时候也需要提取到 string_ids。

    4、索引区—— type_ids

    type_ids 区索引了 dex 文件里的所有数据类型,包括 class 类型,数组类型(array types)和基本类型(primitive types)。区段里的元素格式为 type_ids_item

     
    Android开发中加固原理研究
    image

    type_ids_item 里面 descriptor_idx 的值的意思,是 string_ids 里的 index 序号,是用来描述此 type 的字符串。

    5、索引区—— proto_ids

    proto 的意思是 method prototype 代表 java 语言里的一个 method 的原型 。proto_ids 里的元素为 proto_id_item

     
    Android开发中加固原理研究
    image
    • shorty_idx: 跟 type_ids 一样,它的值是一个 string_ids 的 index 号 ,最终是一个简短的字符串描述,用来说明该 method 原型。

    • return_type_idx: 它的值是一个 type_ids 的 index 号 ,表示该 method 原型的返回值类型。

    • parameters_off: 指向 method 原型的参数列表 type_list,若 method 没有参数,值为0。参数列表的格式是 type_list,下面会有描述。

    6、索引区—— field_ids

    filed_ids 区里面有 dex 文件引用的所有的 field。区段的元素格式是 field_id_item,结构如下:

     
    Android开发中加固原理研究
    image
    • class_idx: 表示 field 所属的 class 类型,class_idx 的值是 type_ids 的一个 index,并且必须指向一个 class 类型。

    • type_idx: 表示本 field 的类型,它的值也是 type_ids 的一个 index 。

    • name_idx: 表示本 field 的名称,它的值是 string_ids 的一个 index 。

    7、索引区—— method_ids

    method_ids 是索引区的最后一个条目,描述了 dex 文件里的所有的 method。method_ids 的元素格式是 method_id_item,结构跟 fields_ids 很相似:

     
    Android开发中加固原理研究
    image
    • class_idx: 表示 method 所属的 class 类型,class_idx 的值是 type_ids 的一个 index,并且必须指向一个 class 类型。ushort类型也是为什么我们说一个 dex 只能有 65535 个方法的原因,多了必须分包。

    • proto_idx: 表示 method 的类型,它的值也是 type_ids 的一个 index。

    • name_idx: 表示 method 的名称,它的值是 string_ids 的一个 index。

    8、索引区—— class_defs

    class_def 区段主要是对 class 的定义,它的结构很复杂,看的我有点晕

     
    Android开发中加固原理研究
    image
    • class_idx: 类名序号,值是type_ids的一个index

    • class_def: 类定义结构体

    • static_values_off: 静态变量值偏移

    • class_data_off: 类定义偏移

    • class_data: 类定义结构体

    • direct_methods_size: 直接函数个数

    • virtual_methods_size: 虚函数个数

    • virtual_methods: 虚函数结构体

    • code_off: 函数代码偏移

    9、索引区—— map_list

    map_list 中大部分 item 跟 header 中的相应描述相同,都是介绍了各个区的偏移和大小,但是 map_list 中描述的更加全面,包括了 HEADER_ITEM 、TYPE_LIST、STRING_DATA_ITEM、DEBUG_INFO_ITEM 等信息。

     
    Android开发中加固原理研究
    image

    map_list 里先用一个 uint 描述后面有 size 个 map_item,后续就是对应的 size 个 map_item 描述。 map_item 结构有 4 个元素: type 表示该 map_item 的类型,Dalvik Executable Format 里 Type Code 的定义; size 表示再细分此 item,该类型的个数;offset 是第一个元素的针对文件初始位置的偏移量; unuse 是用对齐字节的,无用。

    二、DEX文件混淆加密

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

    四种混淆加密的实现方式都是通过修改 class_def 结构体中字段实现的。

    1、静态变量隐藏

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

     
    Android开发中加固原理研究
    image

    2、函数重复定义

    class_def -> class_data -> virtual_methods -> code_ff 表示的是某个类中某个函数的代码偏移地址。这里需要提到一个概念:Java 中所有函数实现都是虚函数,这一点和 C++ 是不一样的,所有这里修改的都是 virtual_methods中 code_off

     
    Android开发中加固原理研究
    image

    实现方式:读取第一个函数的代码偏移地址,将接下来的函数偏移地址都修改为第一的值。

     
    Android开发中加固原理研究
    image

    3、函数隐藏

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

     
    Android开发中加固原理研究
    image

    4、类定义隐藏

    class_def -> class_data_off 保存了具体类定义的偏移地址,也就是 class_def -> class_data 的地址,如果该值为0则所有实现将被隐藏。隐藏后会把类定义的所有东西都隐藏包括成员变量,成员函数,静态变量,静态函数。

     
    Android开发中加固原理研究
    image

    三、APK加壳(加固)

    1、原理解析

     
    Android开发中加固原理研究
    image

    在加固的过程中需要三个对象:

    • 需要加密的****Apk(****源****Apk)

    • 壳程序****Apk(****负责解密****Apk****工作****)

    • 加密工具****(****将源****Apk****进行加密和壳****Dex****合并成新的****Dex)

    2、主要步骤:

    拿 到需要加密的Apk和自己的壳程序Apk,然后用加密算法对源Apk进行加密;再与壳Apk的Dex进行合并得到新的Dex文件;然后替换原壳程序中的 dex文件即可,得到新的Apk。那么这个新的Apk我们也叫作脱壳程序Apk,他已经不是一个完整意义上的Apk程序了,他的主要工作是:负责解密源 Apk,然后加载Apk,让其正常运行起来。

    3、 源Apk和壳Dex合并生成新的Dex

     
    Android开发中加固原理研究
    image

    只要关注上面红色标记的三个部分:

    1) checksum

    文件校验码 ,使用alder32 算法校验文件除去 maigc ,checksum 外余下的所有文件区域 ,用于检查文件错误 。

    2) signature

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

    3) file_size

    Dex 文件的大小 。

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

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

    总结一下:修改****Dex****的三个文件头,将源****Apk****的大小追加到壳****dex****的末尾就可以了。

    修改之后得到新的Dex文件样式如下:

     
    Android开发中加固原理研究
    image

    4、加壳代码

     
    Android开发中加固原理研究
    image
     
    Android开发中加固原理研究
    image
     
    Android开发中加固原理研究
    image
     
    Android开发中加固原理研究
    image

    四、APK脱壳

     
    Android开发中加固原理研究
    image

    步骤:

    1、从脱壳Apk中获取到Dex文件

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

    3、解密源程序Apk

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

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

    五、动态加载

    预备知识:

    android中的类加载器:http://blog.csdn.net/jiangwei0910410003/article/details/41384667

    android中的动态加载机制:http://blog.csdn.net/jiangwei0910410003/article/details/17679823

    第一个思路: 替换LoadedApk中的mClassLoader

    加载Activity的时候,有一个很重要的类:LoadedApk.Java,这个类是负责加载一个Apk程序的

     
    Android开发中加固原理研究
    image

    内部有一个mClassLoader变量,是负责加载一个Apk程序的,只要获取到这个类加载器就可以了。他不是static的,所以还得获取一个LoadedApk对象。再去看一下另外一个类:ActivityThread.java的源码

     
    Android开发中加固原理研究
    image

    ActivityThread类中有一个自己的static对象,然后还有一个ArrayMap存放Apk包名和LoadedApk映射关系的数据结构,那么分析清楚了,下面就来通过反射来获取mClassLoader对象吧。

     
    Android开发中加固原理研究
    image

    第二思路:合并PathClassLoader和DexClassLoader中的dexElements数组

     
    Android开发中加固原理研究
    image

    PathClassLoader和DexClassLoader类的父加载器是BootClassLoader,他们的父类是BaseDexClassLoader。里面有一个DexPathList对象,在来看一下DexPathList.java源码:

     
    Android开发中加固原理研究
    image

    首先看一下这个类的描述,还有一个Elements数组,这个变量是专门存放加载的dex文件的路径的,系统默认的类加载器是PathClassLoader,一个程序加载之后会释放一个dex出来,这时候会将dex路径放到里面,

    当然DexClassLoader也是一样的,可以将DexClassLoader中的dexElements和PathClassLoader中的dexElements进行合并,然后在设置给PathClassLoader中。

     
    Android开发中加固原理研究
    image
     
    Android开发中加固原理研究

    Android开发中加固原理研究转载http://www.codesocang.com/appboke/38316.html
    标签:网站源码