小泽玛利亚电影 一文读懂 DEX 文献神志贯通

发布日期:2024-12-06 12:15    点击次数:103

小泽玛利亚电影 一文读懂 DEX 文献神志贯通

曾有东谈主问我小泽玛利亚电影,为什么要去干贯通 dex 文献这种长途的事?

我念念说的是写个贯通剧本不是为了效法着 apktools 造轮子,而是在贯通历程中寻找逆向的谈路,秩序会变,器用会变,但一切都树立在 dex 上的安卓不会变

一、什么是 Dex 文献

dex 文献是 Android 平台上可实践文献的一种文献类型。它的文献神志不错底下这张图综合:

图片

二、文献头贯通1、文献头简介

dex 文献头一般固定为 0x70 个字节大小,包含符号、版块号、校验码、sha-1 签名以偏激他一些秩序、类的数量和偏移地址等信息。如下图所示:

图片

2、dex 文献头各字段贯通

dex 文献头包含以下各个字段:

magic: 包含了 dex 文献象征符以及版块,从 0x00 起先,长度为 8 个字节

checksum: dex 文献校验码,偏移量为: 0x08,长度为 4 个字节。

signature: dex sha-1 签名,偏移量为 0x0c, 长度为 20 个字节

file_szie: dex 文献大小,偏移量为 0x20,长度为 4 个字节

header_size: dex 文献头大小,偏移量为 0x24,长度为 4 个字节,一般为 0x70

endian_tag: dex 文献判断字节序是否交换,偏移量为 0x28,长度为 4 个字节,一般情况下为 0x78563412

link_size: dex 文献一语气段大小,为 0 则默示为静态一语气,偏移量为 0x2c,长度为 4 个字节

link_off: dex 文献一语气段偏移位置,偏移量为 0x30,长度为 4 个字节

map_off: dex 文献中 map 数据段偏移位置,偏移位置为 0x34,长度为 4 个字节

string_ids_size: dex 文献包含的字符串数量,偏移量为 0x38,长度为 4 个字节

string_ids_off: dex 文献字符串起先偏移位置,偏移量为 0x3c,长度为 4 个字节

type_ids_size: dex 文献类数量,偏移量为 0x40,长度为 4 个字节

type_ids_off: dex 文献类偏移位置,偏移量为 0x44,长度为 4 个字节

photo_ids_size: dex 文献中秩序原型数量,偏移量为 0x48,长度为 4 个字节

photo_ids_off: dex 文献中秩序原型偏移位置,偏移量为 0x4c,长度为 4 个字节

field_ids_size: dex 文献中字段数量,偏移量为 0x50,长度为 4 个字节

field_ids_off: dex 文献中字段偏移位置,偏移量为 0x54,长度为 4 个字节

method_ids_size: dex 文献中秩序数量,偏移量为 0x58,长度为 4 个字节

method_ids_off: dex 文献中秩序偏移位置,偏移量为 0x5c,长度为 4 个字节

class_defs_size: dex 文献中类界说数量,偏移量为 0x60,长度为 4 个字节

class_defs_off: dex 文献中类界说偏移位置,偏移量为 0x64,长度为 4 个字节

data_size: dex 数据段大小,偏移量为 0x68,长度为 4 个字节

data_off: dex 数据段偏移位置,偏移量为 0x6c,长度为 4 个字节

3、dex 文献头代码贯通示例 (python)

dex 使用 open 函数以二进制开放文献,然后使用 seek 函数转移文献指针,举例 magic 即是f.seek(0x00),然后读取相应信息的字节数即可,举例读取版块号f.seek(0x04) f.read(4),然后作念相应打印操作就行,dex 文献头较简便,不波及编码等,是以贯通起来嗅觉脑子都不必带。。。。。具体代码不错看底下或者 github,底下附上代码运行图:

图片

4、dex 文献头贯通达成代码(python 达成)

ps:只截取重要代码,圆善代码请参考文末 github 一语气或网盘一语气

图片

三、checksum (校验和)贯通1、checksum 先容

checksum(校验和)是 DEX 位于文献头部的一个信息,用来判断 DEX 文献是否损坏或者被删改,它位于头部的0x08偏移地址处,占用 4 个字节,禁受小端序存储。

在 DEX 文献中,禁受Adler-32校验算法筹算出校验和,将 DEX 文献从0x0C处起先读取到文献甩手,将读取到的字节数组使用Adler-32 校验算法筹算出甩手即是校验和即 checksum 字段!!!

2、Adler-32 算法

Adler-32算法如下秩序达成:

a、界说两个变量varA、varB,其中varA运行化为1,varB运行化为0。

b、 读取字节数组的一个字节(假定该字节变量名为byte),筹算varA = (varA byte) mod 65521,然后不错筹算出varB = (varA varB) mod 65521。

c. 疏导秩序,直到字节数组一都读取完毕,得到最终varA、varB两个变量的甩手。

d. 凭证第三步得到的varA、varB两个变量,可得到最终校验和checksum =(varB << 16) varA。

底下是官方 WIKI 给的例子:

图片

3、python 达成 Adler-32 算法

先给出 Dex 文献头部信息以及代码跑出的甩手

图片

图片

python 代码达成如下(python 3.6 版块):

图片

四、字符串贯通1、DEX 文献中的字符串

a、DEX 文献梗概上不错鄙俚的分为 3 个部分:文献头、索引区以及数据区。而文献头一般来说占了扫数这个词 DEX 文献 0x70 个字节(还不了解 DEX 文献头的不错看一下我前边两篇著作),在文献头中,对于字符串的相干信息一共有 8 个字节,离别位于 0x38(4 Bytes) 和 0x3c(4 Bytes) 处,前者证实了该 DEX 文献包含了若干个字符串,后者则是字符串索引区的肇端地址,然而需要能干的是,DEX 存储是以小端序存储的(当年少许的说即是从后往前读),如下所示:

图片

b、前边咱们通过文献头知谈了字符串数量和字符串索引区肇端地址等信息,接下来咱们就来具体看一下字符串索引区。字符串索引区存储的是字符串果真存储在数据区的偏移地址,以 4 个字节为一组,默示一个字符串在数据区的偏移地址,是以索引区一个占字符串数量 X 4个字节那么多,一样的,索引区也禁受的是小端序存储,是以咱们在读取地址时,需要与小端序的样式来读取果真的地址,如下所示:

图片

c、从上头咱们依然知谈了如何找到字符串在数据区的偏移地址,接下来咱们需要作念的即是贯通这些数据区的字节。通过偏移地址咱们不错在数据区找到代表字符串的这些字节,在 DEX 文献中,字符串是通过MUTF-8编码而成的(至于 mutf-8 是什么编码,我会将一些相干博客一语气贴在文末),在MUTF-8编码中,第一个字节代表了这个字符串所需要用到的字节数量(不包括终末一个代表已矣的字节),终末一个字节为0x00,默示这个字符串到此甩手,跟 c 言语有点访佛,中间部分才是一个字符串的具体现实,如下所示:(PS:mutf-8第一个字节还经过uleb128编码,是以简便的进行进制换算得到的字节数许多东谈主奇怪对不上,由于比拟复杂,就不外多诠释了,念念进一步了解更深的不错去看一下安卓源码中对 DEX 文献贯通出字符串这一部分)

图片

2、贯通代码:

PS:我电脑运行环境-- python3.6

代码重要截图如下:

图片

运行截图:

图片

图片

五、类的类型贯通1、DEX 文献中的类的类型

a、Dex 文献中对于类的类型需要知谈字符串是怎样贯通的,要是不知谈的,不错看一下前边部分。好了,切入正题,对于类的类型,即是一个对象的所属的类(巧合这样交融吧。。。),举例在 java 中一个字符串,它的类型即是java/lang/String。在 Dex 文献头中,跟类的类型琢磨的一共有八个字节,离别是位于0x40处占四个字节默示类的类型的数量和位于0x44处占四个字节默示类的类型索引值的肇端偏移地址,如下所示:

图片

b、对于类的类型数量,没什么好说的,只需要能干它是以小端序存储的,读取的时期能干即可。对于类的类型偏移地址,找到偏移地址后,它是以四个字节为一组,对应了在贯通出来的字符串数组中的索引值,举例下图中的第一组,它的数据是BE 04 00 00,咱们读取出来即是0x04BE(一样禁受的小端序存储),对应的类的类型即是字符串数组 [0x04be]。

图片

2、贯通剧本

PS:我电脑上剧本运行环境 python3.6

运行成果:

图片

图片

代码重要截图如下:

图片

六、秩序原型贯通1、DEX 文献中的秩序原型

a、对于 dex 文献中秩序原型的贯通,需要知谈怎样贯通出字符串和类的类型,不解白的不错看前边贯通。DEX 文献中的秩序原型界说了一个秩序的复返值类型和参数类型,举例一个秩序复返值为void,参数类型为int,那么在 dex 文献中该秩序原型默示为V(I)(smali中V默示void,I默示int)。在 dex 文献头部中,对于秩序原型有两处,第一处位于0x48处,用 4 个字节界说了秩序原型的数量,在0x4C处用 4 个字节界说了秩序原型的偏移地址,如下所示:

图片

b、在上头咱们知谈了秩序原型的肇端偏移地址,接下来咱们凭证这个偏移地址找到秩序原型,一样的,跟贯通类的类型比拟访佛,一个秩序原型所占字节数为 12 个字节,第一个字节到第四个字节默示了界说秩序原型的字符串,这四个字节按小端序存储,读取出来为在字符串列表的索引,举例一个秩序原型复返值为void,参数为boolean,那么界说该秩序原型的字符串即为VZ;第 5 个字节到第八个字节默示该秩序原型的复返值类型,读取出来的值为前边贯通出来的类的类型列表的索引;第 8 个字节到第十二给字节默示该秩序原型的参数,读取出来为一组地址,通过该地址不错找到该秩序原型的参数,跳转到该地址去,最初看前 4 个字节,前四个字节按照小端序存储,读取出来的值为该秩序原型参数的个数,接着凭证参数个数,读取具体的参数类型,每个参数类型占 2 个字节,这两个字节读取出来的值为前边贯通出来的类的类型列表的索引,如下所示:

图片

图片

2、贯通代码

运行环境:我电脑环境为 python3.6

运行截图:

图片

图片

亚洲黄色

贯通代码重要截图:

图片

七、字段贯通1、dex 文献中的字段

a、在 dex 文献头中,对于字段(ps:字段不错简便交融成界说的变量或者常量)相干的信息有 8 个字节,在0x50~0x53这四个字节,按小端序存储这 dex 文献中的字段数量,在0x54~0x57这四个字节,存储这读取字段的肇端偏移地址,如下所示:

图片

b、凭证上头的字段肇端偏移地址,咱们不错找到字段,默示一个字段需要用八个字节,其中,前两个字节为咱们在前边贯通出来类的类型列表的索引,通过该索引找到的类的类型默示该字段在该类中被界说的(ps:我是这样交融的,如有不合,还请转换);第三个字节和第四个字节,亦然类的类型列表的索引,默示该字段的类型,举例咱们在 java 某个类中界说了一个变量int a,那么咱们此处贯通出来的字段类型即是int;终末四个字节,则是咱们前边贯通出来字符串列表的索引,通过该索引找到的字符串默示字段的,举例咱们界说了一个变量String test;,那么咱们在这里贯通出来的即是test,如下图所示:

图片

2、贯通代码

贯通代码运行截图:

图片

图片

贯通代码重要截图:

图片

八、秩序界说贯通1、Dex 文献中的秩序界说

a、在 dex 文献头中,对于秩序界说的信息一样是八个字节,离别位于0x58处和0x5c处。在0x58处的四个字节,指明了 dex 文献中秩序界说的数量,在0x5c处的四个字节,标明了 dex 文献中的秩序界说的肇端地址(ps:都是以小端序存储的),如下图所示:

图片

b、在上头的一步以及找到了秩序界说的肇端地址,跟字段访佛的,一个秩序界说也需要八个字节。其中,在前两个字节,以小端序存储着贯通出来的类的类型列表的索引,默示该秩序属于哪个类;第三个字节和第四个字节,以小端序存储这贯通出来的秩序原型列表的索引,通过该索引值找到的秩序原型声明了该秩序的复返值类型和参数类型;终末四个字节则以小端序存储着前边贯通出来的字符串列表的索引,声明了该秩序的秩序名。如下图所示:

图片

2、贯通代码

贯通代码运行截图:

图片

图片

贯通代码重要截图:

图片

九、类贯通

PS:Dex 文献贯通到咫尺,终于到了最蹙迫亦然结构最复杂的部分了,这里分析的 dex 样蓝本自一个复杂 apk 的 dex 文献,然而代码运行时使用的样本是一个在网上找的很简便的 dex 样本,原因很简便,分析使用的 dex 波及的 smali 请示太多了,巧合有 200 多个,挨个贯通起来责任量太大了,有时期我会写一个通用的 python 贯通模块,完成了我会上传到 github 仓库,有酷好的完成后不错看一下,用简便的 dex 只波及到 5 个请示,代码写起来就没那么长途了!!!(tips:Dex 类数据这里贯通起来有种俄罗斯套娃的嗅觉,多看几篇就很容易交融了。)

1、uleb128 编码

PS:蓝本对于 uleb128 编码网上一大堆,没必要写这个,然而网上的你抄我的我抄你的,能找的的相干贵府基本都一样。。。。或者干脆贴个官方代码,官方代码的位运算写的很神秘,然而径直去看的化,归正我是没看懂到底是怎样解码出来的。

uleb128 编码,是一种可变长度的编码,长度大小为1-5字节,uleb128 通过字节的最高位来决定是否用到下一个字节,要是最高位为 1,则用到下一个字节,直到某个字节最高位为 0 或依然读取了 5 个字节为止,接下来通过一个实例来交融 uleb128 编码。

假定有以下经过 uleb128 编码的数据(都为 16 进制)--81 80 04,最初来看第一个字节81,他的二进制为10000001,他的最高位为1,则证实还要用到下一个字节,它存放的数据则为0000001;再来看第二个字节80,它的二进制为10000000,它的最高位为1,则证实还需要用到第三个字节,存放的数据为0000000;再来看第三个字节04,它的二进制为00000100,最高位为0,证实一共使用了三个字节,它存放的数据为0000100;通过上头的数据咱们依然得回了存放的数据,接下来即是把这些 bit 组合起来得回解码后的数据,dex 文献里面的数据都是禁受的小端序的样式,uleb128 也不例外,在这三个字节,也不例外,第三个字节04存放的数据0000100手脚解码后的数据的高 7 位,第二个字节80存放的数据0000000手脚解码后的数据的中 7 位,第一个字节81存放的数据0000001手脚解码后的数据的低 7 位;那么解码后的数据二进制则为0000100 0000000 0000001,赞助为 16 进制则为0x10001。其他使用 5 个字节、4 个字节照此类推即可,底下是 python 读取 uleb128 的代码(ps:该代码是最终类数据贯通代码的一共函数,无法单独运行,仅供参考,禁受的是官方提供的位运算算法):

代码言语:javascript复制2、类贯通第一层结构:class_def_item

a、在 dex 文献头0x60-0x63这四个字节,指明了class的数量,在0x64-0x67这四个字节,指明的class_def_item的偏移地址。如下所示:

图片

b、通过上头的偏移地址,咱们不错找到 class_def_item 的肇端地址,class_def_item 包含了一个类的类名、接口、父类、所属 java 文献名等信息。一个 class_def_item 结构大小为 32 字节,离别包含 8 个信息,每个信息大小为 4 字节(小端序存储):

第 1-4 字节 -- class_idx(该值为前边贯通出来的类的类型列表的索引,也即是这个类的类名);

第 5-8 字节 -- access_flags(类的访谒符号,也即是这个类是 public 照旧 private 等,这个通过官方的文档查表得知,具体算法在终末头证实);

第 9-12 字节 -- superclass_idx(该值也为前边贯通出来的类的类型列表的索引,指明了父类的类名)

第 13-16 字节 -- interfaces_off(该值指明了接口信息的偏移地址,所指向的地址结构为 typelist,前边的著作有说过,这里不再多说,要是该类莫得接口,该值则为 0)

第 17-20 字节 -- source_file_idx(该值为 dex 字符串列表的的索引,指明了该类地点的 java 文献名)

第 21-24 字节 -- annotations_off(该值为谛视信息的偏移地址,由于谛视信息不是我要贯通的重心,要检察谛视信息具体结构的不错参考官方文档,官方文档地址粘贴在文末)

第 25-28 字节 -- class_data_off(该值是这个类数据第二层结构的偏移地址,在该结构中指明了该类的字段和秩序)

第 29-32 字节 -- static_value_off(该值亦然一个偏移地址,指向了一个结构,不是重心,感酷好的参考官方文档,要是没相干信息,则该值为 0)

具体分析历程,如下图所示:

图片

3、类贯通第二层结构:class_data_item

a、通过上头 class_def_item 的分析,咱们知谈了类的基本信息,举例类名、父类等啊,接下来即是要找到类里面的字段和秩序这些信息,而这些信息,在 class_def_item 里面的 class_data_off 字段给咱们指明class_data_item就包含这些信息并给出了偏移地址,即咫尺需要贯通class_data_iem结构得回字段和秩序信息。(ps:以下的数据结构不作念很是证实都为 uleb128 编码神志)

b、class_data_item结构包含以下信息:

第一个uleb128编码--static_field_size,指明了该类的静态字段的数量

第二个uleb128编码--instance_field_size,指明了该类的实例字段的数量(实例字段不知谈是啥的冷漠百度)

第三个uleb128编码--direct_method_size,指明了该类的径直秩序的个数

第四个uleb128编码--virtual_method_size,指明了该类的虚秩序的个数(虚秩序交融不了了的冷漠百度一下)

encoded_field--static_fields,该结构指明了具体的静态字段信息,该结构的存在前提是static_field_size >0,该结构包含两个 uleb128 编码,第一个 uleb128 编码为前边贯通出来的字段列表的索引,第二个 uleb128 编码指明了该字段的访谒符号

encoded_field--instance_fields,跟上头访佛,不再多说,值得能干的是,该结构存在的前提是instance_field_size > 0

encoded_method--direct_methods,该结构指明了径直秩序具体信息,该结构存在的前提一样是direct_method_size > 0,该结构包含 3 个 uleb128 编码,第一个 uleb128 为前边著作贯通出来的秩序原型列表的索引值,第二个 uleb128 编码为该秩序的访谒符号,第三个 uleb128 为 code_off,也即是该秩序具体代码的字节码的偏移地址,对应的结构为 code_item,code_item 结构里面包含了该秩序里面的代码,这里是字节码,也即是 smali(ps: 要是该秩序为抽象秩序,举例 native 秩序,这时 code_off 对应的值为 0,即该秩序不存在具体代码)

encoded_method--virtual_methods,该结构指明了该类的虚秩序的具体信息,存在前提为virtual_method_size > 0,具体结构和上头一样,不再多说

具体分析历程,如下图所示:

图片

4、类贯通的第三层结构:code_item

a、在上头的 class_data_item 结构中的encoded_method结构的第三个 uleb128 编码中,指出了一个类中的秩序具体代码的偏移地址,也即是 dv 凭空机在实践该秩序的具体请示的偏移地址,该值指向的地址结构为code_item,里面包含了寄存器数量、具体请示等信息,底下来分析一下该结构。

b、code_item结构包含以下信息:

第 1-2 字节 -- registers_size,该值指明了该秩序使用的寄存器数量,对应的 smali 语法中的.register的值

第 3-4 字节 -- ins_size,该值指明了传入参数的个数

第 5-6 字节 -- outs_size,该值指明了该秩序里面调用其他函数用到的寄存器个数

第 7-8 字节 -- tries_size,该值指明了该秩序用到的try-catch语句的个数

第 9-12 字节 -- debug_info_off,该值指明了调试信息结构的偏移地址,要是不存在调试信息,则该值为 0

第 13-16 字节 -- insns_size,该值指明了请示列表的大小,不错这样交融:规定了请示所用的字节数大小--2 x insns_size

ushort[insns_size] -- insns,这个是请示列表,包含了该秩序所用到的请示的字节,每个请示占用的字节数不错参考官方文档,这个没什么算法,即是一个查表的历程,举例invoke-direct请示占用 6 个字节,return-void请示占用 2 个字节

2 个字节 -- padding,该值存在的前提是tries-size > 0,作用用来对都代码

try_item--tries,该值存在的前提是tries-size > 0,作用是指明特殊具体位置和处置样式,该结构不是贯通重心,重心是贯通请示,感酷好的检察官方文档

encoded_catch_handler_list--handlers, 该结构存在前提为tries-size > 0,一样不是贯通重心,感酷好的检察官方文档

具体分析历程,如下图所示:

图片

图片

5、access_flags算法

access_flags 访谒符号具体值不错去检察官方文档,下图只截了一部分。要是 access_flags 的算法为access_flags = flag1 | flag2 | ...,要是访谒符号惟有一共,径直查表即可,要是是两个,按照算法对比值即可,底下举个例子来交融该算法。

图片

举例我有一个类的访谒符号为public static,经过查表得知public对应的值为0x01,static对应的值为0x8,那么public static对应的访谒符号为0x01 | 0x08 = 0x9,要是读取出来的 access_flags 为 0x09,那么对应的访谒符号则为public static,其余的照此算法筹算即可!!!

6、贯通代码

PS:代码运行环境保举 3.6 偏激以上,需要模块binascii,运行样本为Hello.dex,样本附在文末网盘一语气中!!!

运行截图

图片

通过剧本贯通出来的和通过 apktools 反编译出来的 smali 文献对比图

(ps:左侧为 apktools 反编译出来的,右侧为剧本贯通出来的,不错发现基本差未几)

图片

图片

贯通代码重要截图:

图片

十、一些追忆

有东谈主可能会问没事作念这样多复杂的责任干啥,不是有 apktools 不错径直反编译就完了嘛,但我念念说的是,作念这样作念贯通责任不是念念替换 apktools,而是念念在这个贯通历程中弄光显 dex 文献神志,惟有先交融了这些文献的神志,才智写一下加固决策和分析一些可能市面上的一些小众的壳。举例 java 层请示抽取壳,即是在终末的秩序请示上作念保护。逆向秩序会变,器用会变,但这些最压根的东西,不会变,交融这些,是别称搞安卓安全的必备常识吧!!!

十一、参考贵府和样本代码地址参考贵府:

1、Android 逆向之旅—贯通编译之后的 Dex 文献神志:

http://www.520monkey.com/archives/579

2、一篇著作带你搞懂 DEX 文献的结构:

https://blog.csdn.net/sinat_18268881/article/details/55832757

3、官方文档:

https://source.android.google.cn/devices/tech/dalvik/dex-format#embedded-in-class_def_item,-encoded_field,-encoded_method,-and-innerclass

样本及代码下载:

github 一语气:

https://github.com/windy-purple/parserDex小泽玛利亚电影

本站仅提供存储职业,扫数现实均由用户发布,如发现存害或侵权现实,请点击举报。