开卷有益python热爱者码农的世界

用python一步步解剖dex文件(四)--- 反汇编框架

2018-02-15  本文已影响484人  虎七

请勿转载,谢谢!!! 

另祝大家新年快乐,万事大吉!


Dalvik 字节码格式的官方说明:

字节码格式: https://source.android.google.cn/devices/tech/dalvik/dalvik-bytecode

说明格式: https://source.android.google.cn/devices/tech/dalvik/instruction-formats

之前有介绍过指令字节码如何反编译的,参考文章最后部分:

用python一步步解剖dex文件(二)

每段指令字节码的第一个字节就是指令码,指令码的范围在[0x00 - 0xff],就是256个以内。

每个指令码都对应一个格式解析说明,该说明详细指出了该段字节指令码占用了几个字节,使用几个寄存器,以及如何读取的。

以这个指令格式说明为基础,我设计了反汇编框架,代码地址:

https://github.com/callmejacob/dexfactory/tree/master/disassemble


指令字节数组的最小单位解析

指令字节数组的最小单位,只有一个指令码,后面跟着对应的指令数据。

以'4rcc'指令格式为例子,它的格式说明如下:

4rcc格式说明

它占用了4 * 2 = 8个字节,这8个字节可以按照最左侧的格式进行分解,得到AA, BB, CCCC, HHHH,继而算出 NNNN = CCCC + AA - 1。

反编译出来的代码如下:

op> {vCCCC ... vNNNN}, meth@BBBB, proto@HHHH

其中op就是字节码; CCCC, NNNN, BBBB,HHHH是解析或者计算好的数值。

而meth是一种kind类型,表示一种常量池的索引,而且每个指令码对应的kind类型可能不一样(后面有详细说明)。

最后的proto是固定的,表示proto类型的常量池。

我们把这个反编译出来的用格式化表示: 

总格式:  '%s> {v%d ... v%d}, %s, %s' % (op_map[op], CCCC, NNNN, '%s', '%s')

最后两个为什么用%s呢? 因为也把kind类型的和proto类型的做格式化处理,最后合并到上面的总格式中。

这两个格式都用下述格式表示:

kind格式:  '%s@%.4x'

它的第一个参数是kind类型,第二个就是kind类型的数值,比如

meth@0003

代表method常量池的第3个子项。

我们用代码实现如下:

解析过程

上面的desc就是我们说的总格式,而kind_x, proto_x都是用来形成kind格式的数值。

如果我们拼接好kind格式之后,使用下面的方法汇总到总格式:

总格式拼接

打印方法:

打印方法

上面的例子中,'4rcc'格式比较有代表性,它包含了[op, 变量,kind, proto]四个重要的信息。

下面我们介绍通用的解码过程(decode)。

decode会根据指令码和对应的说明格式进行一一解析,这需要建立一些指令码类型的映射集合,详细如下。

指令码集合(片段):

指令码集合

常量池类型定义(kind):

常量池类型定义

指令码对应的kind类型映射(片段):

指令码和kind的映射

指令码到解释格式的映射集合(片段):

指令码到解释格式的映射

利用op_map可以获取到指令码描述;

利用format_map可以获取到指令码说明格式,并根据该格式进行变量解析;

利用kind_map可以获取到拼接kind格式的类型。

最后,根据上述信息,汇总到总格式字符串中。

这样,一个最小单位的指令字节码就解析完成了。

我们将上述方法都封装到类InsnsItem中,它能够解析一个最基本的指令字节码,并且能够打印出来相关的反汇编代码。

代码片段如下:

类InsnsItem

指令字节码全段解析

指令字节数组可以分解为若干个最小单位的指令字节码,形成一个item_list。

指令字节数组全解码

其中的InsnsItem中的kind格式信息,还是最原始的,比如meth@0003。

为了获取它实际信息,我们定义一个kind到对应section信息的一个映射和获取方法:

kind到section的映射信息

在上述映射的基础上,我们可以把item信息转换成真实的反汇编信息。

打印过程:

指令字节码反汇编打印

其中的context,就是包含section信息的上下文,通过它我们把kind和proto两个格式字符串格式化,获取到kind_desc和proto_desc(它们包含了真实信息),最终再填充到总格式化字符串中。

最后我们把这两个过程封装到类Insns中,它以指令字节数组为参数,可以反编译出对应的指令代码。


反汇编和Dex解析框架

我们把这个反汇编框架和之前的dex格式解析框架结合起来。

全解析框架参考:

用python一步步解剖dex文件(三)

先在Context类中,定义一个变量来代表反编译类的class,并提供设置方法。

context的insns类

然后在code_item段中,对于解析出来的每段insns字节码数组进行反汇编:

字节码反汇编

反汇编测试

测试代码

其中"#反汇编"这段不是必要的,因为后面反汇编类挂接到context中后,也能够直接反汇编解析,这里是为了测试。 

这段的打印结果如下:  (格式是字节码数组和反汇编解释)

反汇编测试

使用反汇编的类信息打印如下:

带反汇编信息的类信息


待续

上一篇下一篇

猜你喜欢

热点阅读