解决换肤框架与高德地图的冲突
直接通过内存地址替换整个 ArtMethod ,完成了高德地图方法的替换。
This commit is contained in:
87
modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp
Normal file
87
modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <jni.h>
|
||||
#include <string.h>
|
||||
|
||||
//
|
||||
// Created by donghongyu on 12/10/20 1:34 PM.
|
||||
// 源码地址 https://github.com/pqpo/methodhook
|
||||
// 方法hook jni类
|
||||
static const char *kClassMethodHookChar = "com/mogo/module/common/hook/MethodHook";
|
||||
|
||||
static struct {
|
||||
jmethodID m1;
|
||||
jmethodID m2;
|
||||
size_t methodSize;
|
||||
} methodHookClassInfo;
|
||||
|
||||
|
||||
/**
|
||||
* 替换指定类中的方法
|
||||
* @param env
|
||||
* @param type 要替换方法的目标 class
|
||||
* @param srcMethodObj 目标方法对象
|
||||
* @param destMethodObj 替换的方法对象
|
||||
* @return
|
||||
*/
|
||||
static jlong methodHook(JNIEnv *env, jclass type, jobject srcMethodObj, jobject destMethodObj) {
|
||||
void *srcMethod = reinterpret_cast<void *>(env->FromReflectedMethod(srcMethodObj));
|
||||
void *destMethod = reinterpret_cast<void *>(env->FromReflectedMethod(destMethodObj));
|
||||
int *backupMethod = new int[methodHookClassInfo.methodSize];
|
||||
memcpy(backupMethod, srcMethod, methodHookClassInfo.methodSize);
|
||||
memcpy(srcMethod, destMethod, methodHookClassInfo.methodSize);
|
||||
return reinterpret_cast<long>(backupMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复指定类中的方法
|
||||
* @param env
|
||||
* @param type 要恢复方法的目标 class
|
||||
* @param srcMethod 目标方法对象
|
||||
* @param methodPtr
|
||||
* @return
|
||||
*/
|
||||
static jobject methodRestore(JNIEnv *env, jclass type, jobject srcMethod, jlong methodPtr) {
|
||||
int *backupMethod = reinterpret_cast<int *>(methodPtr);
|
||||
void *artMethodSrc = reinterpret_cast<void *>(env->FromReflectedMethod(srcMethod));
|
||||
memcpy(artMethodSrc, backupMethod, methodHookClassInfo.methodSize);
|
||||
delete[]backupMethod;
|
||||
return srcMethod;
|
||||
}
|
||||
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
{
|
||||
"hook_native",
|
||||
"(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)J",
|
||||
(void *) methodHook
|
||||
},
|
||||
{
|
||||
"restore_native",
|
||||
"(Ljava/lang/reflect/Method;J)Ljava/lang/reflect/Method;",
|
||||
(void *) methodRestore
|
||||
}
|
||||
};
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
/**
|
||||
* 在jni加载的时候进行方法参数获取
|
||||
* @param vm
|
||||
* @param reserved
|
||||
* @return
|
||||
*/
|
||||
JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env = nullptr;
|
||||
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jclass classEvaluateUtil = env->FindClass(kClassMethodHookChar);
|
||||
if (env->RegisterNatives(classEvaluateUtil, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) <
|
||||
0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
methodHookClassInfo.m1 = env->GetStaticMethodID(classEvaluateUtil, "m1", "()V");
|
||||
methodHookClassInfo.m2 = env->GetStaticMethodID(classEvaluateUtil, "m2", "()V");
|
||||
methodHookClassInfo.methodSize = reinterpret_cast<size_t>(methodHookClassInfo.m2) -
|
||||
reinterpret_cast<size_t>(methodHookClassInfo.m1);
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mogo.module.common.hook;
|
||||
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 替换管理
|
||||
* Created by donghongyu on 12/29/20 1:34 PM
|
||||
*/
|
||||
public final class HookManager {
|
||||
|
||||
private HookManager() {
|
||||
}
|
||||
|
||||
public static HookManager get() {
|
||||
return InstanceHolder.sInstance;
|
||||
}
|
||||
|
||||
private static class InstanceHolder {
|
||||
private static HookManager sInstance = new HookManager();
|
||||
}
|
||||
|
||||
private Map<Pair<String, String>, MethodHook> methodHookMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 替换方法
|
||||
*
|
||||
* @param originMethod 原始方法
|
||||
* @param hookMethod 替换方法
|
||||
*/
|
||||
public void hookMethod(Method originMethod, Method hookMethod) {
|
||||
if (originMethod == null || hookMethod == null) {
|
||||
throw new IllegalArgumentException("argument cannot be null");
|
||||
}
|
||||
|
||||
Pair<String, String> key = Pair.create(hookMethod.getDeclaringClass().getName(), hookMethod.getName());
|
||||
if (methodHookMap.containsKey(key)) {
|
||||
MethodHook methodHook = methodHookMap.get(key);
|
||||
methodHook.restore();
|
||||
}
|
||||
MethodHook methodHook = new MethodHook(originMethod, hookMethod);
|
||||
methodHookMap.put(key, methodHook);
|
||||
methodHook.hook();
|
||||
}
|
||||
|
||||
public void callOrigin(Object receiver, Object... args) {
|
||||
StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[3];
|
||||
String className = stackTrace.getClassName();
|
||||
String methodName = stackTrace.getMethodName();
|
||||
MethodHook methodHook = methodHookMap.get(Pair.create(className, methodName));
|
||||
if (methodHook != null) {
|
||||
try {
|
||||
methodHook.callOrigin(receiver, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.mogo.module.common.hook;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 替换类与c++代码对应
|
||||
* Created by donghongyu on 12/29/20 1:34 PM
|
||||
*/
|
||||
public class MethodHook {
|
||||
|
||||
public static void m1() {
|
||||
}
|
||||
|
||||
public static void m2() {
|
||||
}
|
||||
|
||||
// 目标方法
|
||||
private Method srcMethod;
|
||||
// 要替换的方法
|
||||
private Method hookMethod;
|
||||
|
||||
// 备份目标替换方法ID
|
||||
private long backupMethodPtr;
|
||||
|
||||
public MethodHook(Method src, Method dest) {
|
||||
srcMethod = src;
|
||||
hookMethod = dest;
|
||||
srcMethod.setAccessible(true);
|
||||
hookMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
public void hook() {
|
||||
if (backupMethodPtr == 0) {
|
||||
backupMethodPtr = hook_native(srcMethod, hookMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public void restore() {
|
||||
if (backupMethodPtr != 0) {
|
||||
restore_native(srcMethod, backupMethodPtr);
|
||||
backupMethodPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void callOrigin(Object receiver, Object... args) throws InvocationTargetException, IllegalAccessException {
|
||||
if (backupMethodPtr != 0) {
|
||||
restore();
|
||||
srcMethod.invoke(receiver, args);
|
||||
hook();
|
||||
} else {
|
||||
srcMethod.invoke(receiver, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static native long hook_native(Method src, Method dest);
|
||||
|
||||
private static native Method restore_native(Method src, long methodPtr);
|
||||
|
||||
static {
|
||||
System.loadLibrary("method-hook-lib");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user