public static void renameClassNode(final String oldName, final String newName) { for (ClassNode c : BytecodeViewer.getLoadedClasses()) { for (Object oo : c.innerClasses) { InnerClassNode innerClassNode = (InnerClassNode) oo; if (innerClassNode.innerName != null && innerClassNode.innerName.equals(oldName)) { innerClassNode.innerName = newName; } if (innerClassNode.name.equals(oldName)) { innerClassNode.name = newName; } if (innerClassNode.outerName != null && innerClassNode.outerName.equals(oldName)) { innerClassNode.outerName = newName; } } if (c.signature != null) c.signature = c.signature.replace(oldName, newName); if (c.superName.equals(oldName)) { c.superName = newName; } for (Object o : c.fields.toArray()) { FieldNode f = (FieldNode) o; f.desc = f.desc.replace(oldName, newName); } for (Object o : c.interfaces.toArray()) { String truxerLipton = (String) o; truxerLipton = truxerLipton.replace(oldName, newName); } for (Object o : c.methods.toArray()) { MethodNode m = (MethodNode) o; if (m.localVariables != null) { for (LocalVariableNode node : (List<LocalVariableNode>) m.localVariables) { node.desc = node.desc.replace(oldName, newName); } } if (m.signature != null) m.signature = m.signature.replace(oldName, newName); for (int i = 0; i < m.exceptions.size(); i++) { if (m.exceptions.get(i).equals(oldName)) m.exceptions.set(i, newName); } for (AbstractInsnNode i : m.instructions.toArray()) { if (i instanceof TypeInsnNode) { TypeInsnNode t = (TypeInsnNode) i; if (t.desc.equals(oldName)) { t.desc = newName; } } if (i instanceof MethodInsnNode) { MethodInsnNode mi = (MethodInsnNode) i; if (mi.owner.equals(oldName)) mi.owner = newName; mi.desc = mi.desc.replace(oldName, newName); } if (i instanceof FieldInsnNode) { FieldInsnNode fi = (FieldInsnNode) i; if (fi.owner.equals(oldName)) fi.owner = newName; fi.desc = fi.desc.replace(oldName, newName); } } } } }
@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; }
private static void transformIfNeccessary(File file) throws IOException { InputStream is = new FileInputStream(file); ClassNode cn; try { ClassReader cr = new ClassReader(is); cn = new ClassNode(); cr.accept(cn, 0); } finally { is.close(); } if (!isAlreadyTransformed(cn) && isAnnotationPresent(cn)) { System.out.println("Transforming file " + file); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor ca = new CheckClassAdapter(cw); ClassVisitor cv = new PropertyChangeSupportAdapter(ca); cn.accept(cv); FileOutputStream os = new FileOutputStream(file); try { os.write(cw.toByteArray()); } finally { os.close(); } } }
@Override public byte[] transform(String className, String transformedClassName, byte[] bytes) { String methodName; if (className.equals(OBF_CLASS)) { methodName = SRG_METHOD; } else if (className.equals(MCP_CLASS)) { methodName = MCP_METHOD; } else { return bytes; } ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); for (MethodNode method : classNode.methods) { if (method.name.equals(methodName) && method.desc.equals(METHOD_DESC)) { logger.info("CraftingTweaks will now patch {} in {}...", methodName, className); MethodNode mn = new MethodNode(); Label notClicked = new Label(); // mn.visitMethodInsn(Opcodes.INVOKESTATIC, "org/lwjgl/input/Mouse", "getEventButtonState", // "()Z", false); // mn.visitJumpInsn(Opcodes.IFEQ, notClicked); // if getEventButtonState false, continue // after mn.visitVarInsn(Opcodes.ILOAD, 1); // push mouseX mn.visitVarInsn(Opcodes.ILOAD, 2); // push mouseY mn.visitVarInsn(Opcodes.ILOAD, 3); // push button mn.visitMethodInsn( Opcodes.INVOKESTATIC, "net/blay09/mods/craftingtweaks/CraftingTweaks", "onGuiClick", "(III)Z", false); // call onGuiClick mn.visitJumpInsn(Opcodes.IFEQ, notClicked); // if onGuiClick false, continue after mn.visitInsn(Opcodes.RETURN); // otherwise stop here mn.visitLabel(notClicked); // continue from here AbstractInsnNode insertAfter = null; for (int i = 0; i < method.instructions.size(); i++) { AbstractInsnNode node = method.instructions.get(i); if (node instanceof VarInsnNode) { if (node.getOpcode() == Opcodes.ISTORE && ((VarInsnNode) node).var == 3) { // ISTORE 3 insertAfter = node; break; } } } if (insertAfter != null) { method.instructions.insert(insertAfter, mn.instructions); logger.info("CraftingTweaks successfully patched {} in {}!", methodName, className); } else { logger.warn( "CraftingTweaks failed to patch {0}::{1} ({2} not found) - transfering into crafting grids will not work!", className, methodName, "ISTORE 3"); } } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
@Override public byte[] transform(String name, String transformedName, byte[] basicClass) { if (!"net.minecraft.item.ItemStack".equals(name)) return basicClass; ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(basicClass); classReader.accept(classNode, 0); FieldNode itemField = null; for (FieldNode f : classNode.fields) { if (ITEM_TYPE.equals(f.desc) && itemField == null) { itemField = f; } else if (ITEM_TYPE.equals(f.desc)) { throw new RuntimeException("Error processing ItemStack - found a duplicate Item field"); } } if (itemField == null) { throw new RuntimeException( "Error processing ItemStack - no Item field declared (is the code somehow obfuscated?)"); } MethodNode getItemMethod = null; for (MethodNode m : classNode.methods) { if (GETITEM_DESC.equals(m.desc) && getItemMethod == null) { getItemMethod = m; } else if (GETITEM_DESC.equals(m.desc)) { throw new RuntimeException("Error processing ItemStack - duplicate getItem method found"); } } if (getItemMethod == null) { throw new RuntimeException( "Error processing ItemStack - no getItem method found (is the code somehow obfuscated?)"); } for (MethodNode m : classNode.methods) { for (ListIterator<AbstractInsnNode> it = m.instructions.iterator(); it.hasNext(); ) { AbstractInsnNode insnNode = it.next(); if (insnNode.getType() == AbstractInsnNode.FIELD_INSN) { FieldInsnNode fi = (FieldInsnNode) insnNode; if (itemField.name.equals(fi.name) && fi.getOpcode() == Opcodes.GETFIELD) { it.remove(); MethodInsnNode replace = new MethodInsnNode( Opcodes.INVOKEVIRTUAL, "net/minecraft/item/ItemStack", getItemMethod.name, getItemMethod.desc, false); it.add(replace); } } } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
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(); }
protected byte[] transformClass(byte[] bytes, String clssname) { InputStream is = getClass().getResourceAsStream("/" + clssname.replace('.', '/') + ".class"); ClassReader orig = null; try { ClassReader crRepl = new ClassReader(is); ClassNode cnRepl = new ClassNode(Opcodes.ASM4); crRepl.accept(cnRepl, ClassReader.SKIP_FRAMES); ClassReader crOrig = new ClassReader(bytes); ClassNode cnOrig = new ClassNode(Opcodes.ASM4); crOrig.accept(cnOrig, ClassReader.SKIP_FRAMES); for (Object ofnRepl : cnRepl.fields) { FieldNode fnRepl = (FieldNode) ofnRepl; if (hasReplaceAnnotation(fnRepl.visibleAnnotations)) { FieldNode fnOrig = findField(cnOrig.fields, fnRepl); if (fnOrig != null) { cnOrig.fields.remove(fnOrig); cnOrig.fields.add(cnOrig.fields.size(), scrubField(cnOrig, cnRepl, fnRepl)); } } else if (hasAddAnnotation(fnRepl.visibleAnnotations)) { cnOrig.fields.add(cnOrig.fields.size(), scrubField(cnOrig, cnRepl, fnRepl)); } } for (Object omnRepl : cnRepl.methods) { MethodNode mnRepl = (MethodNode) omnRepl; if (hasReplaceAnnotation(mnRepl.visibleAnnotations)) { MethodNode mnOrig = findMethod(cnOrig.methods, mnRepl); if (mnOrig != null) { cnOrig.methods.remove(mnOrig); cnOrig.methods.add(cnOrig.methods.size(), scrubMethod(cnOrig, cnRepl, mnRepl)); } } else if (hasAddAnnotation(mnRepl.visibleAnnotations)) { cnOrig.methods.add(cnOrig.methods.size() + 1, scrubMethod(cnOrig, cnRepl, mnRepl)); } } ClassWriter cwNew = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cnOrig.accept(cwNew); return cwNew.toByteArray(); } catch (IOException e) { e.printStackTrace(); // To change body of catch statement use File | Settings | File // Templates. } return bytes; }
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 static byte[] getBytesFromClassNode(ClassNode c) { ClassWriter w = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); c.accept(w); byte[] b = w.toByteArray(); SquidAPIPlugin.LOGGER.info("Successfully transformed " + c.name.replace("/", "."), "."); return b; }
private void createAddMessage(ClassNode cn) { Pattern p = new PatternBuilder() .add( new InstructionElement(ALOAD), new LdcElement(new LdcInsnNode("")), new InstructionElement(ALOAD), new InstructionElement(INVOKEVIRTUAL)) .build(); MethodInsnNode ebola1 = null; for (MethodNode mn : cn.methods) { if (!p.contains(mn.instructions)) continue; int offset = p.getOffset(mn.instructions); ebola1 = (MethodInsnNode) mn.instructions.get(offset + 3); } { MethodVisitor mv = cn.visitMethod(ACC_PUBLIC, "addChatMessage", "(Ljava/lang/String;)V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitLdcInsn(""); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, ebola1.owner, ebola1.name, ebola1.desc, ebola1.itf); mv.visitInsn(RETURN); mv.visitEnd(); } }
private static byte[] transform(int index, byte[] classBeingTransformed, boolean isObfuscated) { LOG.info("Transforming: " + classesBeingTransformed[index]); try { ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(classBeingTransformed); classReader.accept(classNode, 0); switch (index) { case 0: transformBiblioFramingChest(classNode, isObfuscated); break; } ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(classWriter); return classWriter.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return classBeingTransformed; }
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(); }
public byte[] finish(String name, String transformedName) { if (currentClass == null) return null; ClassWriter cw = new ClassWriter( 0 /*ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS*/); // compute everything from // scratch currentClass.accept(cw); currentClass = null; byte[] ret = cw.toByteArray(); ret = temporaryFixOfStuff( name, transformedName, ret); // ret = fixSide(name, transformedName, ret); return ret; }
@Override public byte[] transform(String name, byte[] bytes) { if (bytes == null || name.equals("com.nexus.network.packets.Packet")) { return bytes; } ClassReader cr = new ClassReader(bytes); ClassNode classNode = new ClassNode(); cr.accept(classNode, 0); try { if (transformPacket(classNode)) { ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); classNode.accept(cw); return cw.toByteArray(); } return bytes; } catch (ClassCastException e) { } catch (Exception e) { e.printStackTrace(); } return bytes; }
private void fixFieldAccessInMethods() { List<MethodNode> methods = new LinkedList<MethodNode>(); for (MethodNode methodNode : (List<MethodNode>) classNode.methods) { MethodMetadata methodMetadata = classMetadata.getMethodMetadata(methodNode.name, methodNode.desc); if (methodMetadata.isTransactional()) { methodNode = fixMethod(methodNode); } methods.add(methodNode); } classNode.methods = methods; }
private void fixFields() { List<FieldNode> fields = new LinkedList<FieldNode>(); for (FieldNode fieldNode : (List<FieldNode>) classNode.fields) { FieldMetadata fieldMetadata = classMetadata.getFieldMetadata(fieldNode.name); if (fieldMetadata.hasFieldGranularity()) { String referenceDesc = findReferenceDesc(fieldNode.desc); FieldNode fixedFieldNode = new FieldNode( ACC_SYNTHETIC + ACC_FINAL + ACC_PUBLIC, fieldNode.name, referenceDesc, null, // signature null // value ); fields.add(fixedFieldNode); } else { fields.add(fieldNode); } } classNode.fields = fields; }
// 下記の想定で実装されています。 // 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; }
public static byte[] getBytesFromClassNodeNoMsg(ClassNode c) { ClassWriter w = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); c.accept(w); byte[] b = w.toByteArray(); return b; }
@Override public byte[] transform(String name, String transformedName, byte[] bytes) { if (bytes == null) { return null; } if (DEBUG) { FMLRelaunchLog.fine("Considering all methods and fields on %s (%s)\n", name, transformedName); } if (!modifiers.containsKey(name)) { return bytes; } ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); Collection<Modifier> mods = modifiers.get(name); for (Modifier m : mods) { if (m.modifyClassVisibility) { classNode.access = getFixedAccess(classNode.access, m); if (DEBUG) { System.out.println( String.format( "Class: %s %s -> %s", name, toBinary(m.oldAccess), toBinary(m.newAccess))); } continue; } if (m.desc.isEmpty()) { for (FieldNode n : classNode.fields) { if (n.name.equals(m.name) || m.name.equals("*")) { n.access = getFixedAccess(n.access, m); if (DEBUG) { System.out.println( String.format( "Field: %s.%s %s -> %s", name, n.name, toBinary(m.oldAccess), toBinary(m.newAccess))); } if (!m.name.equals("*")) { break; } } } } else { for (MethodNode n : classNode.methods) { if ((n.name.equals(m.name) && n.desc.equals(m.desc)) || m.name.equals("*")) { n.access = getFixedAccess(n.access, m); if (DEBUG) { System.out.println( String.format( "Method: %s.%s%s %s -> %s", name, n.name, n.desc, toBinary(m.oldAccess), toBinary(m.newAccess))); } if (!m.name.equals("*")) { break; } } } } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
private synchronized void load() { if (LOAD_LOCAL) { System.out.println("Loading local gamepack."); final File gamepack = new File("gamepack.jar"); if (!gamepack.exists()) { System.out.println("Unable to load local gamepack."); System.out.println(); return; } System.out.println("Successfully loaded local gamepack."); System.out.println(); System.out.println("Loading classes."); try { final JarFile jar = new JarFile(gamepack); final Enumeration<JarEntry> entries = jar.entries(); int loaded = 0; while (entries.hasMoreElements()) { final JarEntry entry = entries.nextElement(); String name = entry.getName(); if (!name.endsWith(".class") || name.contains("/")) { continue; } name = name.substring(0, name.length() - 6); final ClassReader cr = new ClassReader(jar.getInputStream(entry)); final ClassNode cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); classes.put(name, cn); loaded++; } System.out.println("Successfully loaded " + loaded + " classes."); } catch (final IOException e) { System.out.println("Unable to load classes."); } } else { final byte[] gamepack = getGamepack(); if (gamepack == null) { return; } System.out.println(); final Map<String, byte[]> innerpack = decryptGamepack(gamepack); if (innerpack == null) { return; } System.out.println(); System.out.println("Loading classes."); int loaded = 0; for (final Map.Entry<String, byte[]> entry : innerpack.entrySet()) { final String name = entry.getKey(); final ClassReader cr = new ClassReader(entry.getValue()); final ClassNode cn = new ClassNode(); cr.accept(cn, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); classes.put(name, cn); loaded++; } System.out.println("Successfully loaded " + loaded + " classes."); try { final FileOutputStream fos = new FileOutputStream(new File("gamepack.jar")); final JarOutputStream jos = new JarOutputStream(fos); for (final Map.Entry<String, ClassNode> entry : classes.entrySet()) { final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); final ClassNode cn = entry.getValue(); cn.accept(cw); jos.putNextEntry(new JarEntry(cn.name + ".class")); jos.write(cw.toByteArray()); jos.closeEntry(); } jos.close(); fos.close(); } catch (final Exception ignored) { } } System.out.println(); }
public byte[] patchOnUpdate(String name, byte[] bytes, boolean obfuscated) { RMLog.info("[EntityPlayer] [onUpdate] Patching", true); String targetMethodName = ""; if (obfuscated == true) targetMethodName = "h"; else targetMethodName = "onUpdate"; ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); Iterator<MethodNode> methods = classNode.methods.iterator(); while (methods.hasNext()) { MethodNode method = methods.next(); int invok_index = -1; if ((method.name.equals(targetMethodName) && method.desc.equals("()V"))) { AbstractInsnNode currentNode = null; AbstractInsnNode targetNode = null; Iterator<AbstractInsnNode> iter = method.instructions.iterator(); int index = -1; int GETFIELD_COUNT = 0; while (iter.hasNext()) { index++; currentNode = iter.next(); if (currentNode.getOpcode() == Opcodes.GETFIELD) { GETFIELD_COUNT++; if (GETFIELD_COUNT == 13) { targetNode = currentNode; invok_index = index; break; } } } if (targetNode == null || invok_index == -1) { RMLog.info( "[EntityPlayer] Did not find all necessary target nodes! ABANDON CLASS!", true); return bytes; } /* * mv.visitLineNumber(305, l19); * mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); * mv.visitVarInsn(ALOAD, 0); * -- mv.visitFieldInsn(GETFIELD, "net/minecraft/entity/player/EntityPlayer", "worldObj", "Lnet/minecraft/world/World;"); * mv.visitFieldInsn(GETFIELD, "net/minecraft/world/World", "isRemote", "Z"); * Label l21 = new Label(); * mv.visitJumpInsn(IFNE, l21); */ @SuppressWarnings("unused") AbstractInsnNode p1, p2, p3; p1 = method.instructions.get(invok_index - 1); // mv.visitVarInsn(ALOAD, 0); p2 = method.instructions.get(invok_index); // mv.visitFieldInsn(GETFIELD, // "net/minecraft/entity/player/EntityPlayer", "worldObj", // "Lnet/minecraft/world/World;"); p3 = method.instructions.get( invok_index + 1); // mv.visitFieldInsn(GETFIELD, "net/minecraft/world/World", "isRemote", // "Z"); // method.instructions.remove(p1); // method.instructions.remove(p2); // method.instructions.remove(p3); MethodInsnNode m1 = new MethodInsnNode( Opcodes.INVOKESTATIC, "net/roryclaasen/asm/rorysmodcore/transformer/StaticClass", "shouldWakeUp", "(Lnet/minecraft/entity/player/EntityPlayer;)Z", false); method.instructions.set(p2, m1); method.instructions.remove(p3); break; } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
public void visitEnd() { classNode.accept(cv); }
@SuppressWarnings("unchecked") private void modify(ClassNode node) { if (!mappings.containsKey(node.name)) return; JSONObject object = mappings.get(node.name); String identity = (String) object.get("identity"); String parentOverride = (String) object.get("parent_override"); if (parentOverride != null && !parentOverride.equals("null")) { node.superName = parentOverride; if (node.superName.contains("Canvas")) { for (MethodNode mn : (List<MethodNode>) node.methods) { if (mn.name.equals("<init>")) { for (AbstractInsnNode insn : mn.instructions.toArray()) { if (insn.getOpcode() == Opcodes.INVOKESPECIAL) { MethodInsnNode min = (MethodInsnNode) insn; if (min.owner.contains("Canvas")) { min.owner = node.superName; } } } } } } // System.out.println("\t"+node.name+" parent changed to "+parentOverride); } JSONArray interfaces = (JSONArray) object.get("interfaces"); for (int i = 0; i < interfaces.size(); i++) { if (!node.interfaces.contains(interfaces.get(i))) { // System.out.println("\tAdded interface " + interfaces.get(i) + " to " + identity + " (" + // node.name + ")"); node.interfaces.add(interfaces.get(i)); } } // remove interfaces not specified for (int i = 0; i < node.interfaces.size(); i++) { if (!interfaces.contains(node.interfaces.get(i))) { // System.out.println("\tRemoved interface " + node.interfaces.get(i) + " from " + identity // + " (" + node.name + ")"); node.interfaces.remove(i); } } if (identity.equals("Renderable")) { for (MethodNode mn : (List<MethodNode>) node.methods) { if ((mn.access & Opcodes.ACC_STATIC) != 0) { continue; } if (!mn.desc.endsWith("V")) { continue; } InstructionSearcher searcher = new InstructionSearcher(mn.instructions, 0, Opcodes.INVOKEVIRTUAL, Opcodes.ASTORE); if (searcher.match()) { InstructionSearcher search = new InstructionSearcher(mn.instructions, 0, Opcodes.INVOKEVIRTUAL); AbstractInsnNode[] primMatches = searcher.getMatches().get(0); if (search.match()) { AbstractInsnNode[] matches = search.getMatches().get(1); VarInsnNode var = new VarInsnNode(Opcodes.ALOAD, 0); VarInsnNode var2 = new VarInsnNode( Opcodes.ALOAD, ((VarInsnNode) primMatches[primMatches.length - 1]).var); mn.instructions.insert(matches[matches.length - 1], var); mn.instructions.insert(var, var2); mn.instructions.insert( var2, new MethodInsnNode( Opcodes.INVOKESTATIC, "org/vinsert/bot/script/callback/ModelCallback", "callback", "(Lorg/vinsert/insertion/IRenderable;Lorg/vinsert/insertion/IModel;)V")); // System.out.println("\tInserted model callback to "+node.name+"."+mn.name); } } } } // if (identity.equals("GameObject")) { // for (MethodNode mn : (List<MethodNode>) node.methods) { // if ((mn.access & Opcodes.ACC_STATIC) != 0) { // continue; // } // // if (mn.desc.endsWith("V")) { // continue; // } // // InstructionSearcher searcher = new InstructionSearcher(mn.instructions, 10, Opcodes.LDC, // Opcodes.IMUL, Opcodes.LDC, Opcodes.INVOKEVIRTUAL, Opcodes.ARETURN); // // if (searcher.match()) { // // AbstractInsnNode[] matches = searcher.getMatches().get(0); // // VarInsnNode var = new VarInsnNode(Opcodes.ALOAD, 0); // VarInsnNode var2 = new VarInsnNode(Opcodes.ALOAD, ((VarInsnNode) matches[matches.length - // 1]).var); //// // mn.instructions.insert(mn.instructions.get(mn.instructions.size() - 1), var); // mn.instructions.insert(var, var2); // mn.instructions.insert(var2, new MethodInsnNode(Opcodes.INVOKESTATIC, // "com/hijackrs/bot/script/callback/ModelCallback", "callback", // "(Lcom/hijackrs/insertion/Renderable;Lcom/hijackrs/insertion/Model;)V")); // System.out.println("\tInserted model callback to "+node.name+"."+mn.name); // } // } // } JSONArray mappings = (JSONArray) object.get("mappings"); for (int i = 0; i < mappings.size(); i++) { JSONObject entry = (JSONObject) mappings.get(i); String parent = (String) entry.get("parent"); String name = (String) entry.get("name"); String getterName = (String) entry.get("identity"); String signature = (String) entry.get("signature"); String fieldSignature = (String) entry.get("field_signature"); boolean isStatic = (Boolean) entry.get("static"); int opLoad = ((Number) entry.get("op_load")).intValue(); int opReturn = ((Number) entry.get("op_return")).intValue(); int modBits = ((Number) entry.get("mod_bits")).intValue(); int modDirect = ((Number) entry.get("mod_value")).intValue(); boolean modInverse = (Boolean) entry.get("mod_inverse"); insert( node, parent, name, getterName, signature, fieldSignature, isStatic, opLoad, opReturn, modBits, modDirect, modInverse); } }
@Override public byte[] transform(String name, String transformedName, byte[] basicClass) { if (!name.startsWith("lc.")) return basicClass; ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(basicClass); classReader.accept(classNode, 0); List<FieldNode> fields = classNode.fields; if (fields == null || fields.size() == 0) return basicClass; HashMap<String, String> fieldToClazzMap = new HashMap<String, String>(); Iterator<FieldNode> iq = fields.iterator(); while (iq.hasNext()) { FieldNode field = iq.next(); AnnotationNode hintNode = ASMAssist.findAnnotation(field, "Llc/api/defs/HintProvider;"); if (hintNode != null) { Side theSide = FMLCommonHandler.instance().getSide(); if (theSide == Side.CLIENT) { String className = ASMAssist.findValue(hintNode, "clientClass"); if (className != null) fieldToClazzMap.put(field.name, className.replace(".", "/")); } else { String className = ASMAssist.findValue(hintNode, "serverClass"); if (className != null) fieldToClazzMap.put(field.name, className.replace(".", "/")); } } } if (fieldToClazzMap.size() != 0) { LCLog.debug("Adding %s hint field initializer mappings.", fieldToClazzMap.size()); Iterator<MethodNode> methods = classNode.methods.iterator(); MethodNode initMethod = null; while (methods.hasNext()) { MethodNode method = methods.next(); if (method.name.equals("<init>")) { initMethod = method; break; } } AbstractInsnNode lastInsn = null; if (initMethod == null) { initMethod = new MethodNode(Opcodes.ACC_PUBLIC, "<init>", "()V", "", null); lastInsn = new InsnNode(Opcodes.RETURN); initMethod.instructions.add(lastInsn); } else for (Iterator<AbstractInsnNode> insns = initMethod.instructions.iterator(); insns.hasNext(); ) { AbstractInsnNode node = insns.next(); if (node.getOpcode() == Opcodes.RETURN) lastInsn = node; } for (Entry<String, String> mapping : fieldToClazzMap.entrySet()) { LCLog.debug( "Adding mapping for hint %s to class initializer %s.", mapping.getKey(), mapping.getValue()); initMethod.instructions.insertBefore(lastInsn, new VarInsnNode(Opcodes.ALOAD, 0)); initMethod.instructions.insertBefore( lastInsn, new TypeInsnNode(Opcodes.NEW, mapping.getValue())); initMethod.instructions.insertBefore(lastInsn, new InsnNode(Opcodes.DUP)); initMethod.instructions.insertBefore( lastInsn, new MethodInsnNode(Opcodes.INVOKESPECIAL, mapping.getValue(), "<init>", "()V", false)); initMethod.instructions.insertBefore( lastInsn, new FieldInsnNode( Opcodes.PUTFIELD, name.replace(".", "/"), mapping.getKey(), "Llc/common/IHintProvider;")); } if (initMethod.maxStack < fieldToClazzMap.size() * 4) initMethod.maxStack += fieldToClazzMap.size() * 4; } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
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(); }
// too lazy to deobfuscate all network/chat stuff, use info from method // calls to create new send message function private void createSendMessage(ClassNode cn) { Pattern p = new PatternBuilder() .add( new InstructionElement(INVOKESTATIC), new AnyElement(), new LdcElement(new LdcInsnNode("Chat")), new InstructionElement(INVOKEVIRTUAL)) .build(); MethodInsnNode newBuilder = null; MethodInsnNode setChatText = null; MethodInsnNode ebola1 = null; MethodInsnNode ebola2 = null; MethodInsnNode ebola3 = null; MethodInsnNode ebola4 = null; MethodInsnNode ebola5 = null; MethodInsnNode ebola6 = null; MethodInsnNode ebola7 = null; for (MethodNode mn : cn.methods) { if (!p.contains(mn.instructions)) continue; int offset = p.getOffset(mn.instructions); newBuilder = (MethodInsnNode) mn.instructions.get(offset - 9); // newbuilder // then var insn of parameter, ldc or w/e setChatText = (MethodInsnNode) mn.instructions.get(offset - 7); // setchattext ebola1 = (MethodInsnNode) mn.instructions.get(offset - 6); // U a ebola2 = (MethodInsnNode) mn.instructions.get(offset - 5); // U p ebola3 = (MethodInsnNode) mn.instructions.get(offset - 4); // Player // r ebola4 = (MethodInsnNode) mn.instructions.get(offset - 3); // setMapID ebola5 = (MethodInsnNode) mn.instructions.get(offset - 2); // build // store that crap ebola6 = (MethodInsnNode) mn.instructions.get(offset); // i e // load crap again // LDC "Chat" ebola7 = (MethodInsnNode) mn.instructions.get(offset + 3); // i a } { MethodVisitor mv = cn.visitMethod(ACC_PUBLIC, "sendChatMessage", "(Ljava/lang/String;)V", null, null); mv.visitMethodInsn( INVOKESTATIC, newBuilder.owner, newBuilder.name, newBuilder.desc, newBuilder.itf); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn( INVOKEVIRTUAL, setChatText.owner, setChatText.name, setChatText.desc, setChatText.itf); mv.visitMethodInsn(INVOKESTATIC, ebola1.owner, ebola1.name, ebola1.desc, ebola1.itf); mv.visitMethodInsn(INVOKEVIRTUAL, ebola2.owner, ebola2.name, ebola2.desc, ebola2.itf); mv.visitMethodInsn(INVOKEVIRTUAL, ebola3.owner, ebola3.name, ebola3.desc, ebola3.itf); mv.visitMethodInsn(INVOKEVIRTUAL, ebola4.owner, ebola4.name, ebola4.desc, ebola4.itf); mv.visitMethodInsn(INVOKEVIRTUAL, ebola5.owner, ebola5.name, ebola5.desc, ebola5.itf); mv.visitVarInsn(ASTORE, 2); mv.visitMethodInsn(INVOKESTATIC, ebola6.owner, ebola6.name, ebola6.desc, ebola6.itf); mv.visitVarInsn(ALOAD, 2); mv.visitLdcInsn("Chat"); mv.visitMethodInsn(INVOKEVIRTUAL, ebola7.owner, ebola7.name, ebola7.desc, ebola7.itf); mv.visitInsn(RETURN); mv.visitMaxs(2, 2); mv.visitEnd(); } }
@Override public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (classBeingRedefined != null) { return null; } if (className.startsWith("java/") || className.startsWith("javax/") || className.startsWith("sun/")) { return null; } List<MethodNode> coroutineMethodsInCurrentClass; boolean debug = generateDebugCode; boolean print = printCode; boolean verify = runVerification; boolean outputBin = generateBinaryOutput; boolean asmComputeFrames = overrideFrames; if (!detectCoroutineClasses) { int classnameIndex = Arrays.binarySearch(coroutineEnabledClassnames, className); if (classnameIndex < 0) { // search package String packageName = className; int indexOfSlash; while ((indexOfSlash = packageName.lastIndexOf('/')) != -1) { packageName = packageName.substring(0, indexOfSlash); classnameIndex = Arrays.binarySearch(coroutineEnabledClassnames, packageName); if (classnameIndex >= 0) { break; } } if (classnameIndex < 0) return null; } debug = debugMode[classnameIndex]; print = printMode[classnameIndex]; verify = verifyMode[classnameIndex]; outputBin = outputBinMode[classnameIndex]; asmComputeFrames = overrideFramesMode[classnameIndex]; } boolean log = logger.isLoggable(Level.FINEST); if (log) { logger.finest(className + ": Analyzing"); } ClassReader asmClassReader = new ClassReader(classfileBuffer); ClassNode cn = new ClassNode(); asmClassReader.accept(cn, debug ? 0 : ClassReader.SKIP_DEBUG); ClassAnalyzer analyzer = new ClassAnalyzer(cn); analyzer.analyze(); coroutineMethodsInCurrentClass = analyzer.getCoroutineMethods(); if (coroutineMethodsInCurrentClass.isEmpty()) { return null; } if (log) { logger.finest( className + ": Instrumenting coroutines " + methodNodeListToString(coroutineMethodsInCurrentClass)); } ClassWriter asmClassWriter = new ClassWriter( (asmComputeFrames ? ClassWriter.COMPUTE_FRAMES : 0) | ClassWriter.COMPUTE_MAXS); ClassVisitor cv = asmClassWriter; byte[] instrumentedClassContents; try { if (print) { try { cv = createTracer(className, cv); } catch (FileNotFoundException e) { throw new CoroutineGenerationException("Unable to write trace file ", e); } } new ClassTransformer(cn, coroutineMethodsInCurrentClass, debug).transform(); cn.accept(cv); instrumentedClassContents = asmClassWriter.toByteArray(); if (verify) { verifyClass(className, new ClassReader(instrumentedClassContents), print); } if (outputBin) { dumpClass(className + "Instrumented", instrumentedClassContents); } } catch (IllegalStateException e) { logger.log(Level.WARNING, "Verification failed", e); return null; } catch (IllegalArgumentException e) { logger.log(Level.WARNING, "Verification failed", e); return null; } catch (CoroutineGenerationException e) { logger.warning(e.getMessage()); return null; } catch (Throwable t) { logger.log( Level.SEVERE, "Coroutine generation ended abruptly. This may be a bug in the package itself. Details below:", t); return null; } return instrumentedClassContents; }
@Override public byte[] transform(String name, String transformedName, byte[] bytes) { if (bytes == null) { return null; } boolean makeAllPublic = FMLDeobfuscatingRemapper.INSTANCE.isRemappedClass(name); if (DEBUG) { FMLRelaunchLog.fine( "Considering all methods and fields on %s (%s): %b\n", name, transformedName, makeAllPublic); } if (!makeAllPublic && !modifiers.containsKey(name)) { return bytes; } ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); if (makeAllPublic) { // class Modifier m = new Modifier(); m.targetAccess = ACC_PUBLIC; m.modifyClassVisibility = true; modifiers.put(name, m); // fields m = new Modifier(); m.targetAccess = ACC_PUBLIC; m.name = "*"; modifiers.put(name, m); // methods m = new Modifier(); m.targetAccess = ACC_PUBLIC; m.name = "*"; m.desc = "<dummy>"; modifiers.put(name, m); if (DEBUG) { System.out.printf("Injected all public modifiers for %s (%s)\n", name, transformedName); } } Collection<Modifier> mods = modifiers.get(name); for (Modifier m : mods) { if (m.modifyClassVisibility) { classNode.access = getFixedAccess(classNode.access, m); if (DEBUG) { System.out.println( String.format( "Class: %s %s -> %s", name, toBinary(m.oldAccess), toBinary(m.newAccess))); } continue; } if (m.desc.isEmpty()) { for (FieldNode n : classNode.fields) { if (n.name.equals(m.name) || m.name.equals("*")) { n.access = getFixedAccess(n.access, m); if (DEBUG) { System.out.println( String.format( "Field: %s.%s %s -> %s", name, n.name, toBinary(m.oldAccess), toBinary(m.newAccess))); } if (!m.name.equals("*")) { break; } } } } else { for (MethodNode n : classNode.methods) { if ((n.name.equals(m.name) && n.desc.equals(m.desc)) || m.name.equals("*")) { n.access = getFixedAccess(n.access, m); if (DEBUG) { System.out.println( String.format( "Method: %s.%s%s %s -> %s", name, n.name, n.desc, toBinary(m.oldAccess), toBinary(m.newAccess))); } if (!m.name.equals("*")) { break; } } } } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }