Xposed hook原理

来源:互联网 发布:php foreach 编辑:程序博客网 时间:2024/06/08 00:26


java源码经过编译后,得到很多个class文件, 考虑到手机的内存较小,google改进了字节码的组织形式,将一个app中的所有class文件合到了一起构成dex文件。dex文件最终会和资源文件等一起打包成为apk,签名后安装到手机上。

PackageManager在安装apk时,优化dex文件为odex,存放在/data/dalvik-cache目录下。

dex文件是遵从于dalvik虚拟机标准的文件,它具有跨dalvik虚拟机的特点,而odex是在特定dalvik虚拟机上优化得到的,通常不能跨dalvik虚拟机运行。



程序执行体现在方法的执行上,在dex文件中,方法体里面的内容最终存储在classData区域,方法体里面存储的是二进制的字节码。

dalvik虚拟机是用c/c++写的一套复杂的程序,它定义了256个的smali指令,这些字节码指令高度抽象,组合这些指令可以完成我们想要的功能。smali/baksmali工具可以分析dex文件,解析字节码为对应的smali语法(反汇编),同时也可以将smali语法的文件重新转换为字节码生成dex文件(汇编)。

dex优化过程,其实是将一些字节码替换为dalvik相关的, 优化后的等价字节码。



虚拟机是如何执行这些字节码的呢?
虚拟机对于每一个字节码,都写了一段代码来解释执行。虚拟机在加载了odex(虚拟机总是使用odex文件,第一次使用时会先生成odex), 会将整个odex文件的内容mmap到内存中,之后就和odex文件没有关系了。

虚拟机在load一个Class的时候(参见DexClassLoader源码),根据类的描述符,在内存中的odex区域,查询到对应的数据,构建出ClassObject对象,以及这个ClassObject关联的Method。

Method分为两种,dalvik虚拟机在处理的时候有区别,一种是directMethod,即Java世界里面实现的方法,一种是nativeMethod,即在c/c++里面实现的方法。

ClassObject里面有两个集合,分别存放了这个Class下定义的directMethods和nativeMethods。

Method中,有两个非常重要的指针:

const u2* insns; DalvikBridgeFunc nativeFunc;

对于directMethod,insns存放了该方法的字节码指针(还记得odex被mmap到内存中了么,这个指针就是这段内存里面指向code区域的开始处的指针)。
虚拟机在调用directMethod时,在构建好方法栈以后,pc指针指向了insns,于是可以从内存中取得字节码,然后解释执行。

虚拟机在处理native方法时,走的是另外一套逻辑。

我们在使用native方法时,首先得使用System.loadLibrary对so进行加载,其最终是使用dlopen函数加载了指定的so文件。

之后在我们调用nativeMehtod的时候,会根据方法描述符,通过特定的映射关系(是否主动进行了注册会有不同)得到一个native层的函数名,再从之前dlopen获得的句柄中使用dlsys去查找对应的函数,得到了函数指针后,将这个指针赋值给 insns。在nativeFunc这个桥接函数中,将insns解析为函数指针,然后进行调用。



Xposed hook原理

一个java方法在虚拟机里面对应的Method为directMethod,其insns指向了字节码位置。

Xposed在对java方法进行hook时,先将虚拟机里面这个方法的Method的accessFlag改为native对应的值,然后将该方法的nativeFunc指向自己实现的一个native方法,这样方法在调用时,就会调用到这个native方法,接管了控制权。

在这个native方法中,xposed直接调用了一个java方法,这个java方法里面对原方法进行了调用,并在调用前后插入了钩子,于是就hook住了这个方法。


如何将hook的代码注入到目标app的进程中?

Xposed的实现是依赖于root,重写android的zygote代码,加入自身的加载逻辑。zygote是android 系统最初运行的程序,之后的进程都是通过它fork出来的。 于是zygote中加载的代码,在所有fork出来的子进程都含有。 所以xposed是一个可以hook android系统中任意一个java方法的 hook框架。




整理自:http://www.jianshu.com/p/b29a21a162ad
原创粉丝点击