ASM动态操作方法(增改)

2024-02-13 04:32
文章标签 动态 操作方法 asm 增改

本文主要是介绍ASM动态操作方法(增改),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

package myASM;public class Foo {public  void execute(){System.out.println("test changed method name");}public  void changeMethodContent(){System.out.println("test changed method");}
}

 

package myASM;import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;public class MethodChangeClassAdapter extends ClassVisitor implements Opcodes{public MethodChangeClassAdapter(ClassVisitor cv) {super(Opcodes.ASM4, cv);}@Overridepublic 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);}}@Overridepublic MethodVisitor visitMethod(int access, String name, String desc,String signature, String[] exceptions) {//当方法名为execute时,修改方法名为execute1if (cv != null && "execute".equals(name)){return cv.visitMethod(access, name + "1", desc, signature, exceptions);}//此处的changeMethodContent即为需要修改的方法  ,修改方法內容if("changeMethodContent".equals(name)){//先得到原始的方法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;}
}

 

package myASM;import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;public class AsmMethodVisit extends MethodVisitor{public AsmMethodVisit(MethodVisitor mv) {super(Opcodes.ASM4, mv);}@Overridepublic void visitMethodInsn(int opcode, String owner, String name,String desc) {super.visitMethodInsn(opcode, owner, name, desc); }@Overridepublic void visitCode(){//此方法在访问方法的头部时被访问到,仅被访问一次  //此处可插入新的指令  super.visitCode();}@Overridepublic void visitInsn(int opcode){//此方法可以获取方法中每一条指令的操作类型,被访问多次  //如应在方法结尾处添加新指令,则应判断:if(opcode == Opcodes.RETURN){// pushes the 'out' field (of type PrintStream) of the System class mv.visitFieldInsn(Opcodes.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(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");}super.visitInsn(opcode);}
}

 

package myASM;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 void main(String args[]) throws IOException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, InstantiationException{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);mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");mw.visitLdcInsn("this is add method print!");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();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'//調用changeMethodContent,修改方法內容exampleClass.getMethods()[1].invoke(exampleClass.newInstance(), null);System.out.println("***************************");//調用execute,修改方法名 exampleClass.getMethods()[2].invoke(exampleClass.newInstance(), null); // gets the bytecode of the Example class, and loads it dynamically  FileOutputStream fos = new FileOutputStream("e:\\logs\\Example.class");  fos.write(code);  fos.close();}}

 最后在eclipse控制台输出结果:

 

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

 

然后通过反编译软件,查看E盘生成的Example.class

 

package myASM;import java.io.PrintStream;public class Foo
{public Foo(){}public void execute1(){System.out.println("test changed method name");}public void changeMethodContent(){System.out.println("test changed method");System.out.println("this is a modify method!");}public static void add(String as[]){System.out.println("this is add method print!");}
}

 

这篇关于ASM动态操作方法(增改)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/704483

相关文章

通过ibd文件恢复MySql数据的操作方法

《通过ibd文件恢复MySql数据的操作方法》文章介绍通过.ibd文件恢复MySQL数据的过程,包括知道表结构和不知道表结构两种情况,对于知道表结构的情况,可以直接将.ibd文件复制到新的数据库目录并... 目录第一种情况:知道表结构第二种情况:不知道表结构总结今天干了一件大事,安装1Panel导致原来服务

Javascript访问Promise对象返回值的操作方法

《Javascript访问Promise对象返回值的操作方法》这篇文章介绍了如何在JavaScript中使用Promise对象来处理异步操作,通过使用fetch()方法和Promise对象,我们可以从... 目录在Javascript中,什么是Promise1- then() 链式操作2- 在之后的代码中使

基于Canvas的Html5多时区动态时钟实战代码

《基于Canvas的Html5多时区动态时钟实战代码》:本文主要介绍了如何使用Canvas在HTML5上实现一个多时区动态时钟的web展示,通过Canvas的API,可以绘制出6个不同城市的时钟,并且这些时钟可以动态转动,每个时钟上都会标注出对应的24小时制时间,详细内容请阅读本文,希望能对你有所帮助...

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

Linux使用cut进行文本提取的操作方法

《Linux使用cut进行文本提取的操作方法》Linux中的cut命令是一个命令行实用程序,用于从文件或标准输入中提取文本行的部分,本文给大家介绍了Linux使用cut进行文本提取的操作方法,文中有详... 目录简介基础语法常用选项范围选择示例用法-f:字段选择-d:分隔符-c:字符选择-b:字节选择--c

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

禁止HTML页面滚动的操作方法

《禁止HTML页面滚动的操作方法》:本文主要介绍了三种禁止HTML页面滚动的方法:通过CSS的overflow属性、使用JavaScript的滚动事件监听器以及使用CSS的position:fixed属性,每种方法都有其适用场景和优缺点,详细内容请阅读本文,希望能对你有所帮助... 在前端开发中,禁止htm

Vue3中的动态组件详解

《Vue3中的动态组件详解》本文介绍了Vue3中的动态组件,通过`component:is=动态组件名或组件对象/component`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRa... 目录vue3动态组件动态组件的基本使用第一种写法第二种写法性能优化解决方法总结Vue3动态组件动态