【一】、【二】中从代码的角度分析了dalvik字节码解释执行的过程,这篇文章以一个例子来实际分析一下。

我们以这篇文章中提到的crackme为例,下载链接参见那篇文章。我们只分析dalvik字节码,因此忽略so。

0x01:

使用Jeb打开crackme.apk,找到MainActivity的onCreate方法,其smali内容是:

.method protected onCreate(Bundle)V.registers 5.param p1, "savedInstanceState".prologue
00000000  invoke-super            AppCompatActivity->onCreate(Bundle)V, p0, p1
00000006  const                   v2, 0x7F040019
0000000C  invoke-virtual          MainActivity->setContentView(I)V, p0, v2
00000012  const                   v2, 0x7F0C0050
00000018  invoke-virtual          MainActivity->findViewById(I)View, p0, v2
0000001E  move-result-object      v1
00000020  check-cast              v1, EditText.local v1, txt:Landroid/widget/EditText;
00000024  const                   v2, 0x7F0C0051
0000002A  invoke-virtual          MainActivity->findViewById(I)View, p0, v2
00000030  move-result-object      v0
00000032  check-cast              v0, Button.local v0, btn:Landroid/widget/Button;
00000036  sget-boolean            v2, MainActivity->$assertionsDisabled:Z
0000003A  if-nez                  v2, :4E
:3E
0000003E  if-nez                  v0, :4E
:42
00000042  new-instance            v2, AssertionError
00000046  invoke-direct           AssertionError-><init>()V, v2
0000004C  throw                   v2
:4E
0000004E  new-instance            v2, MainActivity$1
00000052  invoke-direct           MainActivity$1-><init>(MainActivity, EditText)V, v2, p0, v1
00000058  invoke-virtual          Button->setOnClickListener(View$OnClickListener)V, v0, v2
0000005E  return-void
.end method

smali 对于Android,可以理解为汇编对于C。smali中定义了一套完整的dalvik操作码(类似于汇编的指令集),构成了dalvik虚拟机最核心的部分。

字节码是二进制的,这些二进制通过一定的方式可以被解释成为smali指令。我们来看看这个过程。

0x02:

使用010editor打开crackme.apk中的classes.dex,应用dex模板,结果如下:

dex文件格式参见这篇文章

我们分析的目标是MainActivity的onCreate方法,直接找到它:

因为onCreate是重写的父类方法,所以在virtual_methods中,我们看到这个方法需要5个寄存器,2个参数,3个内部方法调用参数,48条指令。字节码在insns中。

0x03:

下面进入对字节码的分析,在【二】中分析方法执行时, dvmInterpretPortable的最后一个语句:

FINISH(0); /* fetch and execute first instruction */

即为定位到insns的起始处,并取2个字节的内容放置到inst变量中,之后取出inst的低字节数值作为handlerTable数组的索引号,然后跳转到对应符号去执行。

代码上的跟踪比较繁琐,好在google有相关的文档:【Dalvik bytecode】、【Dalvik Executable instruction formats】,我们根据文档来分析。

在这个例子中,第一个“两字节”是:6F 20, 其低字节是6F,代表着handlerTable数组的索引号,查询文档:

表示操作符是invoke-super

查看OP_INVOKE_SUPER.cpp,里面有对此指令的执行过程:

HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)GOTO_invoke(invokeSuper, false);
OP_END

其中:

# define HANDLE_OPCODE(_op) op_##_op:
OP_INVOKE_SUPER                 = 0x6f,
#define GOTO_invoke(_target, _methodCallRange)                              \do {                                                                    \methodCallRange = _methodCallRange;                                 \goto _target;                                                       \} while(false)

翻译一下就是:

op_0x6f:do{methodCallRange = false;goto invokeSuper;}while(false)

invokeSuper在gotoTargets.cpp中定义:

GOTO_TARGET(invokeSuper, bool methodCallRange){Method* baseMethod;u2 thisReg;EXPORT_PC();vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */ref = FETCH(1);             /* method ref */vdst = FETCH(2);            /* 4 regs -or- first reg */if (methodCallRange) {ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",vsrc1, ref, vdst, vdst+vsrc1-1);thisReg = vdst;} else {ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);thisReg = vdst & 0x0f;}... //此处省略后后面的内容

其中:

#define GOTO_TARGET(_target, ...) _target:#define GOTO_TARGET_END

翻译一下就是:

invokeSuper:{Method* baseMethod;u2 thisReg;EXPORT_PC();vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */ref = FETCH(1);             /* method ref */vdst = FETCH(2);            /* 4 regs -or- first reg */if (methodCallRange) {ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",vsrc1, ref, vdst, vdst+vsrc1-1);thisReg = vdst;} else {ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);thisReg = vdst & 0x0f;}... //此处省略后后面的内容

这样就找到了invokeSuper真正执行的地方了,可以看到,依然是解析字节码和获取新字节码解析的过程。代码跟踪同样比较复杂,我们直接看文档:

从图中可以看出6f的格式是35c(后面会用到),语法格式为:

invoke-*kind*{vC, vD, vE, vF, vG}, meth@BBBB

其中的A、B、C的解释在后面一列有说明,光看这个还不能看懂,看一下35c:

这个文档我一开始也看得不是太懂,简单的还能对应起来,复杂的(现在这个例子)就搞不清楚了,文档只能理解个大概,最后我选择看代码。这里直接说我看代码看明白的:

首先 6F 20 中的 6F表示操作码,20又分两个4位来解释,2表示寄存器的数量,0代表啥还没有看明白:(,随后的两个字节 47 2A 表示的是method id,47 2A 表示数值是0x2A47,即10823,如图:

所以我们大概明白了:

invoke-super            AppCompatActivity->onCreate(Bundle)V

随后的两个字节 43 00 也是需要被解析的,是用来确定寄存器标号的,至于怎么映射为 p0 p1,我也没有看懂(代码在gotoTargets.cpp的GOTO_TARGET(invokeSuper, bool methodCallRange)中,欢迎有兴趣的同学继续研究并加微信交流)。

0x04:

至此,我们分析完第一条指令的字节码解释过程了。在源码中,你可以看到,它不光是解释成smali这么简单,它真正的去寻找父类的onCreate方法,构造函数堆栈并进行调用。
pc指针随着执行过程不断往后移动,当方法返回后,继续去下一个“两字节”进行解释执行。这个例子中的下一个“两字节"是14 02,其中14为操作码,如图:

可以看到是const vAA, #+BBBBBBBB,和我们在Jeb中看到的const v2, 0x7F040019能够对上。后续的过程和前面完全一致,只是处理的是不同的操作码而已。

0x05:

至此,此系列文章结束。其中有一些细节我也没有弄得很清楚(回头弄明白再来更新),但是大致流程已经清晰了。欢迎有兴趣的同学在此基础上继续研究,可以加我微信进行交流。微信见首页二维码。

作者:difcareer
链接:http://www.jianshu.com/p/aba1f966d7f2
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

彻底弄懂dalvik字节码【三】相关推荐

  1. 彻底弄懂dalvik字节码【一】

    之前曾经简单跟踪过代码,知道dalvik的字节码是可以支持解释执行的,所谓的解释执行,其实就是c/c++编写的用于解释并执行dalvik字节码的程序,说白了就是dalvik字节码到cpu字节码的转换. ...

  2. 彻底弄懂dalvik字节码【二】

    [一]中讲到了最重要的dvmInterpret,继续跟: void dvmInterpret(Thread* self, const Method* method, JValue* pResult) ...

  3. 这一次,彻底弄懂 Java 字节码文件!

    作者 | 东升的思考 责编 | Elle 不啰嗦,直接从最最简单的一段Java源代码开启Java整体字节码分析之旅. Java 源码文件 package com.dskj.jvm.bytecode; ...

  4. 应用程序文件Android安全分析挑战:运行时篡改Dalvik字节码

    发一下牢骚和主题无关: 本文章由Jack_Jia编写,转载请注明出处. 文章接链:http://blog.csdn.net/jiazhijun/article/details/8833710 作者:J ...

  5. 深入理解Dalvik字节码指令及Smali文件

    转自:http://blog.csdn.net/dd864140130/article/details/52076515 今天来介绍有关Dalvik虚拟机相关的知识,首先便是介绍我们最关心的Dalvi ...

  6. 开发一个基于Dalvik字节码的相似性检测引擎,比较同一款Android应用程序的不同版本之间的代码差异(二)

    上文我们说过,<针对Dalvik字节码的相似性检测引擎,比较同一款Android应用程序的不同版本之间的代码差异>这篇文章计划分两个部分来讲解,上文只介绍了如何利用Quarkslab公司开 ...

  7. JVM学习笔记(Ⅰ):Class类文件结构解析(带你读懂Java字节码,这一篇就够了)

    JVM学习笔记(Ⅰ):Class类文件结构解析,带你读懂Java字节码 前言:本文属于博主个人的学习笔记,博主也是小白.如果有不对的地方希望各位帮忙指出.本文主要还是我的学习总结,因为网上的一些知识分 ...

  8. Dalvik字节码类型对照表

    注意:"boolean"用大写的"Z"表示,"long"用大"J"表示,"java类类型"用大写&q ...

  9. 从0到1 Android安全学习之路 -- Java 字节码和 Dalvik 字节码

    Java 字节码和 Dalvik 字节码 概述 源代码样例 Java 字节码 Dalvik 字节码 总结 概述   本篇博客将讲述 Java 源代码到字节码,字节码转汇编,以及 Android 中 J ...

最新文章

  1. php源码安全加密之PHP混淆算法.
  2. 如下10种分类算法对比Classifier comparison
  3. NR 5G 网络功能之AMF
  4. 设置ALV单元格可编辑状态
  5. fastjson解析多层数据_JSON数据如何进行解析呢,方式有哪些?
  6. 嵌入式基础之----C++
  7. MySQL的索引学习
  8. 清华大学python镜像_使用清华开源镜像安装tensorflow
  9. linux mysql 6.0.4 启动_MySQL Connector/J 6.x jdbc.properties 配置, mysql-connector-java-6.0.4.jar 异常...
  10. App后台开发运维和架构实践学习总结(12)——基于token的多平台身份认证架构设计
  11. C++中size_t和int区别
  12. NumPy进阶教程——超详细
  13. java数字高低呼唤_记录某电话交换台 5 分钟内接到的呼唤次数,则样本空间 S={0,1,2, … ,n, … }_Java答案_学小易找答案...
  14. BI与大数据之间的差距有哪些
  15. QtableView点击滑动设计
  16. JS new一个对象的过程
  17. php codesniffer 代码规范,如何用PHP_CodeSniffer检查代码规范
  18. 一杯免费咖啡引发的ERP上云思考
  19. 学生计算机编程比赛获奖感言,学生比赛获奖感言4篇
  20. php 二维数组根据某个键值倒叙、升序排序

热门文章

  1. 《第一行代码》学习笔记40-网络(1)
  2. 关于.net Microsoft.Office.Interop.Word组建操作word的问题,如何控制word表格单元格内部段落的样式。...
  3. java多线程之消费者生产者模式
  4. 修改openwrt 编译 image的大小
  5. 使用DBUnit框架数据库插入特殊字符失败的查错经历
  6. PyTorch进行神经风格转换/迁移(Neural-Transfer:图像风格迁移)
  7. Python学习笔记:面向对象编程(2)
  8. 系统安装重装与优化:chapter7 操作系统的修复与重装
  9. extern C的用法解析
  10. TensorFlow tf.data 导入数据(tf.data官方教程) * * * * *