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的生命周期应该是对应响应的生命周期,如应用全局的生命周期,如单例等。

 

     

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: hook 是一种通过在程序运行期间动态地将自己的代码插入到其他程序中来实现某些功能的技术。要在 Java 代码中使用 hook,需要使用 Java反射功能来动态地修改类的方法。 下面是一个简单的例子,展示了如何使用 Java反射功能动态地插入代码: ``` import java.lang.reflect.Method; public class HookExample { public static void main(String[] args) throws Exception { // 获取要插入代码的目标方法 Method targetMethod = TargetClass.class.getMethod("targetMethod", int.class, String.class); // 使用 Java反射功能动态地修改方法 HookUtils.hook(targetMethod, new MethodReplacement() { @Override public Object replace(Object target, Object[] args) throws Throwable { // 在这里插入自己的代码 System.out.println("Hook successfully!"); return null; } }); // 调用目标方法 TargetClass target = new TargetClass(); target.targetMethod(1, "hello"); } } ``` 在这个例子中,我们使用了 Java反射功能来获取要插入代码的目标方法 `targetMethod`,并使用 `HookUtils.hook` 方法动态地修改这个方法。在 `replace` 方法中,我们可以插入自己的代码。最后,我们调用了目标方法 `targetMethod`,从而触发了我们插入的代码。 ### 回答2: 通过hook技术,在Java代码中插入自己的代码,可以借助于Java Agent机制来实现。Java Agent是Java虚拟机提供的一种机制,允许在虚拟机加载类之前或之后对类进行修改或增强。 具体实现步骤如下: 1. 创建一个代理类,用于对原始类进行修改或增强。代理类需要实现一个接口,这个接口中包含了原始类的所有方法。在代理类中,可以在方法执行前后插入自己的代码逻辑。 2. 创建一个Java Agent,并在其中使用Instrumentation API来做字节码转换。在Agent的premain方法中,使用Instrumentation对象的方法进行字节码转换。将原始类转换为代理类,然后在转换过程中,将自己的代码插入到要转换的方法中。 3. 在代理类中,可以在方法执行前后注入自己的代码。例如,在方法执行前输出一段日志,在方法执行后做一些额外的操作。 4. 将Agent打包成独立的jar文件,并在Java启动参数中增加启动Agent的参数。在启动Java程序时,使用-javaagent参数引入Agent。这样就可以在Java程序运行时自动加载Agent,并在加载类之前进行字节码转换。 通过上述步骤,就可以使用hook技术将自己的代码插入到Java代码中,实现代码的修改或增强。这种方式可以用于实现一些动态代理、AOP切面编程等功能。需要注意的是,使用hook技术需要对Java字节码有一定的了解,并且要小心不要对原始类的功能造成破坏或影响。 ### 回答3: 在Java中,可以通过使用Hook技术将自己的代码插入到已有的Java代码中。Hook是一种钩子函数,可以在程序运行时动态地修改代码逻辑。 要实现这个目标,可以使用Java反射机制来实现,反射可以在运行时获取类、方法和字段的信息,通过反射可以动态地调用类的方法。 首先,需要找到目标代码中适合插入的位置。可以在目标方法的开始或结束处插入代码。假设有一个目标方法public void targetMethod(),我们希望在其开始处插入代码。 然后,定义一个新的类,包含你想要插入的代码逻辑。这个类可以继承自java.lang.instrument.ClassFileTransformer接口,实现其中的transform方法。在transform方法中,可以获取传入的类和类文件字节码,然后将你的代码插入到其中。 接下来,在你的代码中使用Instrumentation的addTransformer方法注册刚刚创建的类,例如:instrumentation.addTransformer(new MyTransformer())。 最后,在目标Java代码的入口处调用Instrumentation的retransformClasses方法,重新转换目标类。例如:instrumentation.retransformClasses(TargetClass.class)。 通过上述步骤,你的代码就会被插入到目标Java代码中。你可以在MyTransformer类的transform方法中编写你自己的代码,这段代码会在目标方法执行之前被调用。 需要注意的是,使用Hook技术需要对Java的Instrumentation API有一定的了解,同时需要在运行时添加javaagent参数来指定你的Agent类。此外,需要注意插入代码的位置和插入逻辑的正确性,确保你的代码对目标方法不会产生负面影响。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值