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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vi 编辑或者 ssh 登陆时出现Warning: Failed to set locale category LC_TIME to en_CN 问题

    vi 编辑或者 ssh 登陆时出现Warning: Failed to set locale category LC_TIME to en_CN 问题

    2021年5月13日
    186
  • linux监控系统catic,网络设备监控-Catic添加H3C的监控图解[通俗易懂]

    linux监控系统catic,网络设备监控-Catic添加H3C的监控图解[通俗易懂]网络设备监控-Catic添加H3C的监控图解作者:尹正杰版权声明:原创作品,谢绝转载!否则将追究法律责任。首先,我要声明满足2个条件才能作本篇笔记的操作:第一:你得有台cacti服务器,第二:你得有台交换机,这台交换机需要配置团体名并且可以和你的cacti服务器互通。以上两点我已经在之前的笔记分享过,这里我就不啰嗦啦,直接上图。对了,如果你懒得部署Cacti的话,也可以直接用网上的别人做好的iso…

    2025年7月27日
    4
  • android之通过Button的监听器往adapter中添加数据时出错

    本来源代码如下: List model; //自定义的一个List数据,存储的是自定义的类 LunchListAdapter adapter;//自定义的一个ListView的适配器 ……//省略class onSavaLis implements OnClickListener{ //Button s

    2022年3月10日
    42
  • keil5破解失败【经验分享】

    keil5破解失败【经验分享】有些小伙伴在输入license时会出现这种情况解决办法:使用管理员方式运行keil5

    2022年5月4日
    823
  • 5g端到端网络切片技术_5G网络切片的特征

    5g端到端网络切片技术_5G网络切片的特征1、网络切片的一些概念网络切片(Slice):基于客户化需求,可以被设计、部署、维护的逻辑网络,旨在满足特定的客户、业务、商业场景的业务特点及商业模式。网络切片实例(E2ESliceInstance-ESI):网络切片实例(Instance)是一个临时逻辑网络,跨多个技术域,包含:(1)组网络:”功能”(Function)即虚拟网元(终端、接入网、回传网、核心网、业务网络)及网管系统对应的资源;(2)存储、运算;(3)连接关系。2、网络切片原因:未来业务需求差异

    2022年9月27日
    4
  • SpringCloud原理–FeignClient

    SpringCloud原理–FeignClient本文介绍SpringCloud的FeignClient的原理。Feign服务调用的工作原理可以总结为以下几个步骤首先通过@EnableFeignCleints注解开启FeignCleint。根据Feign的规则实现接口,添加@FeignCleint注解。程序启动后,会扫描所有有@FeignCleint的类,并将这些信息注入到ioc容器中。注入时从FeignClientFactoryBean.class获取FeignClient当接口的方法被调用时,通过jdk的代理,来生

    2025年8月29日
    4

发表回复

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

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