Android逆向基础----Android Dalvik虚拟机
Android Dalvik虚拟机的特点:
l 体积小,占用内存空间小。
l 专有DEX可执行文件。
l 常量池采用32位索引值,寻址类方法名,字段名,常量更快。
l 基于寄存器架构,并拥有一套完整的指令系统。
l 提供生命周期管理、堆栈管理、线程管理、安全和异常管理以及垃圾回收等重要功能。
l 所有的Android程序都运行在Android系统进程里,每个进程对应一个Dalvik虚拟机实例。
1、Dalvik虚拟机与Java虚拟机的区别
Java虚拟机运行的是Java字节码,Dalvik虚拟机运行的是Dalvik字节码。Dalvik字节码由Java字节码转换而来,并打包成一个DEX可执行文件,通过虚拟机解释执行。
2、Dalvik可执行文件体积更小
Android SDK中的dx工具在转换字节码时会消除类文件的冗余信息,避免虚拟机在初始化时出现重复的文件加载与解析过程。另外,dx工具会将所有的Java类文件中的常量池进行分解,消除其中的冗余信息,组合成一个新的共享常量池。这使得文件体积和解析文件的效率都得到了提高。
3、Dalvik虚拟机与Java虚拟机的架构不同
Java虚拟机的架构及参数传递
Java虚拟机基于栈架构。需要频繁的从栈上读写数据,在这个过程中需要更多的指令分派与内存访问次数,耗费CPU时间,消耗手机资源。
Java虚拟机的指令集被称为零地址,是指指令的源参数与目标参数都是隐含的,它通过Java虚拟机中提高的一种数据结构“求值栈”来传递的。
对于Java程序来说,每个线程在执行时都有一个PC计数器与一个Java栈。PC计数器以字节为单位记录当前运行位置距离方法开头的偏移量,与ARM架构和x86架构类似,通过栈帧对栈中的数据进行操作。
Java栈用于记录Java方法调用的“活动记录”,Java栈以帧为单位保存线程的运行状态,每调用一个方法就会分配一个新的栈帧压入Java栈上,每从一个方法返回则弹出并撤销响应的栈帧。
每个栈帧包括局部变量区、求值栈(JVM规范中将其称为“操作数栈”)和其他一些信息。局部变量区用于存储方法的参数与局部变量,其中参数按源码中从左到右顺序保存在局部变量区开头的几个slot中。
求栈值用于保存求值的中间结果和调用别的方法的参数等,JVM运行时它的状态如下图
每条指令占用一个字节空间,foo()函数Java字节码左边的偏移量就是程序执行到每一行代码时PC的值,并且Java虚拟机最多只支撑0xff条指令。
仔细分析第一条指令iload_1的结构
iload_1可分成两部分,第一部分为下划线左边的iload,属于JVM(Java虚拟机)指令集中load系列中的一条,i是指令前缀,表示操作类型为int类型,load表示将局部变量存入Java栈。第二部分为下划线右边的数字,表示要操作具体哪个变量,索引值从0开始计数,iload_1表示将第二个int类型的局部变量进栈参数。
Dalvik虚拟机的架构及参数传递
Dalvik虚拟机基于寄存器架构,数据访问通过寄存器间直接传递。比起Java虚拟机字节码要简洁很多。
以第一条指令为例简单分析一下。指令add-int将v3与v4寄存器的值相加,然后保存到v0寄存器,v3和v4代表调用函数的所使用的两个参数。这里用到的Dalvik字节码参数表示法是v命名法,另一种是p命名法。
Dalvik虚拟机运行时同样为每个线程维护一个PC计数器与调用栈,与Java虚拟机不同的是,这个调用栈维护一份寄存器列表,寄存器的数量在方法结构体的registers字段中给出,Dalvik虚拟机会根据这个值来创建一份虚拟的寄存器列表。
Dalvik虚拟机由于生成的代码指令减少了,程序执行速度会更快一些。
Dalvik是如何执行程序的
Android系统的架构采用分层思想,这样的好处是拥有减少各层之间的依赖性、便于独立分发、容易收敛问题和错误等优点。
Android系统由linux内核、函数库、Android运行时、应用程序框架以及应用程序组成。
Android系统加载完内核后,第一个执行的是init进程,init进程对设备进行初始化,读取init.rc文件并启动系统中重要外部程序Zygote。
Zygote进程是Android所有进程的孵化器,启动后首先初始化Dalvik虚拟机,然后启动system_server并进入Zygote模式,通过socket等候命令。
当执行一个Android应用程序时,system_server进程通过socket方式发送命令给Zygote,Zygote收到命令后通过fork自身创建一个Dalvik虚拟机的实例来执行应用程序的入口函数,这就是程序启动的流程。
Zygote提供三种
fork(),创建一个Zygote进程
forkAndSpecialize(),创建一个非Zygote进程(不能再fork)
forkSystemService(),创建一个系统服务进程(子进程跟随父进程终止)
fork之后,执行的工作交给Dalvik虚拟机。虚拟机通过loadClassFromDex()函数完成类的装载工作,每个类被成功解析后会拥有一个ClassObject类型的数据结构存储在运行时环境中,虚拟机使用gDvm.loadedClasses全局哈希表来存储与查询所有装载进来的类,随后,字节码验证器使用dvmVerifyCodeFlow()函数对装入的代码进行校验,接着虚拟机调用FindClass()函数查找并装载main方法类,随后调用dvmInterpret()函数初始化解释器并执行字节码流。
Dalvik虚拟机执行程序流程
虚拟机线程->装载程序类->验证字节码->查找主类->执行字节码流->结束
关于Dalvik虚拟机JIT
JIT是即时编译(动态编译),是通过在运行时将字节码翻译为机器码的技术,使得程序的执行速度更快。
主流的JIT包含两种字节码编译方式:
method方式:以函数或方法为单位进行编译。
trace方式:以trace为单位进行编译。
执行代码分为冷路径(在实践运行过程中很少被执行的)和热路径(执行比较频繁的路径),method会编译整个方法,trace编译的是获取的热路径的代码,节省内存。
编辑参考:Android软件安全与逆向分析
转载于:https://www.cnblogs.com/zhaijiahui/p/8810887.html
Android逆向基础----Android Dalvik虚拟机相关推荐
- Android逆向 学习Android安全和逆向开发的路线总结,啃下这些Framework技术笔记
此篇整理了最完整的–Android逆向学习线路知识体系.希望给迷糊的入门者指出一个明确的方向. 真心建议:先正向开发几年再搞逆向吧--正向都不会破解的是啥?不看代码只会脱壳?只会xposed ?远远不 ...
- Android逆向 学习Android安全和逆向开发的路线总结,android开发平台的发展
学习Android逆向之前,必备条件.[必备,出去面试正经公司的安全岗位都会问的基础问题] 从事3-5年真实的Android开发工作,熟练使用C/C++,Java,kotlin,dart等Androi ...
- 【Android 逆向】Android 逆向通用工具开发 ( PC 端工程分析 | 网络初始化操作 | PC 端工程核心业务逻辑 )
文章目录 前言 一.网络初始化操作 二.PC 端工程核心业务逻辑 三.博客资源 前言 本篇博客重点分析 PC 端 hacktool 模块 ; 一.网络初始化操作 HackCommand::Prepar ...
- 【Android 逆向】Android 逆向通用工具开发 ( Windows 平台运行的控制台应用程序类型 | 编译 Windows 平台运行的 Android 逆向程序 )
文章目录 一.Windows 平台运行的控制台应用程序类型 二.编译 Windows 平台运行的 Android 逆向程序 一.Windows 平台运行的控制台应用程序类型 hacktool 工程的类 ...
- 【Android 逆向】Android 进程注入工具开发 ( 总结 | 源码编译 | 逆向环境搭建使用 | 使用进程注入工具进行逆向操作 ) ★★★
文章目录 一.Android 进程注入工具开发系列博客 二.Android 进程注入工具 源码下载编译 三.逆向环境搭建 四.使用注入工具进行逆向操作 1.获取远程进程号 2.注入工具准备 3.注入动 ...
- 【Android 逆向】Android 进程注入工具开发 ( 远程调用 | x86 架构的返回值获取 | arm 架构远程调用 )
文章目录 前言 一.x86 架构的返回值获取 二.ARM 架构远程调用 前言 在之前的博客 [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | 获取 远程 目标进程 中的 ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 注入工具收尾操作 | 关闭注入的动态库 | 恢复寄存器 | 脱离远程调试附着 )
文章目录 一.dlclose 函数简介 二.关闭注入的 libbridge.so 动态库 三.恢复寄存器 四.脱离远程调试附着 一.dlclose 函数简介 dlclose 函数的作用是 卸载一个 指 ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取注入的 libbridge.so 动态库中的 load 函数地址 并 通过 远程调用 执行该函数 )
文章目录 一.dlsym 函数简介 二.获取 目标进程 linker 中的 dlsym 函数地址 三.远程调用 目标进程 linker 中的 dlsym 函数 获取 注入的 libbridge.so ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取 linker 中的 dlopen 函数地址 并 通过 远程调用 执行该函数 )
文章目录 一.dlopen 函数简介 二.获取 目标进程 linker 中的 dlopen 函数地址 三.远程调用 目标进程 linker 中的 dlopen 函数 一.dlopen 函数简介 dlo ...
最新文章
- 查看服务器的某个端口是否允许访问
- ReentrantLock可以是公平锁,sync只能是非公平锁。
- android 切换字体崩溃,androidx - 在Android 10 / Android Q上使用捆绑的ttf字体时崩溃 - 堆栈内存溢出...
- python面试题37道(附答案)看完面试不愁了
- 语言用符号打印出落叶的图案_世界上最好玩的6种表情符号编程语言
- 在JavaScript中NaN为什么不等于NaN
- navicat 使用ssh连接腾讯云主机mysql数据库(保姆级教程)
- uni-app接入友盟
- 多人在线编辑文档 开发_十个在线小工具,科研amp;工作必备神器!
- android笔记 看过stormzhang大大的博客(关于像素,屏幕密度)
- 【jackson异常】com.fasterxml.jackson.databind.JsonMappingException异常处理方法
- iOS 多线程-GCD栅栏方法
- Mysql 杂文记事
- AIR2.0 打开exe
- [Spring实战系列](12)Bean的自动装配
- 社交图片分享应用Instagram
- 统计图之小提琴图解析
- 项目管理PMP学习之10大知识领域
- 2022最新视频打赏系统全开源版本+附教程/亲测可用
- QNX Neutrino 进程间通信编程之Message-passing/Pulse