xposed流程图解析

时间:2024-04-09 07:16:11

二、Xposed机制介绍
这里我们采用大量的流程图来解析。
xposed流程图解析
通过分析android源码,我们可以得出如上图的结论:
不论是java层还是c层的代码,都会进过一个统一的执行函数dvmCallMethodV,之后才判断是解释执行还是elf方式执行。

xposed流程图解析
图1 Xposed启动过程
Xposed通过更改源码app_proccess中的app_main.c用来替换android 解释器zgote孵化器。这个孵化器是每个apk启动过程中都要复制的一个进程。通过更换这个文件。我们便可随意更改执行流程。
如图1中,正常的系统源码通过AndroidRuntime::start()启动com.android.internal.os.ZygotInit。更改过的代码执行xposed的替换代码de.rodv.android.xposed.XposedBridge,之后再调用com.android.internal.os.ZygotInit。这部分是c代码,de.rodv.android.xposed.XposedBridge和com.android.internal.os.ZygotInit是java代码。

xposed流程图解析
图2
de.rodv.android.xposed.XposedBridge位于XposedBridge.java。这里的java代码通过回调机制定义了函数hook前后调用相应的接口,我们在编写hook模块的时候就是实现的这几个接口。

xposed流程图解析
图3.更改执行流程

为了实现用户自定义的接口代码能够执行,XposedBridge模块调用了app_process模块中的类一个关键C代码函数,de_robv_android_xposed_XposedBridge_hookMethod_hookMethodNative函数,这个函数主要作用是把我们之前dvmCallMethodV函数用来判断执行java和c代码执行流程的标志进行更改。如图3。这样,执行流程就被劫持了。通过c指针我们成功的跳转到了自定义的接口回调,也就是用户自定义的hook代码。

三 .Xposed进行所有应用内存Got替换操作
如此我们知道,android通过复制zgote的执行流程被控制了。每一个apk执行的过程也被控制了。但是可惜的是,xposed的作者没有添加关于c代码层hook的逻辑,劫持仅仅停留在java层的hook。但是,本身这个框架拥有很大的潜力,如果在加载自定hook模块的同时,对内存进行操作,替换加载在内存中的Elf-got表,就可以实现native层的函数。如图下:

xposed流程图解析
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (off == false)
{
flushConfig();
}
if (!loadPackageParam.packageName.equals(GlobalConfig.Inject_PackageName))
return;
Class clazz = XposedHelpers.findClass(“java.lang.System”, loadPackageParam.classLoader); //使用注入包的类加载器来反射查找System.load函数,从而调用加载自己的框架so
if(clazz == null)
{
XposedBridge.log("[-] not found class: " + “java.lang.System”);
Log.e(GlobalConfig.Log_TAG, "[-] can’t found class: " + “java.lang.System”);
return;
}
Log.e(GlobalConfig.Log_TAG, "[+] found class: " + “java.lang.System”);
Method method = XposedHelpers.findMethodExact(clazz, “load”, String.class);//查找system.load函数
if (method == null)
{
Log.e(GlobalConfig.Log_TAG, "[-] can’t found function: " + method.getName());
}
Log.e(GlobalConfig.Log_TAG, "[+] found function: " + method.getName());
method.invoke(null, GlobalConfig.Inject_SoPath);//加载待注入库
}
通过实现,我最终在Android沙箱中利用此技术成功的实现了native的实时监控,对比之前采用的substrate,稳定性有了很大的改善。