ODEX

ODEX简介

ODEX,全名Optimized DEX,即优化过的DEX

有至少3种方法去创建一个“准备好的”DEX文件,即ODEX:

  1. 虚拟机JIT输出会跑到一个特殊的dalvik-cache目录。这只在一些特殊的桌面和工程机的设备上使用(这些机器的build中,dalvik-cache目录的权限不是严格的)。在生产机器上这是不被允许的。

  2. 系统的安装器在程序首次安装时候执行,它有写dalvik-cache的权限。

  3. 构建(build)系统预先执行。相关的 jar / apk 文件还在,但classes.dex被剥离出来了。ODEX和原来的zip包保存在一起,不在dalvik-cache,而是系统镜像的一部分。

dalvik-cache目录更准确地说是$ANDROID_DATA/data/dalvik-cache。里面的文件的名字来源于源DEX的完整路径。在设备上该目录被system所拥有,而system拥有0771权限,保存在那里的ODEX被系统和应用的组所拥有,权限为0644。数字权限保护的应用会使用640权限来防止其他应用去检测它们。底线是你可以读取自己的与其他大部分应用的DEX文件,但你不能创建、修改,或删除它们。

前两种方法的执行分为以下三个步骤:

首先,dalvik-cache文件被创建。这必须在一个有恰当权限的进程进行,所以在“系统安装器”的场景,是在运行为root的installd进程执行的。

接着,classes.dex从zip包中解压出来。文件头部留出一小块空间给ODEX header。

最后,文件被内存映射以便访问,并被为当前系统使用进行调整。这包括了字节交换(byte-swapping),结构重新排列(structure realigning),但并没有对DEX文件做有意义的改变。还做了一些其他的基本结构检查,比如确保文件偏移量和数据索引落在有效范围内。

构建系统不在桌面上运行工具,而宁愿去启动模拟器,强制所有相关DEX文件的即时优化,然后从dalvik-cache把结果提取出来。这样做的原因,在解释完优化后会变得更显而易见。

一旦代码被字节替换和对齐,我们就可以继续了。我们添加了一些预计算的数据,在文件头填写ODEX header,然后开始执行。然而,如果我们对验证和优化有兴趣,就需要在初始准备后再插入一个步骤。

dexopt的魔法

在Android 2.3版本以前,系统源码中提供了生成odex的工具dexopt-wrapper,位于Android 2.2系统源码的 build/tools/dexpreopt/dexopt-wrapper/ 目录下,查看DexOptWrapper.cpp文件会发现实际调用的是 /system/bin/dexopt 程序。在5.0及以上版本的设备上,你可能已经再也找不到dexopt了,取而代之的是dex2oat。

我们想要验证和优化DEX文件里的所有类。最简单和安全的方法就是把所有类加载到虚拟机,然后跑一遍。任何加载失败的就是验证/优化失败的。不幸的是,这可能导致一些资源的分配难以释放(比如native共享库的加载),所以我们不想执行在应用运行的虚拟机里。

解决方案就是起一个叫做dexopt的程序(事实上就是虚拟机的后门)。它会执行一个简短的虚拟机初始化,从引导的类路径加载0个或多个DEX文件,然后开始做一切从目标DEX可以做的验证和优化。结束后,进程退出,释放所有资源。

因为多个虚拟机可能同时需求同一个DEX文件,文件锁被用来确保dexopt仅被执行一次。

优化

虚拟机解释器通常会在一段代码被首次使用的时候执行某些优化。常量池引用被指向内部数据结构的指针所替代,总是成功的操作或是那些总会以某种方式工作的,会被更简单的形式所替代。这些的一部分需要仅在运行时可用的信息,另一部分在某些特定假设下可以被静态推论出。
Dalvik优化器做了这些:

  • 对于虚方法调用,把方法索引替换为vtable索引。
  • 对于实例变量(field)的get/put,把变量索引替换为字节偏移。另外,把 boolean / byte / char / short基本变量(variants)合并到单个的32位形式(解释器里更少的代码意味着CPU I-cache里更少的空间)。
  • 替换一些高频次调用,例如把 String.length() 替换成内联的。这可以跳过一些常见的方法调用消耗,直接从解释器切换到native实现。
  • 删除空方法。最简单的例子就是Object.什么都没干,却必须在任何对象被分配的时候执行。指令会被替换为一个新版本的空指令(no-op)形式,除非调试器被attach上去了。
  • 附加预计算数据。例如,虚拟机想要一个类名的哈希表以便查找。不同于在加载DEX文件时候去计算这个,我们可以先计算,以节省堆(heap)空间和所有加载该DEX文件的虚拟机的计算时间。

生成ODEX文件

使用dexopt-wrapper可以将dex转换为odex。dexopt-wrapper在安卓2.3以前的源码中可以找到。将dex-wrapper编译后放到手机中。

adb push dexopt-wrapper /data/local
adb shell chmod 777 /data/local/dexopt-wrapper

从apk文件中提取一个dex文件,将其改名为classex.dex,zip将其压缩后改名为HelloDex.zip

adb push HelloDex.zip /data/local
adb shell
cd /data/local
./dexopt-wrapper HelloDex.zip HelloDex.odex

将ODEX文件转换为DEX文件

经过优化的ODEX文件中包含与设备相关的依赖库列表Dependences结构信息,不同的Android设备的底层bootClassPath环境变量中存放的系统加载库列表也不尽相同。因此,将ODEX文件转换成DEX文件的过程是设备相关的。
为了将ODEX文件还原成DEX文件,需要先将ODEX文件反编译成smali文件,再将smali文件编译成DEX文件。我们将这个过程称为deodex。反编译与编译smali文件使用的工具都是smali。在使用baksmali命令反编译ODEX文件时,需要加入参数-d,以指定与ODEX相关的设备的framework目录。
因为依赖库都来源于Android设备的/system/framework目录,所以,
第一步操作是将设备上的framework目录pull到本地。

adb pull /system/framework ./

(注意,执行以上命令需要拥有设备的root权限)
接下来,执行如下命令完成反编译

baksmali -a 19 -x crack.odex -d ./framework -o ./outdex

其中,-a参数时Android设备的版本号,19表示当前设备是4.4版本的。-x参数用于指定要操作的ODEX文件,-d参数用于指定framework目录,-o参数指定输出smali文件的目录。完成该命令后,会生成一系列smali文件,接下来,只要执行smali命令将smali文件生成DEX文件即可。

smali ./outdex -o outdex.dex

(当然,网上也有odex2dex的自动脚本)

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

推荐阅读更多精彩内容