Java: Hook技术[通俗易懂]

Java: Hook技术[通俗易懂]一、什么是Hook  Hook翻译成中文就是勾子的意思,在java中它表示在事件到达终点前进行拦截或监控的一种行为。 二、Hook的实现实现hook我们必须要知道java的反射和动态代理。 1、反射  反射是java的查看、检测、修改自身的一种行为。  在编译阶段,编译器将我们编写的java文件编译成.class文件。而在运行期,jvm又将.class文件通过…

大家好,又见面了,我是你们的朋友全栈君。

一、什么是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.net/141464.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月9日 下午1:40
下一篇 2022年5月9日 下午2:20


相关推荐

  • No pyvenv.cfg file问题解决方案

    No pyvenv.cfg file问题解决方案nopyvenv cfgfile 问题解决方案百度了一下发现百度也不是万能的解决方法 file 里面的 setting 点击小齿轮再点击 Add 在里面添加路径就可以了路径就是在之前的文件位置附近找总会找到的我就是无脑随便点点找到了找文件错误的话会提醒你但是如果你完成上述步骤的话 你会发现你下载的第三方库都没了 有个好办法就是用 Andconda 的解释器 如何使用呢 就是修改 baseInterpre 就行了之后就可以运行了总体来看 这篇博客写的挺烂的 有问题可以告诉

    2026年3月19日
    2
  • Midjourney怎么付费及收费标准(Midjourney使用教程)

    Midjourney怎么付费及收费标准(Midjourney使用教程)

    2026年3月15日
    3
  • python信号处理库_python开源协议

    python信号处理库_python开源协议本发明涉及的是一种在用电采集终端上实现标准MBUS协议接口用来采集水表、热量表、气表数据的方法,具体涉及一种基于MBUS标准协议接口模块采集水、热、气表的方法,属于用电信息采集领域。背景技术:我国正处于自动化楼宇建设事业蓬勃发展的时期,远程抄表系统作为其中重要的一环,正朝着自动化及智能化方向发展;MBUS(仪表总线)总线作为一种通讯方式,以其高性价比,在水热测量仪表中得到了广泛的应用,大大推动了远…

    2022年10月15日
    3
  • 一些sql

    1、说明:创建数据库CREATE DATABASE database-name 2、说明:删除数据库drop database dbname3、说明:

    2021年12月25日
    45
  • AI Agent开发与应用:基于大模型的智能体构建 PDF电子版

    AI Agent开发与应用:基于大模型的智能体构建 PDF电子版

    2026年3月16日
    3
  • padStart()与padEnd()「建议收藏」

    padStart()与padEnd()「建议收藏」padStart()padStart()方法用另一个字符串填充当前字符串(如果需要的话,会重复多次),以便产生的字符串达到给定的长度。从当前字符串的左侧开始填充。语法str.padStart(targetLength[,padString])参数:targetLength:当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。padString:可选填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截

    2025年9月5日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号