Android so注入-libinject2 简介、编译、运行

Android so注入-libinject2  如何实现so注入

Android so注入-Libinject 如何实现so注入

Android so注入挂钩-Adbi 框架简介、编译、运行

Android so注入挂钩-Adbi 框架如何实现so注入

Android so注入挂钩-Adbi 框架如何实现so函数挂钩

Android so注入挂钩-Adbi 框架如何实现dalvik函数挂钩

Android dalvik挂钩-Xposed框架如何实现注入

Android dalvik挂钩-Xposed框架如何实现挂钩

前面知道,安装xposed框架后,系统启动,执行init, init 再调用 app_process 程序,由于这时候 app_process 已经被换了,所以app_process 启动后先进入的是 xposedbridge.class 的 main 函数, 这个函数最后才进入标准的 zygoteInit.class 的 main 函数,在进入 zygote 之前,它调用了几个函数,初始化了xposed框架,下面逐个分析。

一. initNative

Xposed.cpp (xposed): {"initNative", "()Z", (void*)de_robv_android_xposed_XposedBridge_initNative},
XposedBridge.java (xposedbridge\src\de\robv\android\xposed): if (initNative()) {
XposedBridge.java (xposedbridge\src\de\robv\android\xposed): private native static boolean initNative();

XposedBridge.class 的 initNative 是一个 native 函数,真正的实现在 Xposed.cpp 里的  de_robv_android_xposed_XposedBridge_initNative

1. de_robv_android_xposed_XposedBridge_initNative(JNIEnv* env, jclass clazz)

 xposedHandleHookedMethod = (Method*) env->GetStaticMethodID(xposedClass, "handleHookedMethod",
"(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");

首先,从xposedClass(即XposedBridge.class)类获取函数 handleHookedMethod, 这个函数是java函数,这里获取其对应的 Method 结构体指针,这样就可以在 native 里调用(jni的原理)。那么,这个 handleHookedMethod 是干嘛的呢,这个函数就是最终执行的挂钩函数,后面会分析。

Method* xposedInvokeOriginalMethodNative = (Method*) env->GetStaticMethodID(xposedClass, "invokeOriginalMethodNative",
"(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
dvmSetNativeFunc(xposedInvokeOriginalMethodNative, de_robv_android_xposed_XposedBridge_invokeOriginalMethodNative, NULL);

其次,从xposedClass(即XposedBridge.class)类获取函数  invokeOriginalMethodNative 函数的 Method 结构体指针,然后调用  dvmSetNativeFunc 为这个java函数设置其 jni 实现  de_robv_android_xposed_XposedBridge_invokeOriginalMethodNative , 这样,调用 invokeOriginalMethodNative  函数其实执行的是后者。

objectArrayClass = dvmFindArrayClass("[Ljava/lang/Object;", NULL);
xresourcesClass = env->FindClass(XRESOURCES_CLASS);
xresourcesClass = reinterpret_cast<jclass>(env->NewGlobalRef(xresourcesClass));
if (register_android_content_res_XResources(env) != JNI_OK) {}
xresourcesTranslateResId = env->GetStaticMethodID(xresourcesClass, "translateResId",
"(ILandroid/content/res/XResources;Landroid/content/res/Resources;)I");
xresourcesTranslateAttrId = env->GetStaticMethodID(xresourcesClass, "translateAttrId",
"(Ljava/lang/String;Landroid/content/res/XResources;)I");

最后,获取其他一些java类或函数的标识

二, initXbridgeZygote

XposedBridge.class main 函数第二个重要的函数是 initXbridgeZygote

// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
findAndHookMethod(ActivityThread.class, "handleBindApplication", "android.app.ActivityThread.AppBindData", new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
。。。
}

首先,挂钩了 ActivityThread 类的  handleBindApplication 函数,这个函数是在android ams 系统创建新进程成功后在新进程内部调用的,挂钩这个函数,可以在新进程创建后做一些事情

这里调用了一个函数,实现了挂钩  findAndHookMethod 。这个函数定义在 XposedHelpers.java

XposedHelpers.class

public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
if (parameterTypesAndCallback.length == || !(parameterTypesAndCallback[parameterTypesAndCallback.length-] instanceof XC_MethodHook))
throw new IllegalArgumentException("no callback defined"); XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-];
Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback)); return XposedBridge.hookMethod(m, callback);
}

这个函数找到类 clazz 的函数 methodName 所对应的 Method结构体,然后调用 XposedBridge 的 hookMethod 函数挂钩它

XposedBridge.class

public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
.... boolean newMethod = false;
CopyOnWriteSortedSet<XC_MethodHook> callbacks;
synchronized (sHookedMethodCallbacks) {
callbacks = sHookedMethodCallbacks.get(hookMethod);
if (callbacks == null) {
callbacks = new CopyOnWriteSortedSet<XC_MethodHook>();
sHookedMethodCallbacks.put(hookMethod, callbacks);
newMethod = true;
}
}
callbacks.add(callback); // 先将被挂钩的函数 hookMethod 及挂钩它的函数保存起来
if (newMethod) {
Class<?> declaringClass = hookMethod.getDeclaringClass();
int slot = (int) getIntField(hookMethod, "slot"); Class<?>[] parameterTypes;
Class<?> returnType;
if (hookMethod instanceof Method) {
parameterTypes = ((Method) hookMethod).getParameterTypes();
returnType = ((Method) hookMethod).getReturnType();
} else {
parameterTypes = ((Constructor<?>) hookMethod).getParameterTypes();
returnType = null;
} AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType);
hookMethodNative(hookMethod, declaringClass, slot, additionalInfo); // 最终调用 hookMethodNative 函数
} return callback.new Unhook(hookMethod); }

这个函数先将被挂钩的函数 hookMethod 及挂钩它的 XC_MethodHook结构体保存起来,然后调用 hookMethodNative 函数

{"hookMethodNative", "(Ljava/lang/reflect/Member;Ljava/lang/Class;ILjava/lang/Object;)V", (void*)de_robv_android_xposed_XposedBridge_hookMethodNative},

这个函数定义在 xposed.cpp 里

static void de_robv_android_xposed_XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect,
jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) {
// Usage errors?
if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) {
dvmThrowIllegalArgumentException("method and declaredClass must not be null");
return;
} // Find the internal representation of the method
ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
Method* method = dvmSlotToMethod(declaredClass, slot);
if (method == NULL) {
dvmThrowNoSuchMethodError("could not get internal representation for method");
return;
} if (xposedIsHooked(method)) {
// already hooked
return;
} // Save a copy of the original method and other hook info
XposedHookInfo* hookInfo = (XposedHookInfo*) calloc(, sizeof(XposedHookInfo));
memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct));
hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect));
hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect)); // Replace method with our own code
SET_METHOD_FLAG(method, ACC_NATIVE);
method->nativeFunc = &xposedCallHandler;
method->insns = (const u2*) hookInfo;
method->registersSize = method->insSize;
method->outsSize = ;
if (PTR_gDvmJit != NULL) {
// reset JIT cache
char currentValue = *((char*)PTR_gDvmJit + MEMBER_OFFSET_VAR(DvmJitGlobals,codeCacheFull));
if (currentValue == || currentValue == ) {
MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true;
} else {
ALOGE("Unexpected current value for codeCacheFull: %d", currentValue);
}
}
}

这个过程跟ADBI框架类似,先获取要挂钩的java函数的 Method 结构体指针,然后检查一下是否已经被挂钩了,如果是直接返回,否则,通过对 Method 结构体进行赋值的方式,完成挂钩

method->nativeFunc = &xposedCallHandler;
method->insns = (const u2*) hookInfo;
method->registersSize = method->insSize;
method->outsSize = ;

这里挂钩函数全部使用 xposedCallHandler 这个函数。挂钩的详细信息保存在 Method结构体的 insns 成员里

xposed.cpp

static void xposedCallHandler(const u4* args, JValue* pResult, const Method* method, ::Thread* self) {
。。。
JValue result;
dvmCallMethod(self, xposedHandleHookedMethod, NULL, &result,
originalReflected, (int) original, additionalInfo, thisObject, argsArray);
。。。
}

可以看到,最终执行xposedHandleHookedMethod这个native函数,这个native函数前面 initNative 执行时,已经获取了它的java实现,真正的实现在

XposedBridge.java

private static Object handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,
Object thisObject, Object[] args) throws Throwable {
AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj; if (disableHooks) {
try {
return invokeOriginalMethodNative(method, originalMethodId, additionalInfo.parameterTypes,
additionalInfo.returnType, thisObject, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} Object[] callbacksSnapshot = additionalInfo.callbacks.getSnapshot();
final int callbacksLength = callbacksSnapshot.length;
if (callbacksLength == ) {
try {
return invokeOriginalMethodNative(method, originalMethodId, additionalInfo.parameterTypes,
additionalInfo.returnType, thisObject, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} MethodHookParam param = new MethodHookParam();
param.method = method;
param.thisObject = thisObject;
param.args = args; // call "before method" callbacks
int beforeIdx = ;
do {
try {
((XC_MethodHook) callbacksSnapshot[beforeIdx]).beforeHookedMethod(param);
} catch (Throwable t) {
XposedBridge.log(t); // reset result (ignoring what the unexpectedly exiting callback did)
param.setResult(null);
param.returnEarly = false;
continue;
} if (param.returnEarly) {
// skip remaining "before" callbacks and corresponding "after" callbacks
beforeIdx++;
break;
}
} while (++beforeIdx < callbacksLength); // call original method if not requested otherwise
if (!param.returnEarly) {
try {
param.setResult(invokeOriginalMethodNative(method, originalMethodId,
additionalInfo.parameterTypes, additionalInfo.returnType, param.thisObject, param.args));
} catch (InvocationTargetException e) {
param.setThrowable(e.getCause());
}
} // call "after method" callbacks
int afterIdx = beforeIdx - ;
do {
Object lastResult = param.getResult();
Throwable lastThrowable = param.getThrowable(); try {
((XC_MethodHook) callbacksSnapshot[afterIdx]).afterHookedMethod(param);
} catch (Throwable t) {
XposedBridge.log(t); // reset to last result (ignoring what the unexpectedly exiting callback did)
if (lastThrowable == null)
param.setResult(lastResult);
else
param.setThrowable(lastThrowable);
}
} while (--afterIdx >= ); // return
if (param.hasThrowable())
throw param.getThrowable();
else
return param.getResult();
}

这个函数查找被挂钩函数的挂钩 XC_MethodHook 结构体,然后执行里边的 beforeHookedMethod 函数,再通过 invokeOriginalMethodNative 执行挂钩前的原始函数,最后再执行 afterHookedMethod 函数。

findAndHookMethod 的实现就分析完了,本质上仍然是寻找被挂钩函数的 Method 结构体,将Method属性改为native ,然后对其成员 nativeFunc, registersize 等进行赋值,其中 insns 成员保存了挂钩的详细信息。所有被挂钩的函数,其nativeFunc都赋值为 xposedCallHandler 函数,该函数最终执行 XposedBridge.class 里的 handleHookedMethod 。 handleHookedMethod 寻找 xposed模块及xposed框架调用 findAndHookMethod 注册的 before,after 函数,如果有,就执行,再通过 invokeOriginalMethodNative 执行挂钩前函数。

回到 initXbridgeZygote  函数,xposed 框架预先挂钩的函数,除了 handleBindApplication 外,还有

com.android.server.ServerThread  系统thread创建时触发
hookAllConstructors(LoadedApk.class, new XC_MethodHook(){。。。} apk 包加载时触发这个挂钩
findAndHookMethod("android.app.ApplicationPackageManager", null, "getResourcesForApplication", 。。。 3. loadModules
/**
* Try to load all modules defined in <code>BASE_DIR/conf/modules.list</code>
*/
private static void loadModules(String startClassName) throws IOException {
BufferedReader apks = new BufferedReader(new FileReader(BASE_DIR + "conf/modules.list"));
String apk;
while ((apk = apks.readLine()) != null) {
loadModule(apk, startClassName);
}
apks.close();
}

xposed框架本身挂钩的函数很少,真正的挂钩由具体的xposed模块实现,xposed模块也是正常的app,安装的时候注册其挂钩信息到xposed框架的 modules.list 等配置里。xposed框架初始化的时候, 加载这些模块,并完成挂钩函数的挂钩

/**
* Load a module from an APK by calling the init(String) method for all classes defined
* in <code>assets/xposed_init</code>.
*/
@SuppressWarnings("deprecation")
private static void loadModule(String apk, String startClassName) {
。。。。
while ((moduleClassName = moduleClassesReader.readLine()) != null) {// call the init(String) method of the module
final Object moduleInstance = moduleClass.newInstance();
if (startClassName == null) {
if (moduleInstance instanceof IXposedHookZygoteInit) {
IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
param.modulePath = apk;
((IXposedHookZygoteInit) moduleInstance).initZygote(param);
} if (moduleInstance instanceof IXposedHookLoadPackage)
hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance)); if (moduleInstance instanceof IXposedHookInitPackageResources)
hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
} else {
if (moduleInstance instanceof IXposedHookCmdInit) {
IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
param.modulePath = apk;
param.startClassName = startClassName;
((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
}
}
}
}
loadModule 函数从配置文件里读取所有的模块,实例化模块类,xposed 提供了几个接口类供xposed模块继承,不同的接口类对应不同的hook时机

IXposedHookZygoteInit  zygote 初始化前就执行挂钩,即loadModule执行时就挂钩了
IXposedHookLoadPackage apk包加载的时候执行挂钩,先将挂钩函数保存起来,等加载apk函数执行后触发callback (这里的callback是xposed框架自己挂钩的函数),再执行模块注册的挂钩函数
IXposedHookInitPackageResources apk资源实例化时执行挂钩,同上

android hook 框架 xposed 如何实现挂钩的更多相关文章

  1. 【转】Android Hook框架Xposed详解

    1 Introduction 1.1  概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_pro ...

  2. Android Hook框架Xposed详解

    1 Introduction 1.1  概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_pro ...

  3. android hook 框架 xposed 如何实现注入

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  4. [转载] Android.Hook框架xposed开发篇

    本文转载自: http://www.52pojie.cn/thread-396793-1-1.html 原帖:http://drops.wooyun.org/tips/7488 作者:瘦蛟舞 官方教程 ...

  5. android hook 框架 ADBI 如何实现dalvik函数挂钩

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  6. android hook 框架 libinject2 如何实现so注入

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  7. android hook 框架 libinject2 简介、编译、运行

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  8. android hook 框架 libinject 如何实现so注入

    前面两篇 android hook 框架 libinject2 简介.编译.运行 android hook 框架 libinject2 如何实现so注入 实际运行并分析了 Android中的so注入( ...

  9. Android Hook框架adbi的分析(1)---注入工具hijack

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/74055505 一.Android Hook框架adbi的基本介绍 adbi是And ...

随机推荐

  1. strchr函数的用法

    原型: char *strchr(const char *s,char c); #include<string.h> 查找字符串s中首次出现字符c的位置,返回首次出现c的位置的指针,如果s ...

  2. POJ:3126-Prime Path

    题目链接:http://poj.org/problem?id=3126 Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...

  3. mac上MySQLdb问题解决

    早上有个同学问题python访问mysql的问题,之前的写得脚步突然不能运行了,找了很多文章总算解决问题了O(∩_∩)O哈哈~,希望下次不要浪费这么多时间搞这么坑的问题了.   mac上MySQLdb ...

  4. Java线程---简介

    实现方式 在java中线程有两种实现方式: 1.继承thread类 2.实现runnable接口 Thread类 Thread类时在java.lang包中定义的,继承thread类必须重写run()方 ...

  5. android 事件传递机制

    有三个方法: dispatchTouchEvent onInterceptTouchEvent onTouchEvent 首先:A的dispatchTouchEvent-A的onInterceptTo ...

  6. Android stadio 自定义debug release keystore

    1.添加siggnig name 随意,不过按我写的就可以了.设置完成之后,你的build.grade就会多出来一些: android { signingConfigs { signingConfig ...

  7. 运行SparkStreaming程序时出现 Exception in thread "main" java.lang.NoSuchMethodError: scala.Predef$.ArrowA异常

    Exception in thread "main" java.lang.NoSuchMethodError: scala.Predef$.ArrowA 这个问题是版本不统一导致的 ...

  8. Django 2.0官方文档中文 总索引

    Django 2.0官方文档中文 渣翻 总索引 翻译 2017年12月08日 11:19:1 官方原文: https://docs.djangoproject.com/en/2.0/ 当前翻译版本:  ...

  9. USACO Section1.3 Barn Repair 解题报告

    barn1解题报告 —— icedream61 博客园(转载请注明出处)---------------------------------------------------------------- ...

  10. 孤荷凌寒自学python第五十五天初识MongoDb数据库

    孤荷凌寒自学python第五十五天第一天初识MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 大家好,2019年新年快乐! 本来我想的是借新年第一天开始,正式尝试学习爬虫,结果今天偶然发现 ...