Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.example.coremod;
- import org.objectweb.asm.Opcodes;
- import org.objectweb.asm.Type;
- import org.objectweb.asm.tree.*;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- public class ASMHelper {
- // ====================================================
- // Reflection Utilities
- // ====================================================
- /**
- * Calls a method reflectively (static or instance).
- */
- public static Object callMethod(Object target, String methodName, Class<?>[] paramTypes, Object... args) throws Exception {
- Class<?> clazz = (target instanceof Class) ? (Class<?>) target : target.getClass();
- Method method = clazz.getDeclaredMethod(methodName, paramTypes);
- method.setAccessible(true);
- return method.invoke((target instanceof Class) ? null : target, args);
- }
- /**
- * Gets a field value reflectively, bypassing visibility.
- */
- public static Object getField(Object target, String fieldName) throws Exception {
- Field field = target.getClass().getDeclaredField(fieldName);
- field.setAccessible(true);
- return field.get(target);
- }
- /**
- * Sets a field value reflectively, bypassing visibility and final modifiers.
- */
- public static void setField(Object target, String fieldName, Object value) throws Exception {
- Field field = target.getClass().getDeclaredField(fieldName);
- field.setAccessible(true);
- // Remove final modifier if present
- Field modifiersField = Field.class.getDeclaredField("modifiers");
- modifiersField.setAccessible(true);
- modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- field.set(target, value);
- }
- /**
- * Gets modifiers of a field.
- */
- public static int getModifiers(Class<?> clazz, String fieldName) throws Exception {
- Field field = clazz.getDeclaredField(fieldName);
- return field.getModifiers();
- }
- // ====================================================
- // Descriptor Utilities
- // ====================================================
- /**
- * Generates a JVM method descriptor from return type and parameter types.
- */
- public static String getMethodDescriptor(Class<?> returnType, Class<?>... paramTypes) {
- Type retType = Type.getType(returnType);
- Type[] paramAsmTypes = new Type[paramTypes.length];
- for (int i = 0; i < paramTypes.length; i++) {
- paramAsmTypes[i] = Type.getType(paramTypes[i]);
- }
- return Type.getMethodDescriptor(retType, paramAsmTypes);
- }
- /**
- * Generates a JVM method descriptor from a reflection Method.
- */
- public static String getMethodDescriptor(Method method) {
- return Type.getMethodDescriptor(method);
- }
- /**
- * Generates a JVM field descriptor from a Class.
- */
- public static String getFieldDescriptor(Class<?> type) {
- return Type.getDescriptor(type);
- }
- /**
- * Generates a JVM field descriptor from a reflection Field.
- */
- public static String getFieldDescriptor(Field field) {
- return Type.getDescriptor(field.getType());
- }
- // ====================================================
- // ASM Patch Utilities
- // ====================================================
- /**
- * Injection points for injectCallback.
- */
- public enum InjectionPoint {
- START, END, BEFORE_CALL, AFTER_CALL
- }
- // --------------------------
- // redirectMethodCalls overload #1 (Class owners)
- // --------------------------
- public static void redirectMethodCalls(ClassNode classNode,
- Class<?> originalOwner, String originalName,
- Class<?> returnType, Class<?>[] paramTypes,
- Class<?> newOwner, String newName) {
- String descriptor = getMethodDescriptor(returnType, paramTypes);
- String originalOwnerName = Type.getInternalName(originalOwner);
- String newOwnerName = Type.getInternalName(newOwner);
- redirectMethodCalls(classNode, originalOwnerName, originalName, descriptor, newOwnerName, newName);
- }
- // --------------------------
- // redirectMethodCalls overload #2 (String owners)
- // --------------------------
- public static void redirectMethodCalls(ClassNode classNode,
- String originalOwner, String originalName, String descriptor,
- String newOwner, String newName) {
- for (MethodNode method : classNode.methods) {
- for (AbstractInsnNode insn : method.instructions.toArray()) {
- if (insn instanceof MethodInsnNode) {
- MethodInsnNode mInsn = (MethodInsnNode) insn;
- if (mInsn.owner.equals(originalOwner)
- && mInsn.name.equals(originalName)
- && mInsn.desc.equals(descriptor)) {
- mInsn.owner = newOwner;
- mInsn.name = newName;
- // descriptor stays the same
- }
- }
- }
- }
- }
- // --------------------------
- // injectCallback overload #1 (Class owner)
- // --------------------------
- public static void injectCallback(MethodNode targetMethod, InjectionPoint point,
- Class<?> callbackOwner, String callbackName,
- Class<?> callbackReturnType, Class<?>... callbackParamTypes) {
- String callbackOwnerName = Type.getInternalName(callbackOwner);
- String callbackDesc = getMethodDescriptor(callbackReturnType, callbackParamTypes);
- injectCallback(targetMethod, point, callbackOwnerName, callbackName, callbackDesc);
- }
- // --------------------------
- // injectCallback overload #2 (String owner)
- // --------------------------
- public static void injectCallback(MethodNode targetMethod, InjectionPoint point,
- String callbackOwner, String callbackName, String callbackDescriptor) {
- InsnList callbackInsn = new InsnList();
- callbackInsn.add(new MethodInsnNode(Opcodes.INVOKESTATIC, callbackOwner, callbackName, callbackDescriptor, false));
- switch (point) {
- case START:
- targetMethod.instructions.insert(callbackInsn);
- break;
- case END:
- for (AbstractInsnNode insn : targetMethod.instructions.toArray()) {
- int opcode = insn.getOpcode();
- if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
- targetMethod.instructions.insertBefore(insn, callbackInsn);
- }
- }
- break;
- case BEFORE_CALL:
- case AFTER_CALL:
- for (AbstractInsnNode insn : targetMethod.instructions.toArray()) {
- if (insn instanceof MethodInsnNode) {
- if (point == InjectionPoint.BEFORE_CALL) {
- targetMethod.instructions.insertBefore(insn, callbackInsn);
- } else {
- targetMethod.instructions.insert(insn, callbackInsn);
- }
- }
- }
- break;
- }
- }
- /**
- * Prints all instructions of a method to System.out for debugging.
- */
- public static void printInstructions(MethodNode method) {
- System.out.println("Instructions for method: " + method.name + method.desc);
- for (AbstractInsnNode insn : method.instructions.toArray()) {
- System.out.println(insn.getClass().getSimpleName() + ": " + insn);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment