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


相关推荐

  • 电脑开机显示“DISK Boot Failure,Insert System Disk And Press Enter”

    电脑开机显示“DISK Boot Failure,Insert System Disk And Press Enter” 电脑开机自检时无法通过,并在界面出现“DISKBootFailure,InsertSystemDiskAndPressEnter”的错误提示。这样的问题该如何解决?今天小编教大家如何排除故障。 造成电脑开机,屏幕上出现“DISKBootFailure,InsertSystemDiskAndPressEnter”故障的原因有: (1)由于硬盘,光驱连在同一条数据线上,但…

    2022年7月13日
    56
  • linux下解压zip文件命令

    linux下解压zip文件命令1、把/home目录下面的data目录压缩为data.zipzip-rdata.zipdata#压缩data目录2、把/home目录下面的data.zip解压到databak目录里面unzipdata.zip-ddatabak3、把/home目录下面的a文件夹和3.txt压缩成为a123.zipzip-ra123.zipa3.txt4、把/home目录下面的t.z…

    2022年6月7日
    67
  • java开发是什么_java开发到底是做什么的

    java开发是什么_java开发到底是做什么的1java开发到底是做什么的在互联网迅猛发展的时代,而我们如果对互联网一无所知,那就相当于文盲。所以很多人都想去了解它,去学习他。而作为互联网的产物——java,是一门非常不错的技术,学精通之后,你的未来不会再担心就业。那么下面小编给大家说说java开发到底是做什么的,希望能对你有些帮助。桌面级应用:尤其是需要跨平台的桌面级应用程序。桌面级应用:简单的说就是主要功能都在我们本机上运行的程序,比如w…

    2022年7月9日
    17
  • SSH框架总结(框架分析+环境搭建+实例源代码下载)

    SSH框架总结(框架分析+环境搭建+实例源代码下载)

    2021年11月14日
    38
  • awk 字符串替换 gsub

    awk 字符串替换 gsubgsub(r,s)在整个$0中用s替代rgsub(r,s,t)在整个t中用s替代rawk-F”,”‘{str=gsub(/\t*|*$/,””,$3);ret=$1″,”$2″,”$3″,”NR;printret}’去除第三个字段的空格与制表符awk-F”\t”‘{if($3==”吉林”){gsub($3,”吉林省”,$3);pr

    2022年7月15日
    15
  • c++实现strstr函数_C语言字符串数组

    c++实现strstr函数_C语言字符串数组自己实现C语言中的strstr函数,采用字符一个一个进行匹配,如果不等,则从下一个位置进行匹配。/*strstr实现*/char*mystrstr(constchar*dest,constchar*src){char*tdest=dest;char*tsrc=src;while(*tdest){char*flag=tdest;//设置标志位,方便回滚。while…

    2022年10月13日
    5

发表回复

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

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