Java: Hook技术[通俗易懂]
大家好,又见面了,我是你们的朋友全栈君。
一、什么是Hook
Hook翻译成中文就是勾子的意思,在java中它表示在事件到达终点前进行拦截或监控的一种行为。
二、Hook的实现
实现hook我们必须要知道java的反射和动态代理。
1、反射
反射是java的查看、检测、修改自身的一种行为。
在编译阶段,编译器将我们编写的java文件编译成.class文件。而在运行期,jvm又将.class文件通过类加载器ClassLoader加载一个类对应的Class对象到内存当中。通过修改Class对象,达到我们查看、检测、修改自身的行为。
Class clazz = Class.forName(“android.com.test.TestClass”),方式加载类的class文件。
生成实例的方法不一定通过new ,可通过下面的方法获取Class对象对应的实例
Constructor constructor = clazz.getConstructor();
TestClass o = (TestClass)constructor.newInstance();
当然,构造函数可能有多个,你应该通过获取他的所有构造函数。了解到他的构造函数之后再使用上面的方法,不然会报错
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors){
constructor.setAccessible(true); //可能有些构造函数你的权限不够,让其可能反射
Class[] params = constructor.getParameterTypes(); //某个构造函数的参
Log.i("tag",String.valueOf(params.length)); //看看构造函数参数的长度
for (Class p : params) {
Log.i("tag","参数类型的名字"+p.getName()); //看看这个构造函数是什么类型
}
}
}
同理,通过class类对象,可以获取对象的方法。动态代理中需要在方法拦截。
Methods method[] = clazz.getDeclaredMethods();
获取对象的域,
Field[] fields = clazz.getDeclaredFields()
获取对象的注解,我们ButterKnife就是运用到了这个。
Annotation[] annotations = hookUserClass.getDeclaredAnnotations();
for (Annotation annotation : annotations){
Log.i("tag","注解类型class文件的名字"+annotation.annotationType().getName());
}
2、动态代理
动态代理相对静态代理而言,动态代理是动态的,通过反射对被代理对象的方法,代理成代理对象对应的方法。动态代理也运用到了反射的知识。
final Leader leader = new Leader(new Worker());
IPerson IpensonImp = (IPerson) Proxy.newProxyInstance(Leader.class.getClassLoader(),new Class[]{IPerson.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(leader,args);
return proxy;
}
});
Field[] fields = clazz.getClass().getDeclaredFields();
for (Field field : fields){
field.setAccessible(true);
if (field.getName().equals("iPerson")){
try {
field.set(clazz,IpensonImp);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
hookUser.doWhat();
class TestClass{
IPerson iPerson ;
public HookUser(){
iPerson = new Worker();
}
public void doWhat(){
iPerson.say("我是工人");
}
}
public class Leader implements IPerson{
IPerson iPerson;
public Leader(IPerson iPerson) {
this.iPerson = iPerson;
}
@Override
public void say(String what) {
PrintUtils.print("我领导,我叫我去说");
iPerson.say(what);
PrintUtils.print("事情干完了");
}
@Override
public void walk(String where) {
PrintUtils.print("我领导,我叫我手走过去");
iPerson.walk(where);
PrintUtils.print("事情干完了");
}
}
public class Worker implements IPerson {
@Override
public void say(String what) {
PrintUtils.print(what);
}
@Override
public void walk(String where) {
PrintUtils.print(where);
}
}
三、Hook的条件
如上面代码,运用反射和动态代理,可实现将TestClass中 IPerson iPerson 指向的Worker对象,动态修改为Leader对象,实现了hook的过程。那么实现hook需要什么条件呢?
1、代理对象和被代理对象需要实现同样的接口,Leader和Worker都是iPerson的实现类。
2、被代理对象必须在使用的时候,使用接口作为类型。否则不能被动态代理。 field.set(clazz,IpensonImp)会报错,类似设置错误。
3、此案例中hook的对象是TestClass。一次修改后被系统回收后,hook就失效了。如果要长期生效,那么hook的生命周期应该是对应响应的生命周期,如应用全局的生命周期,如单例等。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/141464.html原文链接:https://javaforall.cn
相关文章
- Java项目毕业设计:基于springboot+vue的电影视频网站系统「建议收藏」
- Java删除文件(delete file in java)[通俗易懂]
- java 取余和取整_Java取整、取余
- java简单的除法运算_Java除法运算的陷阱[通俗易懂]
- java冒泡排序概练_Java的冒泡排序[通俗易懂]
- java标识符与关键字_4、Java标识符和关键字
- java启动器_JAVA基础:Java 启动器如何查找类
- java编程软件下载_Ee Java(Java编程软件) V1.1.0 官方版
- java图书馆新地址_值得你关注的16个顶级 Java 开源项目!小白必看
- java编写一个学生类和教师类,Java创建一个学生类[通俗易懂]
- java中文乱码_Java中文乱码问题的解决方案[通俗易懂]
- java代码大全及详解_Java练级攻略[通俗易懂]
- java 自定义的类加载器_Java如何自定义类加载器[通俗易懂]
- java softreference_Java引用总结–StrongReference、SoftReference、WeakReference、PhantomReference…[通俗易懂]
- Java字符串转集合_java集合转数组
- java 事务嵌套_Java事务以及嵌套事务[通俗易懂]
- Java运行在Linux系统上免费下载(linux java下载)
- 使用Java去连接MySQL数据库(java jdbc mysql)
- Linux上善用Java:实现智能开发(linux 运行java)
- Redis面试中Java相关技术面试题汇总(redis面试题java)
- Oracle数据库中运行Java程序的简易指南(oracle中写java)
- Java消息处理实践突破性技术Redis(redis消息 java)