将hook单独作为库引入

This commit is contained in:
董宏宇
2020-12-31 16:43:05 +08:00
parent 789d983021
commit d582bc3c41
9 changed files with 10 additions and 339 deletions

View File

@@ -1,16 +0,0 @@
//
// Created by on 2020-05-08.
//
#ifndef API_H
#define API_H
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"Native_RtmpPusher",__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,"Native_RtmpPusher",__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,"Native_RtmpPusher",__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"Native_RtmpPusher",__VA_ARGS__)
#endif //API_H

View File

@@ -1,108 +0,0 @@
#include <jni.h>
#include <string.h>
#include "Api.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
* @param srcMethodObj 目标方法对象
* @param destMethodObj 替换的方法对象
* @return
*/
static jlong methodHook(JNIEnv *env,
jclass type,
jobject srcMethodObj,
jobject destMethodObj) {
// 反射获取了Java对象的在native层的 ArtMethod指针
void *srcMethod = reinterpret_cast<void *>(env->FromReflectedMethod(srcMethodObj));
void *destMethod = reinterpret_cast<void *>(env->FromReflectedMethod(destMethodObj));
// 定义存储方法ID的数组
int *backupMethod = new int[methodHookClassInfo.methodSize];
// 使用的内存拷贝函数
// 将旧方法ID拷贝到数组中
memcpy(backupMethod, srcMethod, methodHookClassInfo.methodSize);
// 将新方法替换到旧方法地址上
memcpy(srcMethod, destMethod, methodHookClassInfo.methodSize);
// 将旧方法ID返回给java层用来做方法还原使用
return reinterpret_cast<long>(backupMethod);
}
/**
* 恢复指定类中的方法
* @param env
* @param type
* @param srcMethod 目标方法对象
* @param methodPtr
* @return
*/
static jobject methodRestore(JNIEnv *env,
jclass type,
jobject srcMethod,
jlong methodPtr) {
// 要还原的旧方法 指针
int *backupMethod = reinterpret_cast<int *>(methodPtr);
// 获取了Java对象的在native层的 ArtMethod指针
void *artMethodSrc = reinterpret_cast<void *>(env->FromReflectedMethod(srcMethod));
// 将旧方法指针,替换到 artMethodSrc 中
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;
}
// 加载指定java class
jclass classEvaluateUtil = env->FindClass(kClassMethodHookChar);
// 注册
if (env->RegisterNatives(classEvaluateUtil, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) <
0) {
return JNI_FALSE;
}
// 获取 MethodHook m1、m2 的方法ID
methodHookClassInfo.m1 = env->GetStaticMethodID(classEvaluateUtil, "m1", "()V");
methodHookClassInfo.m2 = env->GetStaticMethodID(classEvaluateUtil, "m2", "()V");
// 获取artMethod的大小
methodHookClassInfo.methodSize = reinterpret_cast<size_t>(methodHookClassInfo.m2) -
reinterpret_cast<size_t>(methodHookClassInfo.m1);
return JNI_VERSION_1_4;
}

View File

@@ -1,67 +0,0 @@
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();
}
}
}
}

View File

@@ -1,100 +0,0 @@
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;
/**
* hook方法
*
* @param src 要替换的方法对象
* @param dest 被替换的方法对象
*/
public MethodHook(Method src, Method dest) {
srcMethod = src;
hookMethod = dest;
srcMethod.setAccessible(true);
hookMethod.setAccessible(true);
}
/**
* 调用 native 层,完成替换
*/
public void hook() {
if (backupMethodPtr == 0) {
backupMethodPtr = hook_native(srcMethod, hookMethod);
}
}
/**
* 调用 native 层,完成方法还原
*/
public void restore() {
if (backupMethodPtr != 0) {
restore_native(srcMethod, backupMethodPtr);
backupMethodPtr = 0;
}
}
/**
* 调用原来class 对象中的方法
*
* @param receiver 接受对象
* @param args 方法列表
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
public void callOrigin(Object receiver, Object... args)
throws InvocationTargetException, IllegalAccessException {
if (backupMethodPtr != 0) {
restore();
srcMethod.invoke(receiver, args);
hook();
} else {
srcMethod.invoke(receiver, args);
}
}
/**
* 调用 native 方法完成 方法替换
*
* @param src 旧方法
* @param dest 新方法
* @return 就方法ID
*/
private static native long hook_native(Method src, Method dest);
/**
* 调用 native 方法完成 方法还原
*
* @param src
* @param methodPtr
* @return
*/
private static native Method restore_native(Method src, long methodPtr);
static {
// 加载本地方法 so
System.loadLibrary("method-hook-lib");
}
}