private void hookSendMessage(ClassNode cn) { Pattern p = new PatternBuilder() .add( new InstructionElement(INVOKESTATIC), new AnyElement(), new LdcElement(new LdcInsnNode("Chat")), new InstructionElement(INVOKEVIRTUAL)) .build(); for (MethodNode mn : cn.methods) { if (!p.contains(mn.instructions)) continue; int offset = p.getOffset(mn.instructions) + 4; InsnList inject = new InsnList(); inject.add(new VarInsnNode(ALOAD, 2)); inject.add( new MethodInsnNode( INVOKESTATIC, "me/themallard/bitmmo/impl/plugin/chathook/ChatHookManager", "onChatMessage", "(Ljava/lang/String;)V", false)); mn.instructions.insert(mn.instructions.get(offset), inject); } }
private void hookRecieveMessage(ClassNode cn) { Pattern p = new PatternBuilder() .add( new InstructionElement(DUP), new InstructionElement(INVOKESPECIAL), new LdcElement(new LdcInsnNode("\n"))) .build(); for (MethodNode mn : cn.methods) { if (!p.contains(mn.instructions)) continue; int offset = p.getOffset(mn.instructions); MethodInsnNode getMsgInsn = (MethodInsnNode) mn.instructions.get(offset + 5); InsnList inject = new InsnList(); inject.add(new VarInsnNode(ALOAD, 1)); inject.add( new MethodInsnNode( INVOKEVIRTUAL, getMsgInsn.owner, getMsgInsn.name, "()Ljava/lang/String;", false)); inject.add( new MethodInsnNode( INVOKESTATIC, "me/themallard/bitmmo/impl/plugin/chathook/ChatHookManager", "onReceiveMessage", "(Ljava/lang/String;)V", false)); mn.instructions.insertBefore(mn.instructions.get(offset), inject); } }
@Override public byte[] transform(String name, String transformedName, byte[] bytes) { if (transformedName.equals("net.minecraft.block.BlockDynamicLiquid") && CoreLoadingPlugin.util.getBoolean("FiniteWater", false)) { ClassReader reader = new ClassReader(bytes); ClassNode node = new ClassNode(); reader.accept(node, 0); InsnList getSmallestFlowDecay = new InsnList(); getSmallestFlowDecay.add(new VarInsnNode(ALOAD, 0)); getSmallestFlowDecay.add(new InsnNode(ICONST_0)); getSmallestFlowDecay.add( new FieldInsnNode( PUTFIELD, "net/minecraft/block/BlockDynamicLiquid", "field_149815_a", "I")); for (MethodNode method : node.methods) if ("func_149810_a" .equals( FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(name, method.name, method.desc))) method.instructions.insertBefore(method.instructions.getFirst(), getSmallestFlowDecay); ClassWriter writer = new ClassWriter(0); node.accept(writer); return writer.toByteArray(); } return bytes; }
/** {@inheritDoc} */ @Override public List<Mutation> apply( MethodNode mn, String className, String methodName, BytecodeInstruction instruction, Frame frame) { List<Mutation> mutations = new LinkedList<Mutation>(); FieldInsnNode node = (FieldInsnNode) instruction.getASMNode(); Type fieldType = Type.getType(node.desc); // insert mutation into bytecode with conditional InsnList mutation = new InsnList(); logger.debug("Mutation deletefield for statement " + node.name + node.desc); if (node.getOpcode() == Opcodes.GETFIELD) { logger.debug("Deleting source of type " + node.owner); mutation.add(new InsnNode(Opcodes.POP)); } mutation.add(getDefault(fieldType)); // insert mutation into pool Mutation mutationObject = MutationPool.addMutation( className, methodName, NAME + " " + node.name + node.desc, instruction, mutation, getInfectionDistance(node, mutation)); mutations.add(mutationObject); return mutations; }
private int firePeacefulRegenEventAndStoreEventBefore( MethodNode method, AbstractInsnNode injectPoint, LabelNode endLabel) { // create variable LabelNode peacefulRegenEventStart = new LabelNode(); LocalVariableNode peacefulRegenEvent = new LocalVariableNode( "peacefulRegenEvent", Type.getDescriptor(HealthRegenEvent.PeacefulRegen.class), null, peacefulRegenEventStart, endLabel, method.maxLocals); method.maxLocals += 1; method.localVariables.add(peacefulRegenEvent); InsnList toInject = new InsnList(); // HealthRegenEvent.PeacefulRegen peacefulRegenEvent = Hooks.firePeacefulRegenEvent(this); toInject.add(new VarInsnNode(ALOAD, 0)); toInject.add( new MethodInsnNode( INVOKESTATIC, Type.getInternalName(Hooks.class), "firePeacefulRegenEvent", "(Lnet/minecraft/entity/player/EntityPlayer;)Lsqueek/applecore/api/hunger/HealthRegenEvent$PeacefulRegen;", false)); toInject.add(new VarInsnNode(ASTORE, peacefulRegenEvent.index)); toInject.add(peacefulRegenEventStart); method.instructions.insertBefore(injectPoint, toInject); return peacefulRegenEvent.index; }
@Override public void transform(ClassNode cnode) { System.out.println("[NOVA] Transforming Chunk class for chunkModified event."); ObfMapping obfMap = new ObfMapping("apx", "a", "(IIILaji;I)Z"); ObfMapping srgMap = new ObfMapping( "net/minecraft/world/chunk/Chunk", "func_150807_a", "(IIILnet/minecraft/block/Block;I)Z"); MethodNode method = ASMHelper.findMethod(obfMap, cnode); if (method == null) { System.out.println( "[NOVA] Lookup " + obfMap + " failed. You are probably in a deobf environment."); method = ASMHelper.findMethod(srgMap, cnode); if (method == null) { System.out.println("[NOVA] Lookup " + srgMap + " failed!"); } } System.out.println("[NOVA] Found method " + method.name); InsnList list = new InsnList(); list.add(new VarInsnNode(ALOAD, 0)); list.add(new VarInsnNode(ILOAD, 1)); list.add(new VarInsnNode(ILOAD, 2)); list.add(new VarInsnNode(ILOAD, 3)); list.add(new VarInsnNode(ALOAD, 8)); list.add(new VarInsnNode(ILOAD, 9)); list.add(new VarInsnNode(ALOAD, 4)); list.add(new VarInsnNode(ILOAD, 5)); list.add( new MethodInsnNode( INVOKESTATIC, "nova/wrapper/mc1710/asm/StaticForwarder", "chunkSetBlockEvent", "(Lnet/minecraft/world/chunk/Chunk;IIILnet/minecraft/block/Block;ILnet/minecraft/block/Block;I)V", false)); AbstractInsnNode lastInsn = method.instructions.getLast(); while (lastInsn instanceof LabelNode || lastInsn instanceof LineNumberNode) { lastInsn = lastInsn.getPrevious(); } if (ASMHelper.isReturn(lastInsn)) { method.instructions.insertBefore(lastInsn, list); } else { method.instructions.insert(list); } System.out.println("[NOVA] Injected instruction to method: " + method.name); }
/** {@inheritDoc} */ @Override public List<Mutation> apply( MethodNode mn, String className, String methodName, BytecodeInstruction instruction, Frame frame) { JumpInsnNode node = (JumpInsnNode) instruction.getASMNode(); List<Mutation> mutations = new LinkedList<Mutation>(); LabelNode target = node.label; boolean isBoolean = frame.getStack(frame.getStackSize() - 1) == BooleanValueInterpreter.BOOLEAN_VALUE; for (Integer op : getOperators(node.getOpcode(), isBoolean)) { logger.debug("Adding replacement " + op); if (op >= 0) { // insert mutation into bytecode with conditional JumpInsnNode mutation = new JumpInsnNode(op, target); // insert mutation into pool Mutation mutationObject = MutationPool.addMutation( className, methodName, "ReplaceComparisonOperator " + getOp(node.getOpcode()) + " -> " + getOp(op), instruction, mutation, getInfectionDistance(node.getOpcode(), op)); mutations.add(mutationObject); } else { // Replace relational operator with TRUE/FALSE InsnList mutation = new InsnList(); if (opcodesInt.contains(node.getOpcode())) mutation.add(new InsnNode(Opcodes.POP)); else mutation.add(new InsnNode(Opcodes.POP2)); if (op == TRUE) { mutation.add(new LdcInsnNode(1)); } else { mutation.add(new LdcInsnNode(0)); } mutation.add(new JumpInsnNode(Opcodes.IFNE, target)); Mutation mutationObject = MutationPool.addMutation( className, methodName, "ReplaceComparisonOperator " + getOp(node.getOpcode()) + " -> " + op, instruction, mutation, getInfectionDistance(node.getOpcode(), op)); mutations.add(mutationObject); } } return mutations; }
public void addTinkersDrawHoveringTextHook( MethodNode method, Class<?> hookClass, String hookMethod, String hookDesc, boolean isObfuscated) { AbstractInsnNode targetNode = null; // get last drawGradientRect call for (AbstractInsnNode instruction : method.instructions.toArray()) { if (instruction.getOpcode() == INVOKEVIRTUAL) { MethodInsnNode methodInsn = (MethodInsnNode) instruction; if (methodInsn.desc.equals("(IIIIII)V")) targetNode = instruction; } } if (targetNode == null) { AppleCore.Log.warn("Could not patch " + method.name + "; target node not found"); return; } LocalVariableNode x = ASMHelper.findLocalVariableOfMethod(method, "i1", "I"); LocalVariableNode y = ASMHelper.findLocalVariableOfMethod(method, "j1", "I"); LocalVariableNode w = ASMHelper.findLocalVariableOfMethod(method, "k", "I"); LocalVariableNode h = ASMHelper.findLocalVariableOfMethod(method, "k1", "I"); if (x == null || y == null || w == null || h == null) { AppleCore.Log.warn("Could not patch " + method.name + "; local variables not found"); return; } InsnList toInject = new InsnList(); /* // equivalent to: Hooks.onDrawHoveringText(0, 0, 0, 0); */ toInject.add(new VarInsnNode(ILOAD, x.index)); toInject.add(new VarInsnNode(ILOAD, y.index)); toInject.add(new VarInsnNode(ILOAD, w.index)); toInject.add(new VarInsnNode(ILOAD, h.index)); toInject.add( new MethodInsnNode( INVOKESTATIC, hookClass.getName().replace('.', '/'), hookMethod, hookDesc, false)); method.instructions.insert(targetNode, toInject); }
private InsnList generateInvokeDynamicStatic(String name, String owner, String desc) { InsnList insnList = new InsnList(); Handle methodHandle = new Handle(Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, "dynvokeStatic", BOOTSTRAP_SIGNATURE); insnList.add(new InvokeDynamicInsnNode(owner + "." + name, desc, methodHandle, "")); return insnList; }
public static InsnList createArgumentLoaders(String methodDescriptor) { checkArgNotNull(methodDescriptor, "methodDescriptor"); InsnList instructions = new InsnList(); Type[] types = Type.getArgumentTypes(methodDescriptor); for (int i = 0; i < types.length; i++) { instructions.add(new VarInsnNode(getLoadingOpcode(types[i]), i + 1)); } return instructions; }
/** * getInfectionDistance * * @param original a {@link org.objectweb.asm.tree.FieldInsnNode} object. * @param mutant a {@link org.objectweb.asm.tree.InsnList} object. * @return a {@link org.objectweb.asm.tree.InsnList} object. */ public InsnList getInfectionDistance(FieldInsnNode original, InsnList mutant) { InsnList distance = new InsnList(); if (original.getOpcode() == Opcodes.GETFIELD) distance.add(new InsnNode(Opcodes.DUP)); // make sure to re-load this for GETFIELD distance.add( new FieldInsnNode(original.getOpcode(), original.owner, original.name, original.desc)); Type type = Type.getType(original.desc); if (type.getDescriptor().startsWith("L") || type.getDescriptor().startsWith("[")) { ReplaceVariable.addReferenceDistanceCheck(distance, type, mutant); } else { ReplaceVariable.addPrimitiveDistanceCheck(distance, type, mutant); } return distance; }
private InsnList generateInvokeDynamicConstructor(String name, String owner, String desc) { InsnList insnList = new InsnList(); Handle methodHandle = new Handle( Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, "dynvokeConstructor", BOOTSTRAP_SIGNATURE); String descReceiver = Type.getMethodDescriptor(Type.getObjectType(owner), Type.getArgumentTypes(desc)); insnList.add(new InvokeDynamicInsnNode(owner + "." + name, descReceiver, methodHandle, "")); return insnList; }
private byte[] transformEntitySheep(byte[] bytes) { System.out.println("Transforming EntitySheep..."); ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(bytes); cr.accept(cn, 0); Iterator<MethodNode> methods = cn.methods.iterator(); while (methods.hasNext()) { MethodNode m = methods.next(); if (m.name.equals(names.get("entitySheep_setColour_func")) && m.desc.equals(names.get("entitySheep_setColour_desc"))) { System.out.println("Found target method: " + m.name + m.desc + "! Inserting call..."); for (int idx = 0; idx < m.instructions.size(); idx++) { if (m.instructions.get(idx).getOpcode() == Opcodes.ISTORE) { System.out.println("Found ISTORE at index " + idx + ", inserting code afterwards..."); idx++; // AFTERwards, not before ;) InsnList toAdd = new InsnList(); // to mark the end of the code LabelNode lmmnode = new LabelNode(new Label()); // load this toAdd.add(new VarInsnNode(Opcodes.ALOAD, 0)); // new fleece colour toAdd.add(new VarInsnNode(Opcodes.ILOAD, 1)); // old fleece colour toAdd.add(new VarInsnNode(Opcodes.ILOAD, 2)); toAdd.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onSheepDye", "(L" + names.get("entitySheep_javaName") + ";II)Z")); LabelNode endIf = new LabelNode(new Label()); toAdd.add(new JumpInsnNode(Opcodes.IFEQ, endIf)); toAdd.add(new InsnNode(Opcodes.RETURN)); toAdd.add(endIf); toAdd.add(lmmnode); m.instructions.insertBefore(m.instructions.get(idx), toAdd); break; } } } } ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cn.accept(cw); return cw.toByteArray(); }
public void addCodeChickenDrawHoveringTextHook( MethodNode method, Class<?> hookClass, String hookMethod, String hookDesc) { AbstractInsnNode targetNode = ASMHelper.findFirstInstruction(method); InsnList toInject = new InsnList(); /* // equivalent to: Hooks.onDrawHoveringText(0, 0, 0, 0); */ toInject.add(new VarInsnNode(ILOAD, 0)); // x toInject.add(new VarInsnNode(ILOAD, 1)); // y toInject.add(new VarInsnNode(ILOAD, 2)); // w toInject.add(new VarInsnNode(ILOAD, 3)); // h toInject.add( new MethodInsnNode( INVOKESTATIC, hookClass.getName().replace('.', '/'), hookMethod, hookDesc, false)); method.instructions.insertBefore(targetNode, toInject); }
private void addInitializationLogicToConstructors() { if (!classMetadata.hasManagedFieldsWithFieldGranularity()) { return; } for (MethodNode methodNode : (List<MethodNode>) classNode.methods) { MethodMetadata methodMetadata = classMetadata.getMethodMetadata(methodNode.name, methodNode.desc); if (methodMetadata.isTransactional() && methodMetadata.isConstructor()) { int firstAfterSuper = firstIndexAfterSuper(methodNode, classNode.superName); if (firstAfterSuper >= 0) { InsnList extraInstructions = new InsnList(); for (FieldNode fieldNode : (List<FieldNode>) classNode.fields) { FieldMetadata fieldMetadata = classMetadata.getFieldMetadata(fieldNode.name); if (fieldMetadata.hasFieldGranularity()) { extraInstructions.add(new VarInsnNode(ALOAD, 0)); String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); extraInstructions.add(new TypeInsnNode(NEW, referenceName)); extraInstructions.add(new InsnNode(DUP)); extraInstructions.add( new MethodInsnNode(INVOKESPECIAL, referenceName, "<init>", "()V")); extraInstructions.add( new FieldInsnNode(PUTFIELD, classNode.name, fieldNode.name, referenceDesc)); } AbstractInsnNode first = methodNode.instructions.get(firstAfterSuper); methodNode.instructions.insert(first, extraInstructions); } } } } }
/** * getInfectionDistance * * @param opcodeOrig a int. * @param opcodeNew a int. * @return a {@link org.objectweb.asm.tree.InsnList} object. */ public InsnList getInfectionDistance(int opcodeOrig, int opcodeNew) { InsnList distance = new InsnList(); switch (opcodeOrig) { case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPLE: case Opcodes.IF_ICMPLT: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: distance.add(new InsnNode(Opcodes.DUP2)); distance.add(new LdcInsnNode(opcodeOrig)); distance.add(new LdcInsnNode(opcodeNew)); distance.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "org/evosuite/instrumentation/mutation/ReplaceComparisonOperator", "getInfectionDistance", "(IIII)D", false)); break; case Opcodes.IFEQ: case Opcodes.IFNE: case Opcodes.IFLE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: distance.add(new InsnNode(Opcodes.DUP)); distance.add(new LdcInsnNode(opcodeOrig)); distance.add(new LdcInsnNode(opcodeNew)); distance.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "org/evosuite/instrumentation/mutation/ReplaceComparisonOperator", "getInfectionDistance", "(III)D", false)); break; default: distance.add(new LdcInsnNode(0.0)); } return distance; }
@Override protected void apply(ClassNode cn) { MethodNode m = ReikaASMHelper.getMethodByName( cn, "func_77943_a", "tryPlaceItemIntoWorld", "(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;IIIIFFF)Z"); AbstractInsnNode ain = ReikaASMHelper.getLastOpcode(m.instructions, Opcodes.INVOKEVIRTUAL); InsnList li = new InsnList(); li.add(new VarInsnNode(Opcodes.ALOAD, 0)); li.add(new VarInsnNode(Opcodes.ALOAD, 1)); li.add(new VarInsnNode(Opcodes.ALOAD, 2)); li.add(new VarInsnNode(Opcodes.ILOAD, 3)); li.add(new VarInsnNode(Opcodes.ILOAD, 4)); li.add(new VarInsnNode(Opcodes.ILOAD, 5)); li.add(new VarInsnNode(Opcodes.ILOAD, 6)); li.add(new VarInsnNode(Opcodes.FLOAD, 7)); li.add(new VarInsnNode(Opcodes.FLOAD, 8)); li.add(new VarInsnNode(Opcodes.FLOAD, 9)); li.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "Reika/DragonAPI/Instantiable/Event/PostItemUseEvent", "fire", "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;IIIIFFF)V", false)); m.instructions.insert(ain, li); // ReikaJavaLibrary.pConsole(ReikaASMHelper.clearString(m.instructions)); }
private InsnList generateInvokeDynamicVirtualInterfaceSpecial( String name, String owner, String desc, String bootstrapMethod) { InsnList insnList = new InsnList(); Handle methodHandle = new Handle(Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, bootstrapMethod, BOOTSTRAP_SIGNATURE); List<Type> argsList = new ArrayList<Type>(Arrays.asList(new Type[] {Type.getObjectType(owner)})); argsList.addAll(Arrays.asList(Type.getArgumentTypes(desc))); String descReceiver = Type.getMethodDescriptor( Type.getReturnType(desc), argsList.toArray(new Type[argsList.size()])); insnList.add(new InvokeDynamicInsnNode(owner + "." + name, descReceiver, methodHandle, "")); return insnList; }
public byte[] transformCreeper(byte[] bytes) { ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(bytes); cr.accept(cn, 0); // System.out.println("Transforming EntityCreeper..."); Iterator<MethodNode> methods = cn.methods.iterator(); while (methods.hasNext()) { MethodNode m = methods.next(); // System.out.println(m.name + m.desc + " vs " + names.get("entityCreeper_onUpdate_func") + // names.get("entityCreeper_onUpdate_desc")); if (m.name.equals(names.get("entityCreeper_onUpdate_func")) && m.desc.equals(names.get("entityCreeper_onUpdate_desc"))) { for (int i = m.instructions.size() - 1; i >= 0; i--) { if (m.instructions.get(i).getOpcode() == Opcodes.IFNE) { System.out.println("Found insertion point! inserting code!"); i++; InsnList insns = new InsnList(); insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); insns.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onCreeperExplode", "(L" + names.get("entityCreeper_javaName") + ";)Z")); LabelNode endIf = new LabelNode(new Label()); insns.add(new JumpInsnNode(Opcodes.IFEQ, endIf)); // insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); // insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, // names.get("entityCreeper_javaName"), names.get("entityCreeper_setDead_func"), // names.get("entityCreeper_setDead_desc"))); insns.add(new InsnNode(Opcodes.RETURN)); insns.add(endIf); insns.add(new LabelNode(new Label())); m.instructions.insertBefore(m.instructions.get(i), insns); break; } } } } ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cn.accept(cw); return cw.toByteArray(); }
public void addPeacefulRegenHook(ClassNode classNode, MethodNode method) { AbstractInsnNode relevantConditional = ASMHelper.find(method.instructions, new LdcInsnNode("naturalRegeneration")); JumpInsnNode ifNode = (JumpInsnNode) ASMHelper.find(relevantConditional, new JumpInsnNode(IFEQ, new LabelNode())); LabelNode ifBlockEndLabel = ifNode.label; AbstractInsnNode targetNode = ASMHelper.find(ifNode, new InsnNode(FCONST_1)).getPrevious(); int peacefulRegenEventIndex = firePeacefulRegenEventAndStoreEventBefore(method, targetNode, ifBlockEndLabel); InsnList healAmountNeedle = new InsnList(); healAmountNeedle.add(new InsnNode(FCONST_1)); InsnList healAmountReplacement = new InsnList(); healAmountReplacement.add(new VarInsnNode(ALOAD, peacefulRegenEventIndex)); healAmountReplacement.add( new FieldInsnNode( GETFIELD, Type.getInternalName(HealthRegenEvent.PeacefulRegen.class), "deltaHealth", "F")); ASMHelper.findAndReplace( method.instructions, healAmountNeedle, healAmountReplacement, targetNode); InsnList ifNotCanceledBlock = new InsnList(); LabelNode ifNotCanceled = new LabelNode(); ifNotCanceledBlock.add(new VarInsnNode(ALOAD, peacefulRegenEventIndex)); ifNotCanceledBlock.add( new MethodInsnNode( INVOKEVIRTUAL, Type.getInternalName(HealthRegenEvent.PeacefulRegen.class), "isCanceled", "()Z", false)); ifNotCanceledBlock.add(new JumpInsnNode(IFNE, ifNotCanceled)); method.instructions.insertBefore(targetNode, ifNotCanceledBlock); method.instructions.insertBefore(ifBlockEndLabel, ifNotCanceled); }
private byte[] transformNetServerHandler(byte[] bytes) { ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(bytes); cr.accept(cn, 0); Iterator<MethodNode> methods = cn.methods.iterator(); while (methods.hasNext()) { MethodNode m = methods.next(); if (m.name.equals(names.get("netServerHandler_handleFlying_func")) && m.desc.equals(names.get("netServerHandler_handleFlying_desc"))) { System.out.println("Found target method: " + m.name + m.desc + "! Inserting code..."); InsnList toInsert = new InsnList(); toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1)); toInsert.add(new VarInsnNode(Opcodes.ALOAD, 0)); toInsert.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onPlayerMove", "(L" + names.get("packet10Flying_javaName") + ";L" + names.get("netServerHandler_javaName") + ";)Z")); LabelNode endIf = new LabelNode(new Label()); toInsert.add(new JumpInsnNode(Opcodes.IFEQ, endIf)); toInsert.add(new InsnNode(Opcodes.RETURN)); toInsert.add(endIf); toInsert.add(new LabelNode(new Label())); m.instructions.insert(toInsert); } } ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cn.accept(cw); return cw.toByteArray(); }
private InsnList fixInstructions(MethodNode originalMethod, CloneMap cloneMap) { InsnList instructions = new InsnList(); for (int k = 0; k < originalMethod.instructions.size(); k++) { AbstractInsnNode originalInsn = originalMethod.instructions.get(k); switch (originalInsn.getOpcode()) { // the put on the field granular field is transformed to a fieldref.set case PUTFIELD: { FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn; ClassMetadata ownerMetadata = metadataRepository.loadClassMetadata(classLoader, fieldInsn.owner); FieldMetadata fieldMetadata = ownerMetadata.getFieldMetadata(fieldInsn.name); Type originalFieldType = Type.getType(fieldMetadata.getDesc()); if (fieldMetadata.hasFieldGranularity()) { boolean fieldIsCategory2 = isCategory2(fieldMetadata.getDesc()); if (fieldIsCategory2) { // value(category2), owner,.. instructions.add(new InsnNode(DUP2_X1)); // [value(category2), owner, value(category2),...] instructions.add(new InsnNode(POP2)); // [owner, value(category2), ...] } else { // [value(category1), owner, instructions.add(new InsnNode(SWAP)); // [owner, value(category1),.. } String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); instructions.add( new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc)); if (fieldIsCategory2) { // [owner, value(category2),.. instructions.add(new InsnNode(DUP_X2)); // [owner, value(category2), owner instructions.add(new InsnNode(POP)); // [value(category2), owner } else { // [owner, value(category1) instructions.add(new InsnNode(SWAP)); // [value(category1), owner.. } // call the set if (originalFieldType.getSort() == Type.ARRAY || originalFieldType.getSort() == Type.OBJECT) { String objectDesc = Type.getDescriptor(Object.class); MethodInsnNode methodInsn = new MethodInsnNode( INVOKEVIRTUAL, referenceName, "set", format("(%s)%s", objectDesc, objectDesc)); instructions.add(methodInsn); } else { MethodInsnNode methodInsn = new MethodInsnNode( INVOKEVIRTUAL, referenceName, "set", format("(%s)%s", fieldMetadata.getDesc(), fieldMetadata.getDesc())); instructions.add(methodInsn); } // pop the unused return value of the set. if (fieldIsCategory2) { instructions.add(new InsnNode(POP2)); } else { instructions.add(new InsnNode(POP)); } } else { instructions.add(originalInsn.clone(cloneMap)); } } break; // the get on the field granular field is transformed to a fieldref.get case GETFIELD: { FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn; FieldMetadata fieldMetadata = metadataRepository .loadClassMetadata(classLoader, fieldInsn.owner) .getFieldMetadata(fieldInsn.name); if (!fieldMetadata.hasFieldGranularity()) { // if it is not getter on a field granular field instructions.add(originalInsn.clone(cloneMap)); } else { // it is a getter on a field granular field. String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); // place the fieldref on the stack. instructions.add( new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc)); Type originalFieldType = Type.getType(fieldMetadata.getDesc()); if (originalFieldType.getSort() == Type.ARRAY || originalFieldType.getSort() == Type.OBJECT) { instructions.add( new MethodInsnNode( INVOKEVIRTUAL, referenceName, "get", format("()%s", getDescriptor(Object.class)))); if (!originalFieldType.equals(Type.getType(Object.class))) { instructions.add( new TypeInsnNode(CHECKCAST, originalFieldType.getInternalName())); } } else { instructions.add( new MethodInsnNode( INVOKEVIRTUAL, referenceName, "get", format("()%s", fieldMetadata.getDesc()))); } } } break; default: instructions.add(originalInsn.clone(cloneMap)); break; } } return instructions; }
@Override boolean processMethods(List<MethodNode> methods) { int found = 0; for (MethodNode mn : methods) { if (mn.name.equals("<init>")) { logger.log(Level.INFO, "\tPatching constructor in EntityPlayer"); ListIterator<AbstractInsnNode> it = mn.instructions.iterator(); while (it.hasNext()) { AbstractInsnNode insn = it.next(); if (insn instanceof TypeInsnNode) { if (((TypeInsnNode) insn).desc.equals(inventoryClassName)) { ((TypeInsnNode) insn).desc = "mods/battlegear2/api/core/InventoryPlayerBattle"; } } else if (insn instanceof MethodInsnNode) { if (((MethodInsnNode) insn).owner.equals(inventoryClassName)) { ((MethodInsnNode) insn).owner = "mods/battlegear2/api/core/InventoryPlayerBattle"; } } } found++; } else if (mn.name.equals(onItemFinishMethodName) && mn.desc.equals(SIMPLEST_METHOD_DESC)) { sendPatchLog("onItemUseFinish"); InsnList newList = new InsnList(); ListIterator<AbstractInsnNode> it = mn.instructions.iterator(); while (it.hasNext()) { AbstractInsnNode next = it.next(); if (next instanceof MethodInsnNode && ((MethodInsnNode) next) .owner.equals("net/minecraftforge/event/ForgeEventFactory")) { found++; int index = ((MethodInsnNode) next).desc.indexOf(")"); String newDesc = ((MethodInsnNode) next).desc.substring(0, index) + "I" + ((MethodInsnNode) next).desc.substring(index); newList.add(new VarInsnNode(ILOAD, 1)); newList.add( new MethodInsnNode(INVOKESTATIC, UTILITY_CLASS, "beforeFinishUseEvent", newDesc)); } else { newList.add(next); } } mn.instructions = newList; } else if (mn.name.equals(onUpdateMethodName) && mn.desc.equals(SIMPLEST_METHOD_DESC)) { sendPatchLog("onUpdate"); InsnList newList = new InsnList(); ListIterator<AbstractInsnNode> it = mn.instructions.iterator(); while (it.hasNext()) { AbstractInsnNode next = it.next(); if (next instanceof FieldInsnNode && ((FieldInsnNode) next).owner.equals(entityPlayerClassName) && ((FieldInsnNode) next).name.equals(playerInventoryFieldName)) { found++; newList.add(new VarInsnNode(ALOAD, 0)); newList.add( new FieldInsnNode( GETFIELD, entityPlayerClassName, playerItemInUseField, "L" + itemStackClassName + ";")); newList.add( new MethodInsnNode( INVOKESTATIC, UTILITY_CLASS, "getCurrentItemOnUpdate", "(L" + entityPlayerClassName + ";L" + itemStackClassName + ";)L" + itemStackClassName + ";")); next = it.next(); } else { newList.add(next); } } mn.instructions = newList; } else if (mn.name.equals(setCurrentItemArmourMethodName) && mn.desc.equals(setCurrentItemArmourMethodDesc)) { sendPatchLog("setCurrentItemOrArmor"); replaceInventoryArrayAccess( mn, entityPlayerClassName, playerInventoryFieldName, mn.maxStack, mn.maxLocals); found++; } else if (mn.name.equals(interactWithMethodName) && mn.desc.equals(interactWithMethodDesc)) { sendPatchLog("interactWith"); MethodNode mv = new MethodNode(ACC_PUBLIC, interactWithMethodName, interactWithMethodDesc, null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn( INVOKESTATIC, UTILITY_CLASS, "interactWith", "(L" + entityPlayerClassName + ";L" + entityClassName + ";)Z"); mv.visitInsn(IRETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "L" + entityPlayerClassName + ";", null, l0, l1, 0); mv.visitLocalVariable("p_70998_1_", "L" + entityClassName + ";", null, l0, l1, 1); mv.visitMaxs(2, 2); mv.visitEnd(); mn.instructions = mv.instructions; found++; } } logger.log(Level.INFO, "\tCreating new methods in EntityPlayer"); methods.add(methods.size(), generateAttackOffhandMethod()); methods.add(methods.size(), generateSwingOffhand()); methods.add(methods.size(), generateGetOffSwingMethod()); methods.add(methods.size(), generateUpdateSwingArm()); methods.add(methods.size(), generateIsBattleMode()); methods.add(methods.size(), generateIsBlockingWithShield()); methods.add(methods.size(), generateSetBlockingWithShield()); methods.add( methods.size(), generateGetter(entityPlayerClassName, "getSpecialActionTimer", "specialActionTimer", "I")); methods.add( methods.size(), generateSetter(entityPlayerClassName, "setSpecialActionTimer", "specialActionTimer", "I")); return found == 5; }
private static void transformBiblioFramingChest(ClassNode classNode, boolean isObfuscated) { LOG.info("Found class. Hunting for method."); final String ENTITY_COLLIDE = "func_145845_h"; final String ENTITY_COLLIDE_DESC = "()V"; /* Instructions we need to find: mv.visitInsn(IADD); mv.visitFieldInsn(PUTFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "ticksSinceSync", "I"); */ /* Need to add this: To tick the chest for heat and decay mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "worldObj", "Lnet/minecraft/world/World;"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "xCoord", "I"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "yCoord", "I"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "zCoord", "I"); mv.visitMethodInsn(INVOKESTATIC, "com/bioxx/tfc/Core/TFC_Core", "handleItemTicking", "(Lnet/minecraft/inventory/IInventory;Lnet/minecraft/world/World;III)V", false); */ for (MethodNode method : classNode.methods) { if (method.name.equals(ENTITY_COLLIDE) && method.desc.equals(ENTITY_COLLIDE_DESC)) { LOG.info("Found our method"); AbstractInsnNode targetNode = null; for (AbstractInsnNode instruction : method.instructions.toArray()) { if (instruction.getOpcode() == ALOAD) { if (((VarInsnNode) instruction).var == 0 && instruction.getNext().getOpcode() == INVOKESPECIAL) { targetNode = instruction; LOG.info("Found target instruction"); break; } } } if (targetNode != null) { /* mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "worldObj", "Lnet/minecraft/world/World;"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "xCoord", "I"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "yCoord", "I"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "zCoord", "I"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "ticksSinceSync", "I"); mv.visitMethodInsn(INVOKESTATIC, "TechNodefirmacraft/ASM/Transform/TF_BiblioFramingChest", "handleItemTicking", "(Lnet/minecraft/inventory/IInventory;Lnet/minecraft/world/World;IIII)V", false); */ InsnList toInsert = new InsnList(); toInsert.add(new VarInsnNode(ALOAD, 0)); toInsert.add(new VarInsnNode(ALOAD, 0)); toInsert.add( new FieldInsnNode( GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "field_145850_b", "Lnet/minecraft/world/World;")); toInsert.add(new VarInsnNode(ALOAD, 0)); toInsert.add( new FieldInsnNode( GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "field_145851_c", "I")); toInsert.add(new VarInsnNode(ALOAD, 0)); toInsert.add( new FieldInsnNode( GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "field_145848_d", "I")); toInsert.add(new VarInsnNode(ALOAD, 0)); toInsert.add( new FieldInsnNode( GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "field_145849_e", "I")); toInsert.add(new VarInsnNode(ALOAD, 0)); toInsert.add( new FieldInsnNode( GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "ticksSinceSync", "I")); toInsert.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "TechNodefirmacraft/ASM/Transform/TF_BiblioFramingChest", "handleItemTicking", "(Lnet/minecraft/inventory/IInventory;Lnet/minecraft/world/World;IIII)V", false)); method.instructions.insertBefore(targetNode, toInsert); LOG.info("Done terrible things to that method. Working?"); // method.instructions.insert(popNode, newLabelNode); } else { LOG.error("Something went wrong transforming TileEntityFramedChest!"); } } } }
// 下記の想定で実装されています。 // EntityLiving.class の doRenderLiving の先頭に // tutorial/test.class の passTestRender(EntityLiving, double, double, double)メソッドの呼び出しを追加する。 private byte[] hookOnItemRightClick(String className, byte[] bytes) { // ASMで、bytesに格納されたクラスファイルを解析します。 ClassNode cnode = new ClassNode(); ClassReader reader = new ClassReader(bytes); reader.accept(cnode, 0); // 改変対象のメソッド名です String targetMethodName = "onItemRightClick"; String targetMethodNameSRG = "func_77659_a"; // 改変対象メソッドの戻り値型および、引数型をあらわします ※1 String targetMethoddesc = "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/item/ItemStack;"; String targetMethoddescSRG = "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/item/ItemStack;"; // 対象のメソッドを検索取得します。 MethodNode mnode = null; String mdesc = null; for (MethodNode curMnode : cnode.methods) { String mName = FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(className, curMnode.name, curMnode.desc); String mdName = FMLDeobfuscatingRemapper.INSTANCE.mapMethodDesc(curMnode.desc); // System.out.println("[ " + mName + " : " + curMnode.name + " ] [ " + mdName + " : " + // curMnode.desc); if ((targetMethodName.equals(curMnode.name) && targetMethoddesc.equals(curMnode.desc)) || (targetMethodNameSRG.equals(mName) && targetMethoddescSRG.equals(mdName))) { mnode = curMnode; mdesc = curMnode.desc; break; } } if (mnode != null) { InsnList overrideList = new InsnList(); // メソッドコールを、バイトコードであらわした例です。 overrideList.add(new VarInsnNode(ALOAD, 1)); overrideList.add(new VarInsnNode(ALOAD, 2)); overrideList.add(new VarInsnNode(ALOAD, 3)); overrideList.add( new MethodInsnNode( INVOKESTATIC, "shift/sextiarysector/asm/vanilla/BottleMethod", "onBottleRightClick", mdesc, false)); overrideList.add(new InsnNode(ARETURN)); // mnode.instructions.get(1)で、対象のメソッドの先頭を取得 // mnode.instructions.insertで、指定した位置にバイトコードを挿入します。 mnode.instructions.insert(mnode.instructions.get(1), overrideList); // mnode.maxLocals = 4; // 改変したクラスファイルをバイト列に書き出します ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); cnode.accept(cw); bytes = cw.toByteArray(); System.out.println("bbbb"); } return bytes; }
private byte[] transformLightningBolt(byte[] bytes) { ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(bytes); cr.accept(cn, 0); Iterator<MethodNode> methods = cn.methods.iterator(); while (methods.hasNext()) { MethodNode m = methods.next(); if (m.name.equals("<init>")) { System.out.println("Found constructor in EntityLightningBolt, searching for landmarks..."); AbstractInsnNode mark1 = null; AbstractInsnNode mark2 = null; AbstractInsnNode firstEndIf = null; AbstractInsnNode secondEndIf = null; InsnList insns1 = new InsnList(); insns1.add(new VarInsnNode(Opcodes.ALOAD, 0)); insns1.add(new VarInsnNode(Opcodes.ALOAD, 1)); insns1.add(new VarInsnNode(Opcodes.ILOAD, 8)); insns1.add(new VarInsnNode(Opcodes.ILOAD, 9)); insns1.add(new VarInsnNode(Opcodes.ILOAD, 10)); insns1.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onLightningStrike", "(L" + names.get("entityLightningBolt_javaName") + ";L" + names.get("world_javaName") + ";III)Z")); LabelNode endIf1 = new LabelNode(new Label()); insns1.add(new JumpInsnNode(Opcodes.IFNE, endIf1)); InsnList insns2 = new InsnList(); insns1.add(new InsnNode(Opcodes.ACONST_NULL)); insns2.add(new VarInsnNode(Opcodes.ALOAD, 1)); insns2.add(new VarInsnNode(Opcodes.ILOAD, 9)); insns2.add(new VarInsnNode(Opcodes.ILOAD, 10)); insns2.add(new VarInsnNode(Opcodes.ILOAD, 11)); insns2.add( new MethodInsnNode( Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onLightningStrike", "(L" + names.get("entityLightningBolt_javaName") + ";L" + names.get("world_javaName") + ";III)Z")); LabelNode endIf2 = new LabelNode(new Label()); insns2.add(new JumpInsnNode(Opcodes.IFNE, endIf2)); boolean firstInvokeV = false; for (int i = 0; i < m.instructions.size(); i++) { if (m.instructions.get(i).getOpcode() == Opcodes.IFEQ) { if (mark1 != null) mark2 = m.instructions.get(i).getNext(); else mark1 = m.instructions.get(i).getNext(); } if (m.instructions.get(i).getOpcode() == Opcodes.INVOKEVIRTUAL && !firstInvokeV && mark1 != null) { firstEndIf = m.instructions.get(i).getNext(); } else if (m.instructions.get(i).getOpcode() == Opcodes.INVOKEVIRTUAL && mark2 != null && firstInvokeV) { secondEndIf = m.instructions.get(i).getNext(); } } m.instructions.insertBefore(mark1, insns1); m.instructions.insertBefore(firstEndIf, endIf1); m.instructions.insertBefore(mark2, insns2); m.instructions.insertBefore(secondEndIf, endIf2); } } ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cn.accept(cw); return cw.toByteArray(); }