/Hooker-1

XposedHook模板

Primary LanguageJava

Xposed模块配置 Project ┗ app ┗ lib //手动创建目录添加文件 ┗ XposedBridgeApi-82.jar //右键 Add as library 添加到库

Project ┗ app ┗ build.gradle dependencies{ //在这里插入代码 //注意 IDA自动填写的要去掉 implementation files('lib\XposedBridgeApi-82.jar') compileOnly 'de.robv.android.xposed:api:82' //设置只编译不打包 }

Project ┗ app ┗ src ┗ AndroidManifest.xml <application android:xxx = "" .......... >

     <meta-data android:name="xposedmodule" android:value="true" /> 			//让Xposed识别为模块
     <meta-data android:name="xposedminversion" android:value="82" /> 		//最小支持Api版本
     <meta-data android:name="xposeddescription" android:value="描述" />		//模块描述
	 
	</application>

Project ┗ app ┗ src ┗ main //手动创建目录添加文件 ┗ assets ┗ xposed_init //里面写xposed启动函数入口

动态加载劫持 ┗ 动态加载Dex ┗ XposedHelpers.findAndHookMethod - > Application.class, "attach", Context.class ┗ 动态加载Class ┗ XposedBridge.hookAllMethods -> ClassLoader.class, "loadClass"

//////第二节////// 自学推荐 http://c.biancheng.net/java/ Java基础教程(从入门到精通) https://www.cnblogs.com/gordon0918/p/6732100.html 基本用法 https://skyhand.blog.csdn.net/article/details/52574650 插件开发之二: Xposed一些知识 https://skyhand.blog.csdn.net/article/details/52575900 插件开发之三: 编写广告去除插件 https://www.jianshu.com/p/616be7deec33 Xposed系列之微信屏蔽拍一拍(三)

ClassLoader (类加载器) 类加载器可以有很多个 也就是有很多个爸爸 她们的孩子可能名字相同 但是做着不同的事 所以要找对孩子才行

(我是第一个加载器加载的) ClassLoader ┗ Main ┗ OKhttp3 ┗ MMKV ┗ MMKV$Thread1 ┗ MMKV$Thread2 ┗ Account ┗ 很多很多类

(我是第二个加载器加载的) ClassLoader
┗ MMKV //如果被动态加载 ClassLoader = MMKV.getClassLoader() ┗ MMKV$Thread1 //Clazz = findClass(MMKV.getClassName() + "$Thread1", ClassLoader) ┗ MMKV$Thread2 //findAndHookMethod(Clazz, "Method", Object... , CallBack) ┗ Account

动态加载劫持 ┗ 动态加载Dex XposedHelpers.findAndHookMethod - > Application.class, "attach", Context.class beforeHookedMethod(){ context = (Context)param.args[0]; ClassLoader classLoader = context.getClassLoader(); }

┗ 动态加载Class XposedBridge.hookAllMethods -> ClassLoader.class, "loadClass" afterHookedMethod(){ if (param.hasThrowable()) return; if (param.args.length != 1 ) return; Class clszz = (Class) param.getResult(); if (clszz.getName.equals("Class")){ XposedHelpers.findAndHookMethod(clszz, "Method") } }

//堆栈调用(StackTraceElement/堆栈跟踪元素) -> PrintStack package com.god

class Test { OnCreate(){ if (UserInfo != null){ isVip() } }

Stack(){
print(Stack)
}

isVip(){
print("我被执行了")
Stack()
}

main(){ //首先被执行
OnCreate()
}

}

//main 首先被执行 打印结果是: 我被执行了 at com.god.Test.isVip(Test.java:?) at com.god.Test.OnCreate(Test.java:?) at com.god.Test.main(Test.java:?) //这样的好处是方便分析是谁调用 更好的 去分析整个执行流程

关于 XposedBridge 基础功能 //注意!!! Method 被 abstract || native 修饰不能HOOK

//这是最基本Hook public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) ┗ 什么是Hook //hookMethod 的第二个参数是回调 但她有两种类型 这里先简单介绍 后面会详细说 ┗ a.XC_MethodHook 执行回调 beforeHookedMethod(MethodHookParam param) 调用前回调 和 afterHookedMethod(MethodHookParam param) 调用后回调 //原本执行流程 调用函数 -> A函数 //被Hook后 调用函数 -> beforeHookedMethod(MethodHookParam param) -> A函数 -> afterHookedMethod(MethodHookParam param) //如果 beforeHookedMethod(MethodHookParam param) 中调用 param.setResult(); 不会继续执行 !≠-> A函数 -> afterHookedMethod(MethodHookParam param)

┗ b.XC_MethodReplacement	  替换方法 replaceHookedMethod
//原本执行流程
调用函数 -> A函数
//被Hook后
调用函数 -> replaceHookedMethod(MethodHookParam param) !≠-> A函数  不会继续调用 A函数

//给大家看个两个 XposedApi 提供的源代码 大家看看就好 ┗ Hook全部 相同名称 的方法 返回 XC_MethodHook.Unhook 的集合 public static Set<XC_MethodHook.Unhook> hookAllMethods(Class<?> hookClass, String methodName, XC_MethodHook callback) { Set<XC_MethodHook.Unhook> unhooks = new HashSet<XC_MethodHook.Unhook>(); for (Member method : hookClass.getDeclaredMethods()) if (method.getName().equals(methodName)) unhooks.add(hookMethod(method, callback)); return unhooks; }

┗ Hook全部 构造函数 的方法 返回 XC_MethodHook.Unhook 的集合 public static Set<XC_MethodHook.Unhook> hookAllConstructors(Class<?> hookClass, XC_MethodHook callback) { Set<XC_MethodHook.Unhook> unhooks = new HashSet<XC_MethodHook.Unhook>(); for (Member constructor : hookClass.getDeclaredConstructors()) unhooks.add(hookMethod(constructor, callback)); return unhooks; }

//其实 'XposedBridge' 和 'XposedHelpers' 提供的Hook会都调用 hookMethod 这个函数来实现

┗ 关于 hookMethod 的返回 XC_MethodHook.Unhook 类型 //这个看看就好 主要是 用于 卸载Hook (unhook()) 获取Hook当前方法 (getHookedMethod()) 获取Hook回调XC_MethodHook (getCallback()) public class Unhook implements IXUnhook<XC_MethodHook> { private final Member hookMethod;

	/*package*/ Unhook(Member hookMethod) {
		this.hookMethod = hookMethod;
	}

	/**
	 * Returns the method/constructor that has been hooked.
	 */
	public Member getHookedMethod() {
		return hookMethod;
	}

	@Override
	public XC_MethodHook getCallback() {
		return XC_MethodHook.this;
	}

	@SuppressWarnings("deprecation")
	@Override
	public void unhook() {
		XposedBridge.unhookMethod(hookMethod, XC_MethodHook.this);
	}

}

┗ 关于 XC_MethodHook 类型

┗ 普通Hook方法
class MethodHook extends XC_MethodHook {
	
	@Override
	protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
		
		Object thisClassObject = param.thisObject; //当前类的hook方法所在类的对象
		Class<?> thisClass = thisClassObject.getClass(); //当前类的hook方法所在类
		
		Object[] args = param.args; //调用函数的全部参数
		
		//假设参数一是 Xcc 个类 
		//你需 获取这个类里面的 public String Key 数据
		//并且 调用该类里面的 boolean Pass(String Key) 函数
		//你应该这么做
		
		//所有类都属于 Object
		Class<?> c_Xcc = args[0].getClass();
		
		//获取类里面的 字段
		//clszz.getDeclaredField("FieldName"); 可以访问查找 全部字段 类型
		//clszz.getDeclaredFields(); 获取全部的数组
		
		//clszz.getField("FieldName"); 只能访问查找 没保护 的 public 修饰的之类的字段
		//clszz.getFields(); 获取全部 没保护 的 public 修饰的之类的字段 的数组
		
		//简单点区分 有 Declared 获取范围更广(即可以访问未公开字段)
		//加 s 是获取她的全部 即数组
		//说了那么多 肯定也是 getDeclaredField 这个函数好用 但是可能执行效率低下
		Field Key = c_Xcc.getDeclaredField("Key");
		
		//如果有保护会导致访问出错 抛出异常 所有保险起见都 设置为可访问
		Key.setAccessible(true);
		
		//所有类都属于 Object
		//public String Key 的对象是 o_Key(Object)
		//o_Key.getClass() = String 这是必然的
		Object o_Key = Key.get(c_Xcc);
		
		//获取类里面的 方法
		//Clazz.getDeclaredMethod("MethodName");
		//Clazz.getDeclaredMethods();
		
		//Clazz.getMethod("MethodName");
		//Clazz.getMethods();
		//这些都和上面同理
		
		//注意!!!
		//public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
		//获取方法时 不仅名称要对应 参数类型也要对应
		//我们这个方法第一个参数是 String 类型 就填 String.class
		//什么类就填 什么 class 有几个参数就得填几个 必须对应类型
		//没有的 类型 就用 XposedHelpers.findClass 函数 去获取填入
		
		Method Pass = c_Xcc.getDeclaredMethod("Pass", String.class);
		//如果有保护会导致访问出错 抛出异常 所有保险起见都 设置为可访问
		Pass.setAccessible(true);
		
		//public native Object invoke(Object obj, Object... args)
		//第一个填类的 Object 后面就是参数
		//她的返回类型是 boolean 就强转一下吧
		boolean issucceed = (boolean)Pass.invoke(c_Xcc, (String)o_Key);
		//这样就完成一个调用了
		if (!issucceed){
			//修改返回值
			//注意!!!
			//修改返回值后 执行完 当前函数后 不会执行 原函数
			param.setResult(true);
		}
		
		
	}

	@Override
	protected void afterHookedMethod(MethodHookParam param) throws Throwable {
		Object Result = param.getResult();
		//a.获取返回值 做想做的事
		//b.修改返回值
		//c.执行完后可以去调用某些函数(一般等执行完是为了初始化数据在调用)和上面一样的方法
		if (Result.toString.contains("AD广告Uir:")){
			param.setResult("没有广告再见");
		}
		
	}
	
}

┗ 重写/替换方法
class MethodReplacement extends XC_MethodReplacement {
	
	@Override
	protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
		Object Result = null;//这是一个空的返回值 null
		if (param.args[0].toString().equals("送钱了")){
			//我现在反悔了 想调用一下原函数
			
			//原封不动的调用
			Result = XposedBridge.invokeOriginalMethod(param.method, param.thisObject, param.args);
			//或 自己改参数的调用
			//XposedBridge.invokeOriginalMethod(param.method, param.thisObject, new Object[]{"送钱了",10000})
			
			//你都送钱了那我就不 Hook你了
			//卸载Hook
			XposedBridge.unhookMethod(param.method,this);
			//以上说的两个方法在 Hook 回调中均可使用不限于 replaceHookedMethod beforeHookedMethod afterHookedMethod
		}
		
	
		//注意 返回Object 一定要和 原函数类型相符 否则 程序容易出错
		return Result;
	}
	
}

┗ 构造概念 Constructor 和 Method 的区别
//反编译中经常看到的 <init> 函数就是构造函数 Constructor 
//注意!!!
//a.在选择Hook时要使用 hookConstructor 而且不是 hookMethod
//b.一般用Hook用 afterHookedMethod 的回调进行操作 这样可以避免一些数据未被初始化导致调用崩溃
class a {
	final int a;
	final String b;
	final long c;
	a(int A,String B){ //构造函数 她可以被重写 ,当被 new a(1,"b") 会被执行
		a = A;
		b = B;
	}
	
	a(int A,String B,long C){ //构造函数的 重写 ,当被 new a(2,"bb",2L) 会被执行
		a = A;
		b = B;
		c = C;
	}
	
}

关于 XposedHelpers 辅助功能 //她主要封装了很多查找功能 方便使用 大家会了基础在会这个没毛病吧

//findMethod 的底层实现是 clazz.getDeclaredMethod(methodName, parameterTypes)

Object... 代表可以多个参数 但在这些函数中最后一个会被当作 Callback(Hook回调/函数回调) findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) clazz = findClass(className, classLoader)//中间加了个辅助 ↓ findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback)

//

findAndHookConstructor(String className, ClassLoader classLoader, Object... parameterTypesAndCallback) clazz = findClass(className, classLoader)//中间加了个辅助 ↓ findAndHookConstructor(Class<?> clazz, Object... parameterTypesAndCallback) //以上最终实现 Hook XposedBridge.hookMethod()

clazz.newInstance() //Java9之后推荐使用 clazz.getDeclaredConstructor().newInstance()