How to change Java bytecode using ASM 4.0

I am new to ASM. I have been working on this ASM framework for a week. I have seen tutorials on the net regarding parsing a class and creating a .class file from scratch. But I cannot keep track of how to modify an existing class in ASM.

Please help me.

I was unable to execute a thread of execution between ClassVisitor, ClassWriter and ClassReader.

Please solve my problem by providing me an ASM example for the following code.

public class ClassName { public void showOne() { System.out.println("Show One Method"); } public static void main(String[] args) { ClassName c=new ClassName(); c.showOne(); } } 

The above class should be changed as follows:

 public class ClassName { public void showOne() { System.out.println("Show One Method"); } public void showTwo() { System.out.println("Show Two Method"); } public static void main(String[] args) { ClassName c=new ClassName(); c.showOne(); c.showTwo(); } } 

What should be the ASM code to change it?

I used the ASMifier tool to generate the code. But I do not know where to apply it.

Please help me. +

+5
source share
1 answer

Your requirements are a little unproven. The following is an example of a program that uses the ASM visitor API to convert a class, supposedly having the structure of your question, to the resulting class. I added a convenience method that takes a byte array and returns an array of bytes. This method can be used in both cases, the static conversion applied to class files on disk, as well as in the Instrumentation agent.

When combining ClassWriter with ClassVisitor passed to ClassReader , as shown below, it automatically replicates every function of the source class, so you only need to override these methods in which you want to apply the changes.

Here visitMethod redefined to intercept when the main method is encountered to modify it, and visitEnd redefined to add a completely new showTwo method. MainTransformer will intercept RETURN statements (there should be only one in your example) to insert a showTwo call showTwo front of it.

 import org.objectweb.asm.*; import org.objectweb.asm.commons.GeneratorAdapter; public class MyTransformer extends ClassVisitor { public static byte[] transform(byte[] b) { final ClassReader classReader = new ClassReader(b); final ClassWriter cw = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); classReader.accept(new MyTransformer(cw), ClassReader.EXPAND_FRAMES); return cw.toByteArray(); } public MyTransformer(ClassVisitor cv) { super(Opcodes.ASM5, cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor v=super.visitMethod(access, name, desc, signature, exceptions); if(name.equals("main") && desc.equals("([Ljava/lang/String;)V")) v=new MainTransformer(v, access, name, desc, signature, exceptions); return v; } @Override public void visitEnd() { appendShowTwo(); super.visitEnd(); } private void appendShowTwo() { final MethodVisitor defVisitor = super.visitMethod( Opcodes.ACC_PUBLIC, "showTwo", "()V", null, null); defVisitor.visitCode(); defVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); defVisitor.visitLdcInsn("Show Two Method"); defVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); defVisitor.visitInsn(Opcodes.RETURN); defVisitor.visitMaxs(0, 0); defVisitor.visitEnd(); } class MainTransformer extends GeneratorAdapter { MainTransformer(MethodVisitor delegate, int access, String name, String desc, String signature, String[] exceptions) { super(Opcodes.ASM5, delegate, access, name, desc); } @Override public void visitInsn(int opcode) { if(opcode==Opcodes.RETURN) { // before return insert c.showTwo(); super.visitVarInsn(Opcodes.ALOAD, 1); // variable c super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "ClassName", "showTwo", "()V", false); } super.visitInsn(opcode); } } } 
+6
source

Source: https://habr.com/ru/post/1201383/


All Articles