Java 反射之Hook 实例

Hook 机制主要是通过反射机制,在运行时改变某个对象的属性或者行为(很抽象!!!),
所以必须以实例作为学习的切入点。
或者可以参考:其实用高大上的Hook技术动态注入代码很简单,一看就会! - JavaShuo

这里仅做实例记录

1. 普通场景

直接上代码, 很容易看懂
(1) Weapon 类

package com.example.javalearnproject.reflectbasictest.hook;

public class Weapon {
    protected int damage = 10;

    public void attack(){
        System.out.println(String.format("对目标形成 %d 点伤害",damage));
    }
}


(2) Hero 类

package com.example.javalearnproject.reflectbasictest.hook;

public class Hero {
    private Weapon weaponMain;

    public Hero(Weapon weaponMain) {
        this.weaponMain = weaponMain;
    }

    public void attack(){
        weaponMain.attack();
    }
}


(3) Game 类

package com.example.javalearnproject.reflectbasictest.hook;

public class Game {
    public static void main(String[] args){
        Hero hero = new Hero(new Weapon());
        hero.attack();
    }
}

输出:

对目标形成 10 点伤害

2. Hook 场景(改变属性值)

(1) Hero 保存不变
(2) WeaponHook 继承Weapon, 并且在attack方法中设置回调

package com.example.javalearnproject.reflectbasictest.hook.dohook;

//对于上面这段程序,游戏对咱们隐藏了Weapon的伤害值,但如今咱们想要在每次攻击的时候知道这个伤害值是多少。
//下面看看使用Hook机制如何来实现。

import com.example.javalearnproject.reflectbasictest.hook.Weapon;

//首先咱们经过观察,发现切入点就是weaponMain,咱们要对它下手。
//建立一个Weapon的复制品WeaponHook,咱们须要用本身的人WeaponHook打入内部。
//WeaponHook一切看起来都和Weapon那么类似,可是咱们给它留了一个后门,使得咱们能够进行监控。
public class WeaponHook extends Weapon {
    private OnUseWeaponAttackListener onUseWeaponAttackListener;

    @Override
    public void attack(){
        super.attack();
        System.out.println("WeaponHook has called Weapon.attach");
        if (onUseWeaponAttackListener != null){
            onUseWeaponAttackListener.onUseWeaponAttack(damage);
        }
    }

    public void setOnUseWeaponAttackListener(OnUseWeaponAttackListener onUseWeaponAttackListener) {
        this.onUseWeaponAttackListener = onUseWeaponAttackListener;
    }

    //这就是咱们的后门
    public static interface OnUseWeaponAttackListener {
        int onUseWeaponAttack(int damage);
    }
}

(3) GameHook 反射注入 WeaponHook对象

package com.example.javalearnproject.reflectbasictest.hook.dohook;

import com.example.javalearnproject.reflectbasictest.hook.Hero;
import com.example.javalearnproject.reflectbasictest.hook.Weapon;

import java.lang.reflect.Field;

public class GameHook {
    public static void main(String[] args){
        Hero hero = new Hero(new Weapon());
        try {
            //Field weapon = ReflectUtils.getVariable(hero.getClass(), "weaponMain");
            Class<?> heroClass = hero.getClass();
            //Field weapon = heroClass.getField("weaponMain");// 不包含私有属性
            Field weapon = heroClass.getDeclaredField("weaponMain");// 包含私有属性
            weapon.setAccessible(true);
            Weapon weaponHook = new WeaponHook();
            ((WeaponHook) weaponHook).setOnUseWeaponAttackListener(damage -> {
                //经过后门进行操做,这其实就是咱们注入的代码
                System.out.println("damage = " + damage);
                return damage;
            });
            weapon.set(hero, weaponHook); //偷天换日  >>> 关键操作,替换掉原来的成员变量  (属性.set(对象,新的成员变量的对象))
            hero.attack(); //最终调用的是 weaponHook
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

此时输出:

对目标形成 10 点伤害
WeaponHook has called Weapon.attach
damage = 10

3. 防止Hook入侵

(1) HeroPro 增加hashcode判断

package com.example.javalearnproject.reflectbasictest.hook.hookprotect;

import com.example.javalearnproject.reflectbasictest.hook.Weapon;

public class HeroPro {
    private Weapon weaponMain;
    private final int weaponMainId;

    public HeroPro(Weapon weaponMain) {
        this.weaponMain = weaponMain;
        weaponMainId = this.weaponMain.hashCode();//记录原始Weapon对象的Id,hashCode对于每一个对象而言都是惟一的。
    }

    public void attack() {
        if (this.weaponMain.hashCode() != weaponMainId) { //关键位置检查是否遭到替换
            throw new IllegalAccessError(String.format("警告!遭到入侵!入侵者身份:%d", this.weaponMain.hashCode()));
        }
        weaponMain.attack();
    }
}


(2) GamePro 确认是否还可以hook 入侵

package com.example.javalearnproject.reflectbasictest.hook.hookprotect;

import com.example.javalearnproject.reflectbasictest.hook.Weapon;
import com.example.javalearnproject.reflectbasictest.hook.dohook.WeaponHook;

import java.lang.reflect.Field;

public class GamePro {
    public static void main(String[] args){
        HeroPro hero = new HeroPro(new Weapon());
        try {
            //Field weapon = ReflectUtils.getVariable(hero.getClass(), "weaponMain");
            Class<?> heroClass = hero.getClass();
            //Field weapon = heroClass.getField("weaponMain");// 不包含私有属性
            Field weapon = heroClass.getDeclaredField("weaponMain");// 包含私有属性
            weapon.setAccessible(true);
            Weapon weaponHook = new WeaponHook();
            ((WeaponHook) weaponHook).setOnUseWeaponAttackListener(damage -> {
                //经过后门进行操做,这其实就是咱们注入的代码
                System.out.println("damage = " + damage);
                return damage;
            });
            weapon.set(hero, weaponHook); //偷天换日  >>> 关键操作,替换掉原来的成员变量  (属性.set(对象,新的成员变量的对象))
            hero.attack(); //最终调用的是 weaponHook
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

(3) WeaponHook保持不变

输出(Exception):

Exception in thread "main" java.lang.IllegalAccessError: 警告!遭到入侵!入侵者身份:1060830840
    at com.example.javalearnproject.reflectbasictest.hook.hookprotect.HeroPro.attack(HeroPro.java:16)
    at com.example.javalearnproject.reflectbasictest.hook.hookprotect.GamePro.main(GamePro.java:24)

– End –

本文转自 https://www.jianshu.com/p/a69983752f29,如有侵权,请联系删除。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值