详解odex中dex部分的变化原理

今年春节写代码度过的,也挺充实的。

这是假期的最后一篇啦。 :)



在odex格式的解析文章中提到过,它的dex文件部分和原dex相比发生了变更,参见:

用python一步步解剖dex文件(五)--- odex格式

这里的变更共有3部分,分别是class_def段code段和header中的checksum

而且变更后的dex部分和原文件大小一致,变更的内容也不是很多。

到底发生了什么呢,我们还是从源码中找下,dexopt过程中到底对原dex文件做了什么。


class_def段

dexopt过程包含内容比较多,我们直接跳到核心优化的代码点吧。。。

http://androidxref.com/4.4_r1/xref/dalvik/vm/analysis/DexPrepare.cpp

dvmContinueOptimization

上面的函数中,巴拉巴拉写了一堆的校验和重写(形成odex必要的一些数据),我们都忽略了,只关注dex部分的流程,如下:

重写dex文件

其中rewriteDex又调用了下述函数:

校验和优化所有的类

这里的verifyAndOptimizeClasses就是我们要找的函数了。

它遍历了class_def的列表,获取到了每个类的信息,并且对每个类都执行优化。

校验和优化所有类

对于单个类的校验和优化的过程如下:

校验和优化单个类

打住打住,这个函数对DexClassDef的accessFlags做了变更,分别在校验和优化后加入两个标志。

特殊类型
两个标志位的异或结果

这个结果不就是0x00030000吗? class_def段的对比如下,这个03终于找到了。。。

class_def_diff



code段

继续阅读源码,看类是怎么优化的。

http://androidxref.com/4.4_r1/xref/dalvik/vm/analysis/Optimize.cpp

优化单个类

上面这个函数遍历了它的直接方法和虚方法列表,对每个函数做优化。

优化单个函数

上面这个函数就是最最核心的方法了,它对指令字节码部分做转换,转换后的指令码列表如下:

快速标记指令

过程可以划分为针对instance_field,static_field, invoke_init, return_void, invoke_virtual, inline的几个部分。

指令转换

转换instance_field

实例属性

从上图可以看出,除了指令码更改为quick类型外,还会将原指令中的field_idx转换为byte_offset,这个byte_offset是偏移量可以直接定位。

这里还涉及到volatile类型,如果它是volatile类型的变量那么会把volatile_opc写入field_idx部分而不是byte_offset

转换指令码

上图是如何转换指令,以为指令码只占用一个字节,所以通过异或来保留第二个字节的原有信息。 至于opcode >= 256基本是没用的,因为从上面的quick列表看,都在256以内。

转换过程还涉及到如何查找field,如下图所示。

属性域转换

这个过程需要先查找类。

这个部分很难,说它难不是它在虚拟机中的加载难,而是没有任何依赖的情况下,如何加载并定位它,可是这是不可能的。。。 因为很多类,是rom自己编译好的,只能从rom对应的framework.odex, core.odex等系统类信息中去查询。

所以当我看到下面的referrer->classLoader,忽然就觉得,『有你真好!』

寻找类

接着是一个递归查询的方法,它沿着类和它的父类一直往上查询,直到查询到field为止。

寻找属性

转换static_field

同instance_field的转换类似。

注意一下,非volatile类型的static属性,是不做任何处理了。

看下面的逻辑,static_field被索引到后,只是判断了它的volatile类型信息。

write_static

转换invoke_init

这是比较独特的一个转换,就是把构造函数的<init>单独拎出来了,转换前后的数字很容易识别。

invoke init

转换return_void

这个转换只涉及指令码转换

return

这个转换过程是有条件的,从下面代码可以看出,如果函数所属的类是final类型或者它的属性中至少有一个是final类型的。

转换return的条件

转换invoke_virtual

过程和instance_field类似,除了转换指令码,还会通过method_id找到对应的method方法,将它的method_index替换掉method_id。

virtual

转换inline

同invoke_virtual的转换类似,不同的是,把method_id转换为对应的内联方法的索引。

inline

从上面的转换过程来看,主要是把属性获取和设置,方法调用相关的指令字节码优化掉,这样虚拟机在加载odex后,在执行指令字节码的时候能更加快速的获取到相关信息。

对比结果分析

下面是code段对比的一个差异图,我们按照上面的转换过程一一对比下。

code段对比

先看下这段的反汇编信息:

(关于反汇编,参看:  用python一步步解剖dex文件(四)--- 反汇编框架

数据对应的反汇编信息

这里共有5个指令字节码单元,我们一个个分析。

第一段: 70 10 11 00 00 00

它是执行了<init>方法,所以对应上面的『转换invoke_init』部分,按照逻辑分支又属于invoke_direct的分支,所以转换结果是 0xf0 | 0x100 = 0x1f0, 字节表示就是右侧的 f0 01。 其它不变化。

第二段:5b 01 0b 00

它是执行iput-object指令,对应上面的『转换instance_field』部分。

这个部分更改两处,一个是指令码变更为0xf7,另一个就是转换field_idx。

field_idx是字节的0b 00部分,也就是0x000b = 11,在field_id_list中的索引号为11。

经过虚拟机的类属性查询,它转换后的数值为08.

第三段:5b 02 0c 00

同第二段,指令码转换为0xf7,而field_idx经过转换后数值不变。

第四段: 0e

这个是return-void类型,因为原函数的所属类,没有final信息,所以不转换。

第五段: 00

nop类型,啥也不动。

这样,code段的变化就都解释清楚了。



checksum

最后的最后,odex对dex部分做checksum校验并重写。

这里有做checksum计算的示例:

https://github.com/callmejacob/dexfactory/blob/master/dexinfo.py




请勿转载,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容