java ASM

2016-08-16

Java ASM
我们知道Java是静态语言,而pythonruby是动态语言Java程序一旦写好很难在运行时更改类的行为,而pythonruby可以。
不过基于bytecode层面上我们可以做一些手脚,来使Java程序多一些灵活性和MagicASM就是这样一个应用广泛的开源库。

ASM is a Java bytecode manipulation framework. It can be used to dynamically generate stub classes or other proxy classes,
directly in binary form, or to dynamically modify classes at load time, i.e., just before they are loaded into the Java
Virtual Machine.

ASM
完成了
BCELSERP同样的功能,但ASM
只有30k,而后两者分别是350k150kapache真是越来越过气了。

让我们来看一个ASM的简单例子Helloworld.java,它生成一个Example类和一个main方法,main方法打印"Hello world!"语句:

Java代码

  1. import java.io.FileOutputStream;   
  2. import java.io.PrintStream;   
  3.   
  4. import org.objectweb.asm.ClassWriter;   
  5. import org.objectweb.asm.MethodVisitor;   
  6. import org.objectweb.asm.Opcodes;   
  7. import org.objectweb.asm.Type;   
  8. import org.objectweb.asm.commons.GeneratorAdapter;   
  9. import org.objectweb.asm.commons.Method;   
  10.   
  11. public class Helloworld extends ClassLoader implements Opcodes {   
  12.   
  13.   public static void main(final String args[]) throws Exception {   
  14.   
  15.     // creates a ClassWriter for the Example public class,   
  16.     // which inherits from Object   
  17.   
  18.      ClassWriter cw = new ClassWriter(0);   
  19.      cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);   
  20.      MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,   
  21.         null);   
  22.      mw.visitVarInsn(ALOAD, 0);   
  23.      mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");   
  24.      mw.visitInsn(RETURN);   
  25.      mw.visitMaxs(1, 1);   
  26.      mw.visitEnd();   
  27.      mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",   
  28.         "([Ljava/lang/String;)V", null, null);   
  29.      mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out",   
  30.         "Ljava/io/PrintStream;");   
  31.      mw.visitLdcInsn("Hello world!");   
  32.      mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",   
  33.         "(Ljava/lang/String;)V");   
  34.      mw.visitInsn(RETURN);   
  35.      mw.visitMaxs(2, 2);   
  36.      mw.visitEnd();   
  37.     byte[] code = cw.toByteArray();   
  38.      FileOutputStream fos = new FileOutputStream("Example.class");   
  39.      fos.write(code);   
  40.      fos.close();   
  41.      Helloworld loader = new Helloworld();   
  42.      Class exampleClass = loader   
  43.          .defineClass("Example", code, 0, code.length);   
  44.      exampleClass.getMethods()[0].invoke(null, new Object[] { null });   
  45.   
  46.     // ------------------------------------------------------------------------   
  47.     // Same example with a GeneratorAdapter (more convenient but slower)   
  48.     // ------------------------------------------------------------------------   
  49.   
  50.      cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);   
  51.      cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);   
  52.      Method m = Method.getMethod("void <init> ()");   
  53.      GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null,   
  54.          cw);   
  55.      mg.loadThis();   
  56.      mg.invokeConstructor(Type.getType(Object.class), m);   
  57.      mg.returnValue();   
  58.      mg.endMethod();   
  59.      m = Method.getMethod("void main (String[])");   
  60.      mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);   
  61.      mg.getStatic(Type.getType(System.class), "out", Type   
  62.          .getType(PrintStream.class));   
  63.      mg.push("Hello world!");   
  64.      mg.invokeVirtual(Type.getType(PrintStream.class), Method   
  65.          .getMethod("void println (String)"));   
  66.      mg.returnValue();   
  67.      mg.endMethod();   
  68.      cw.visitEnd();   
  69.      code = cw.toByteArray();   
  70.      loader = new Helloworld();   
  71.      exampleClass = loader.defineClass("Example", code, 0, code.length);   
  72.      exampleClass.getMethods()[0].invoke(null, new Object[] { null });   
  73.    }   
  74. }  

import java.io.FileOutputStream;

import java.io.PrintStream;

 

import org.objectweb.asm.ClassWriter;

import org.objectweb.asm.MethodVisitor;

import org.objectweb.asm.Opcodes;

import org.objectweb.asm.Type;

import org.objectweb.asm.commons.GeneratorAdapter;

import org.objectweb.asm.commons.Method;

 

public class Helloworld extends ClassLoader implements Opcodes {

 

  public static void main(final String args[]) throws Exception {

 

    // creates a ClassWriter for the Example public class,

    // which inherits from Object

 

    ClassWriter cw = new ClassWriter(0);

    cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

    MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,

        null);

    mw.visitVarInsn(ALOAD, 0);

    mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");

    mw.visitInsn(RETURN);

    mw.visitMaxs(1, 1);

    mw.visitEnd();

    mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",

        "([Ljava/lang/String;)V", null, null);

    mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out",

        "Ljava/io/PrintStream;");

    mw.visitLdcInsn("Hello world!");

    mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",

        "(Ljava/lang/String;)V");

    mw.visitInsn(RETURN);

    mw.visitMaxs(2, 2);

    mw.visitEnd();

    byte[] code = cw.toByteArray();

    FileOutputStream fos = new FileOutputStream("Example.class");

    fos.write(code);

    fos.close();

    Helloworld loader = new Helloworld();

    Class exampleClass = loader

        .defineClass("Example", code, 0, code.length);

    exampleClass.getMethods()[0].invoke(null, new Object[] { null });

 

    // ------------------------------------------------------------------------

    // Same example with a GeneratorAdapter (more convenient but slower)

    // ------------------------------------------------------------------------

 

    cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

    Method m = Method.getMethod("void <init> ()");

    GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null,