首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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

Dalvik 字节码格式的官方说明:(相关网站不一定能打开,我直接放网盘了)

链接: https://pan.baidu.com/s/1bq27bbx 密码: pirc

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

用python一步步解剖dex文件(二)https://www.jianshu.com/p/f8e1c80b913a

每段指令字节码的第一个字节就是指令码,指令码的范围在[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> , meth@BBBB, proto@HHHH

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

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

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

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

总格式: '%s> , %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格式解析框架结合起来。

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

context的insns类

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

字节码反汇编

反汇编测试

测试代码

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

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

反汇编测试

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

带反汇编信息的类信息

待续

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180216G0P1SI00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券