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,如有侵权,请联系删除。