`

asm字节码操作 方法的动态修改增加

 
阅读更多

asm 4.0 版本

http://forge.ow2.org/plugins/scmsvn/index.php?group_id=23

 

asm是java的字节码操作框架,可以动态查看类的信息,动态修改,删除,增加类的方法。

 

下面基于4.0版本的一个使用示例,演示了对类Foo进行修改方法名称,增加方法,修改方法内容等 

 

 

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class AsmExample extends ClassLoader implements Opcodes{
    
    public static  class Foo {
        public static void execute() {
            System.out.println("test changed method name");
        }
        public static void changeMethodContent() {
            System.out.println("test change method");
        }
    }

    public static void main(String[] args) throws IOException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException {
        
        ClassReader cr = new ClassReader(Foo.class.getName());
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new MethodChangeClassAdapter(cw);
        cr.accept(cv, Opcodes.ASM4);
        
        //新增加一个方法
        MethodVisitor mw= cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
                "add",
                "([Ljava/lang/String;)V",
                null,
                null);
        // pushes the 'out' field (of type PrintStream) of the System class
        mw.visitFieldInsn(GETSTATIC,
                "java/lang/System",
                "out",
                "Ljava/io/PrintStream;");
        // pushes the "Hello World!" String constant
        mw.visitLdcInsn("this is add method print!");
        // invokes the 'println' method (defined in the PrintStream class)
        mw.visitMethodInsn(INVOKEVIRTUAL,
                "java/io/PrintStream",
                "println",
                "(Ljava/lang/String;)V");
        mw.visitInsn(RETURN);
        // this code uses a maximum of two stack elements and two local
        // variables
        mw.visitMaxs(0, 0);
        mw.visitEnd();
        
        // gets the bytecode of the Example class, and loads it dynamically
        byte[] code = cw.toByteArray();


        AsmExample loader = new AsmExample();
        Class<?> exampleClass = loader.defineClass(Foo.class.getName(), code, 0, code.length);

        for(Method method:  exampleClass.getMethods()){
            System.out.println(method);
        }
        
        System.out.println("*************");
        
        
        // uses the dynamically generated class to print 'Helloworld'
        exampleClass.getMethods()[0].invoke(null, null);  //調用changeMethodContent,修改方法內容
        
        System.out.println("*************");
        
        
        exampleClass.getMethods()[1].invoke(null, null); //調用execute,修改方法名
        
        // gets the bytecode of the Example class, and loads it dynamically

        FileOutputStream fos = new FileOutputStream("e:\\logs\\Example.class");
        fos.write(code);
        fos.close();
    }
    
    static class MethodChangeClassAdapter extends ClassVisitor implements Opcodes {

        public MethodChangeClassAdapter(final ClassVisitor cv) {
            super(Opcodes.ASM4, cv);
        }

        @Override
        public void visit(
            int version,
            int access,
            String name,
            String signature,
            String superName,
            String[] interfaces)
        {
            if (cv != null) {
                cv.visit(version, access, name, signature, superName, interfaces);
            }
        }
        
        @Override
        public MethodVisitor visitMethod(
            int access,
            String name,
            String desc,
            String signature,
            String[] exceptions)
        {
            if (cv != null && "execute".equals(name)) { //当方法名为execute时,修改方法名为execute1
                return cv.visitMethod(access, name + "1", desc, signature, exceptions);
            }
     
            if("changeMethodContent".equals(name))  //此处的changeMethodContent即为需要修改的方法  ,修改方法內容
            {  
                MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);//先得到原始的方法  
                MethodVisitor newMethod = null;  
                newMethod = new AsmMethodVisit(mv); //访问需要修改的方法  
                return newMethod;  
            }  
            if (cv != null) {
                return cv.visitMethod(access, name, desc, signature, exceptions);
            }
            
            return null;
        }


    }
    
     static  class AsmMethodVisit extends MethodVisitor {

        public AsmMethodVisit(MethodVisitor mv) {
            super(Opcodes.ASM4, mv);    
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
            super.visitMethodInsn(opcode, owner, name, desc);
        }

        @Override
        public void visitCode() {       
            //此方法在访问方法的头部时被访问到,仅被访问一次
            //此处可插入新的指令
            super.visitCode();
        }
        
        @Override
        public void visitInsn(int opcode) {     
            //此方法可以获取方法中每一条指令的操作类型,被访问多次
            //如应在方法结尾处添加新指令,则应判断:
            if(opcode == Opcodes.RETURN)
            {
                // pushes the 'out' field (of type PrintStream) of the System class
                mv.visitFieldInsn(GETSTATIC,
                        "java/lang/System",
                        "out",
                        "Ljava/io/PrintStream;");
                // pushes the "Hello World!" String constant
                mv.visitLdcInsn("this is a modify method!");
                // invokes the 'println' method (defined in the PrintStream class)
                mv.visitMethodInsn(INVOKEVIRTUAL,
                        "java/io/PrintStream",
                        "println",
                        "(Ljava/lang/String;)V");
//                mv.visitInsn(RETURN);
            }
            super.visitInsn(opcode);
        }
    }

}

 

输出:

 

add方法是新增的,execute方法名改为execute1,changeMethodContent方法修改后增加了输出this is a modify method!

 

 

public static void AsmExample$Foo.changeMethodContent()
public static void AsmExample$Foo.execute1()
public static void AsmExample$Foo.add(java.lang.String[])
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
*************
test change method
this is a modify method!
*************
test changed method name
 

我们把最终的字节码保存到文件中e:\\logs\\Example.class中,再用反编译工具java decompiler 查看最终的生成的源码:

 

最终的类如下:

 

 

import java.io.PrintStream;

public class AsmExample$Foo
{
  public static void execute1()
  {
    System.out.println("test changed method name");
  }
  public static void changeMethodContent() {
    System.out.println("test change method");
    System.out.println("this is a modify method!");
  }

  public static void add(String[] paramArrayOfString)
  {
    System.out.println("this is add method print!");
  }
}
 

 

接下来再慢慢研究asm里面对字节码的操作,还有其他框架是如果使用asm的。

1
3
分享到:
评论

相关推荐

    ASM字节码操作简单实例

    ASM字节码库是Java字节码操作的强大工具,它允许程序员在运行时动态生成类或者增强已有类的功能。在本实例中,我们将探讨如何利用ASM实现简单的面向切面编程(AOP)功能,这是一种在不修改源代码的情况下,添加额外...

    ASM操作字节码,动态生成Java类class文件

    ASM是一个开源的Java字节码操控和分析框架,它能够用来动态生成类或者增强已有类的功能。ASM可以被用来创建Java代理、实现元编程、甚至深入到Java虚拟机(JVM)层面进行性能优化。在Java开发中,ASM库允许我们直接...

    ASM 字节码修改工具中文帮助手册

    ### ASM 字节码修改工具中文帮助手册知识点概览 #### 1. ASM 4.0 简介 - **版本信息**: ASM 4.0 是一个 Java 字节码操作和分析框架,由 Eric Bruneton 开发并维护,版权归属 Eric Bruneton(2007-2011)。 - **...

    Android-埋点计时Gradle插件利用ASM插入字节码

    它可以直接生成和修改Java类的字节码,从而实现诸如动态代理、代码混淆、性能监控等功能。在这个插件中,ASM被用来在运行时动态插入代码,记录并打印指定类或注解方法的执行时间。 插件的使用流程大致如下: 1. ...

    演示Asm字节码插桩asmd-demo-master.zip

    Asm字节码插桩是一种在Java字节码层面对程序进行动态修改的技术,它允许开发者在不修改源代码的情况下,向已有的类或方法中插入额外的代码。这种技术在性能监控、日志记录、行为追踪、代码优化等领域有广泛应用。在...

    asm字节插桩asm-master.zip

    ASM字节码插桩是一种在Java字节码级别进行动态代码增强的技术,广泛应用于性能监控、日志记录、安全审计等领域。ASM是一个底层的Java字节码操控和分析框架,它可以直接转换Java类和.dex文件,并能被用来动态生成类...

    java字节码框架ASM操作字节码的方法浅析

    Java字节码框架ASM是一个强大的库,它允许程序员在运行时动态生成和修改Java类和接口的字节码。ASM提供了对JVM字节码的底层访问,这使得开发者能够实现诸如AOP(面向切面编程)或者元编程等高级功能。 首先,我们...

    [字节码系列]ObjectWeb ASM构建Method Monitor

    ObjectWeb ASM是一个轻量级且强大的Java字节码操控和分析框架,它允许程序员动态生成和修改类的字节码。本文将深入探讨如何使用ASM库来构建一个Method Monitor,以便监控和记录应用程序中方法的调用。 首先,了解...

    Java字节码和asm入门资料

    ASM是一个开源的Java字节码操控和分析框架,它可以直接用来生成和修改Java类文件,是Java动态代理和字节码增强技术的重要工具。在深入学习Java字节码和ASM之前,我们需要先理解Java编译和运行的基本过程。 1. **...

    Android字节码插桩

    总结起来,ASM作为强大的字节码操作工具,为Android开发者提供了字节码插桩的能力,使得我们可以在不修改源代码的情况下实现各种功能增强,这对于优化和调试Android应用具有极大的价值。同时,掌握ASM也能提升开发者...

    Android-Android无痕埋点框架使用ASM插桩实现

    ASM是一个低级别的库,可以直接操作Java字节码,提供了一种动态生成和修改类的方法。它通过ClassWriter、ClassReader、MethodVisitor等接口,允许开发者对字节码进行读取、修改和写入。ASM的核心在于它的事件驱动...

    JAVA字节码操作库 BCEL

    它为开发者提供了一种深入理解与操作Java类文件的底层机制,允许分析、创建、修改和优化字节码。在软件工程中,BCEL在诸如动态代理、代码分析、代码生成以及逆向工程等领域有广泛应用。 **一、BCEL的基本概念** 1....

    cglib,字节码生成库是生成和转换Java字节码的高级API。它被aop、测试、数据访问框架用来生成动态代理对象和拦截字段访问。.zip

    CGlib库利用ASM库(一个底层的Java字节码操作和分析框架)来生成和修改字节码。通过这种方式,开发者可以在程序运行时动态地创建新的类或修改现有类的行为,而无需重新编译源代码。 **动态代理** CGlib常用于实现...

    字节码编程和操作系统等知识文档

    Javaagent技术允许我们在JVM启动时附加一个代理程序,这个代理可以修改类的字节码,从而在不改变原有代码的情况下,实现对方法调用的拦截和处理。 字节码编程不仅是Java开发者的必备技能之一,它也是深入理解JVM...

    通过Android字节码插桩插件实现Android端无埋点(或自动埋点),并且支持根据配置文件实现业务数据的自动采集。.zip

    字节码插桩是一种动态或静态修改字节码的技术,用于在运行时或编译时插入额外的代码。在Android中,我们可以使用ASM、Dexmaker或ByteBuddy等库来实现字节码插桩。LazierTracker就是基于这些技术,它能够在运行时动态...

    Java字节码实现Aop

    Java字节码实现AOP(面向切面编程)是一种在程序运行时动态插入代码的技术,它使得我们可以在不修改原有代码的情况下,增加新的功能或监控已有功能。在Java中,AOP通常通过代理模式和字节码操作来实现,如Spring AOP...

    字节码实战包含class,字节码.zip

    例如,CGLIB、ASM等库可以在运行时生成和修改字节码,实现动态类的创建和功能增强。 7. **JVM内存模型与字节码**: 字节码执行与JVM的内存模型密切相关,包括堆、栈、方法区、本地方法栈等。理解这些概念有助于...

    ASM插桩在Android项目中的应用

    通过ASM,开发者可以直接操作字节码,实现对方法的插入、删除或修改。这对于创建AOP(面向切面编程)框架、性能监控工具、代码混淆等场景非常有用。 在Android开发中,ASM插桩主要应用于以下几个方面: 1. 性能...

    Java Classloading Mechanism : ClassLoader & ASM & 动态字节码增强

    总结起来,Java的类加载机制保证了程序的稳定运行,而ASM库则提供了对字节码的直接操作能力,使得我们能够在运行时动态地修改类的行为。掌握这两者,开发者可以更好地理解和定制Java应用的运行过程,提升程序的灵活...

    修改class字节码需要的工具.zip

    在进行字节码修改时,需要谨慎操作,因为错误的修改可能导致程序崩溃或者运行异常。通常,这种操作是在对现有代码有深入理解或需要进行特定优化时进行的。使用这些工具,开发者可以实现如方法内联、优化循环、替换...

Global site tag (gtag.js) - Google Analytics