Asm动态生成类和get and set方法

news2024/11/14 14:27:43

asm在解析文件的时候是按照特定顺序进行分析的,首先是visit方法,做类相关的解析,然后是注解,然后是属性,最后才是方法,属性是在所有方法分析前面进行,也就是只有当class文件中的所有属性都遍历完毕之后,才会去遍历方法

1.自定义类加载器

package club.jiajia.test;
public class MyClassLoader extends ClassLoader{  
    public  Class<?> defineClassByName(String name,byte[] b,int off,int len){   
        Class<?> clazz = super.defineClass(name,b, off, len);  
        return clazz;   
    }   
}

2.asm动态生成字节码

package club.jiajia.test2;
import java.util.List;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
 * jiajiajia
 */
public class Asm implements Opcodes {
    public byte[] createBeanClass(String className, List<FieldInfo> fields) {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_1, ACC_PUBLIC, className, null, "java/lang/Object", null);
        // creates a MethodWriter for the (implicit) constructor
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
 
        for (FieldInfo f : fields) {
            addMethod(cw, mv, className, f);
        }
 
        return cw.toByteArray();
    }
 
    private void addMethod(ClassWriter cw, MethodVisitor mv, String className,
                                  FieldInfo fieldInfo) {
        String fieldName = fieldInfo.name;
        String setMethodName = "set" +fieldName;
        String getMethodName = "get" +fieldName;
 
        String typeof = Type.getType(fieldInfo.type).getDescriptor();
        String getof = getof(typeof);
        String setof = setof(typeof);
        int[] loadAndReturnOf = loadAndReturnOf(typeof);
        
        //add field
        cw.visitField(ACC_PRIVATE, fieldName, typeof, null, 0).visitEnd();
 
        // getMethod
        mv = cw.visitMethod(ACC_PUBLIC, getMethodName, getof, null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, className, fieldName, typeof);
        mv.visitInsn(loadAndReturnOf[1]);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
        
        // setMethod
        mv = cw.visitMethod(ACC_PUBLIC, setMethodName, setof, null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(loadAndReturnOf[0], 1);
        mv.visitFieldInsn(PUTFIELD, className, fieldName, typeof);
        mv.visitInsn(RETURN);
        mv.visitMaxs(3, 3);
        mv.visitEnd();
    }
 
    private String setof(String typeof) {
        return "(" + typeof + ")V";
    }
 
    private String getof(String typeof) {
        return "()" + typeof;
    }
    private int[] loadAndReturnOf(String typeof) {
        if (typeof.equals("I") || typeof.equals("Z")) {
            return new int[]{ILOAD,IRETURN};
        } else if (typeof.equals("J")) {
            return new int[]{LLOAD,LRETURN};
        } else if (typeof.equals("D")) {
            return new int[]{DLOAD,DRETURN};
        } else if (typeof.equals("F")) {
            return new int[]{FLOAD,FRETURN};
        } else {
            return new int[]{ALOAD,ARETURN};
        }
    }
}

3.定义属性信息

package club.jiajia.test2;

public class FieldInfo {
	public Class<?> clazz;
	public String name;
	public String type;
	public Object value;
	public FieldInfo(Class<?> clazz, String name, Object value) {
		super();
		this.clazz = clazz;
		this.name = name;
		this.value = value;
	}
}

4.测试

package club.jiajia.test2;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import club.jiajia.test.MyClassLoader;
 
/**
 * jiajiajia
 */
public class Test extends ClassLoader {
    private static String className="Abc";
    private static List<FieldInfo> fields;
 
    public static byte[] setUp(){
        FieldInfo testString = new FieldInfo(int.class, "name", 1);
        testString.type="I";
        fields = new ArrayList<FieldInfo>();
        fields.add(testString);
        return  new Asm().createBeanClass(className, fields);
    }
    
    public static void main(String[] args) {
		byte b[]=setUp();
		MyClassLoader mcl=new MyClassLoader();  
        //返回的对象时被加载类的class  
        Class<?> hw=mcl.defineClassByName("Abc", b, 0, b.length);  
        try {  
            //利用反射创建对象  
            Object o= hw.newInstance();
            java.lang.reflect.Method method=   o.getClass().getMethod("getname");
            java.lang.reflect.Method method2=   o.getClass().getMethod("setname",int.class);
            method2.invoke(o,3);
            System.out.println(method.invoke(o));
        }catch (Exception e) {
        	e.printStackTrace();
		}
	    
		File file = new File("E://jiajiajia/Abc.class");
		try {
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(b);
			fout.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

5.测试结果

QQ截图20190305161048.png

测试的时候会在E://jiajiajia文件夹下生成一个Abc.clss文件

6.反编译结果为:

public class Abc
{
    private int name = 0;
    
    public int getname() {
        return this.name;
    }
    
    public void setname(final int name) {
        this.name = name;
    }
}

7.测试2

生成if条件判断

package club.jiajia.test3;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TestAsm implements Opcodes{
	public static void main(String[] args) throws InstantiationException, IllegalAccessException{
		ClassWriter cw=new ClassWriter(0);
		String className="Example";
		cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});

		String field="test";
		String a="a";
		Object defaultValue=123d;
		Object defaultValues=1123;
		String setMd="setTest";
		String getMd="getTest";
		
		String getMa="getMa";
		cw.visitField(ACC_PRIVATE,field,"D",null,defaultValue == null?null:Double.parseDouble(defaultValue.toString())).visitEnd();
		cw.visitField(ACC_PRIVATE,a,"I",null,defaultValues == null?null:Double.parseDouble(defaultValues.toString())).visitEnd();

		
		MethodVisitor mv=cw.visitMethod(ACC_PUBLIC,getMd,"()D",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitFieldInsn(GETFIELD,className,field,"D");
		mv.visitInsn(DRETURN);
		mv.visitMaxs(2,2);
		mv.visitEnd();
		cw.visitEnd();
		
		
		

		mv=cw.visitMethod(ACC_PUBLIC,setMd,"(D)V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		/**
		 * 访问本地变量指令。本地变量指令是ar *指令,它加载或存储本地变量* @param的值。这个操作码是ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE或RET.* @param vanthe操作数的指令访问。这个操作数是一个局部变量的索引
		 */
		mv.visitVarInsn(DLOAD,1);
		mv.visitFieldInsn(PUTFIELD,className,field,"D");
		mv.visitInsn(RETURN);
		mv.visitMaxs(3,3);
		mv.visitEnd();
		
		
		
		
		/***********************************************************/
		mv=cw.visitMethod(ACC_PUBLIC,getMa,"(I)V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ILOAD, 1);
		Label label = new Label();
		mv.visitJumpInsn(IFLT, label);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ILOAD, 1);
		mv.visitFieldInsn(PUTFIELD, className, "a", "I");
		Label end = new Label();
		mv.visitJumpInsn(GOTO, end);
		mv.visitLabel(label);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
		mv.visitInsn(DUP);
		mv.visitMethodInsn(INVOKESPECIAL,
		"java/lang/IllegalArgumentException", "<init>", "()V");
		mv.visitInsn(ATHROW);
		mv.visitLabel(end);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		mv.visitInsn(RETURN);
		mv.visitMaxs(2, 2);
		mv.visitEnd();
		/***********************************************************/
		
		
		
		//下面产生构造方法
		mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
		mv.visitInsn(RETURN);
		mv.visitMaxs(1,1);
		mv.visitEnd();
		
		
		cw.visitEnd();

		byte[] bs=cw.toByteArray();
		File file = new File("E://jiajiajia/Example.class");
		try {
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(bs);
			fout.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		MyCLassLoader loader=new MyCLassLoader();
		Class<?> c=loader.defineClass(bs);
		
		ITest ins=(ITest)c.newInstance();
		ins.setTest(100.0d);
		ins.getMa(-2);
		System.out.println(ins.getTest());
	}
	
	public interface ITest{
		public double getTest();
		public void setTest(double d);
		public void getMa(int a);
	}

	public static class MyCLassLoader extends ClassLoader{
		public Class defineClass(byte[] data){
			return super.defineClass(null,data,0,data.length,null);
		}
	}
}

反编译结果为

import club.jiajia.test3.*;

public class Example implements Cloneable, TestAsm$ITest
{
    private double test = 123.0;
    private int a = 1123;
    
    public double getTest() {
        return this.test;
    }
    
    public void setTest(final double test) {
        this.test = test;
    }
    
    public void getMa(final int i) {
        while (i < 0) {}
        this.a = i;
    }
}

image.png

8.生成更为复杂的方法

package club.jiajia.test3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TestAsm2 implements Opcodes{
	public static void main(String[] args) throws InstantiationException, IllegalAccessException{
		ClassWriter cw=new ClassWriter(0);
		String className="Example2";
		cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});

		String a="a";
		Object av=123;
		
		String getA="getA";
		String setA="setA";
		cw.visitField(ACC_PRIVATE,a,"I",null,av == null?null:Integer.parseInt(av.toString())).visitEnd();

		
		MethodVisitor mv=cw.visitMethod(ACC_PUBLIC,getA,"()I",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitFieldInsn(GETFIELD,className,a,"I");
		mv.visitInsn(IRETURN);
		mv.visitMaxs(2,2);
		mv.visitEnd();
		cw.visitEnd();
		
		
		/***********************************************************/
		mv=cw.visitMethod(ACC_PUBLIC,setA,"(II)V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ILOAD, 1);
		mv.visitVarInsn(ILOAD, 2);
		Label label = new Label();
		mv.visitJumpInsn(IF_ICMPLT, label);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ILOAD, 1);
		mv.visitFieldInsn(PUTFIELD, className, "a", "I");
		
		Label end = new Label();
		mv.visitJumpInsn(GOTO, end);
		mv.visitLabel(label);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ILOAD, 2);
		mv.visitFieldInsn(PUTFIELD, className, "a", "I");
		
		mv.visitLabel(end);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		mv.visitInsn(RETURN);
		mv.visitMaxs(3, 3);
		mv.visitEnd();
		/***********************************************************/
		
		//下面产生构造方法
		mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
		mv.visitInsn(RETURN);
		mv.visitMaxs(1,1);
		mv.visitEnd();
		
		cw.visitEnd();

		byte[] bs=cw.toByteArray();
		File file = new File("E://jiajiajia/Example2.class");
		try {
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(bs);
			fout.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		MyCLassLoader loader=new MyCLassLoader();
		Class<?> c=loader.defineClass(bs);
		
		ITest ins=(ITest)c.newInstance();
		ins.setA(145,12);
		System.out.println(ins.getA());
	}
	
	public interface ITest{
		public int getA();
		public void setA(int a,int b);
	}

	public static class MyCLassLoader extends ClassLoader{
		public Class<?> defineClass(byte[] data){
			return super.defineClass(null,data,0,data.length,null);
		}
	}
}

menu.saveimg.savepath20190322094711.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1870080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Android11】开机启动日志捕捉服务

一、前言 制作这个功能的原因是客户想要自动的记录日志中的报错和警告到设备的内存卡里面。虽然开发者模式中有一个“bug report” 会在/data/user_de/0/com.android.shell/files/bugreports/目录下生成一个zip包记录了日志。但是客户觉得这个日志很难获取到他们需要的信息&am…

无需劳师动众,让石油化工DCS集散控制系统轻松实现无线传输!

石油化工中,为了保证较高的可靠性和安全性,大量使用的是DCS集散控制系统。与FCS现场总线的“现场采集,转换为数字信号来集中传输”不同,DCS系统为了避免由于线缆断裂或者节点问题导致整个控制系统失灵,采用“分散传输,集中采集”的方式,即每个传感器通过4-20mA的模拟量通…

el-upload 上传图片及回显照片和预览图片,文件流和http线上链接格式操作

<div v-for"(info, index) in zsjzqwhxqList.helicopterTourInfoList" :key"info.id" >编辑上传图片// oss返回线上地址http链接格式&#xff1a;<el-form-itemlabel"巡视结果照片":label-width"formLabelWidth"><el…

【MySQL】 -- 用户管理

1. 权限 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。创建出非root用户&#xff0c;限制其权限。 权限这个概念拿出来就是用来限制非root用户的。这样从技术手段上保证了数据的安全性和完整性&#xff0c;防止有人删库…

LeetCode11. 盛最多水的容器题解

LeetCode11. 盛最多水的容器题解 题目链接&#xff1a; https://leetcode.cn/problems/container-with-most-water 示例 思路 暴力解法 定住一个柱子不动&#xff0c;然后用其他柱子与其围住面积&#xff0c;取最大值。 代码如下&#xff1a; public int maxArea1(int[]…

麒麟系统安装Redis

一、背景 如前文&#xff08;《麒麟系统安装MySQL》&#xff09;所述。 二、下载Redis源码 官方未提供麒麟系统的Redis软件&#xff0c;须下载源码编译。 下载地址&#xff1a;https://redis.io/downloads 6.2.14版本源码下载地址&#xff1a;https://download.redis.io/re…

ADI-DSP|在指定内存写入数据

一、LDF文件设置内存空间 user_data_test { TYPE(BW RAM) START(0x00380010) END(0x0039bfff) WIDTH(8) }//usr data dxe_user_data_bw BW{INPUT_SECTION_ALIGN(4)INPUT_SECTIONS( $OBJS_LIBS(user_data) )} > user_data_test 二、在C文件中设置数据 /************…

2.x86游戏实战-跨进程读取血量

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 接下来会写C/C代码&#xff0c;C/C代码不是很难&#xff0c;然后为了快速掌握逆向这个技能&#xff0c;我…

List常用操作比for循环更优雅的写法

private String name; //姓名 private Integer age; //年龄 private Integer departId; //所属部门id } List list new ArrayList<>(); 复制代码 简单遍历 使用lamada表达式之前&#xff0c;如果需要遍历list时&#xff0c;一般使用增强for循环&#xff0c;代码如…

uboot基本使用网络命令和从服务器端下载linux内核启动

网络命令ip地址设置: setenv gmac_debug 0; setenv mdio_intf rgmii; setenv bootdelay 1; setenv ethaddr 00:xxxx:81:70; // mac地址 setenv ipaddr xxx; //开发板 IP 地址 setenv netmask 255.255.255.0; setenv gatewayip xxx.1; setenv serverip xxxx; //服…

RP2040 开发,用 Arduino 通过 ADC 获取电压测量数据

这两天测试了一下如何通过 RP2040 的内置 ADC 获取一个待测量的电压数据&#xff0c;RP2040 内置了4路ADC&#xff0c;分辨率是12bit&#xff0c;也就是说&#xff0c;可以获取4096阶的变化量&#xff0c;但第4个 ADC 已经用于测量芯片的内部温度&#xff0c;所以实际能用的仅有…

YOLO模型评价指标

在模型训练完成之后&#xff0c;需要对模型的优劣作出评估&#xff0c;YOLO系列算法的评价指标包括&#xff1a; 1. 准确率&#xff08;Precision&#xff09;&#xff1a;指模型预测为正样本中实际为正样本的比例。 &#x1d447;&#x1d443;、&#x1d439;&#x1d443;、…

计算机方向国际学术会议推荐

*华中师范大学伍伦贡联合研究院与南京大学联合主办 第三届人工智能、物联网和云计算技术国际会议&#xff08;AIoTC 2024&#xff09; 大会官网&#xff1a;www.icaiotc.net 时间地点&#xff1a;2024年9月13-15日&#xff0c;中国武汉 收录检索&#xff1a;EI Compendex&a…

从一道算法题开始,爱上Python编程

Python是一门简单易学、高效强大的编程语言&#xff0c;许多人因为它的便捷性和广泛应用而爱上编程。今天&#xff0c;我将通过一道有趣的算法题&#xff0c;带领大家一步步写出Python代码&#xff0c;并最终解决问题。希望通过这篇文章&#xff0c;能激发大家对Python编程的兴…

从万里长城防御体系看软件安全体系建设@安全历史03

长城&#xff0c;是中华民族的一张重要名片&#xff0c;是中华民族坚韧不屈、自强不息的精神象征&#xff0c;被联合国教科文组织列入世界文化遗产名录。那么在古代&#xff0c;长城是如何以其复杂的防御体系&#xff0c;一次次抵御外族入侵&#xff0c;而这些防御体系又能给软…

C++语法20 一维数组及其相关问题详解

这是《C算法宝典》语法入门篇的第20节文章啦~ 如果你之前没有太多C基础&#xff0c;请点击&#x1f449;专栏&#xff1a;C语法入门&#xff0c;如果你C语法基础已经炉火纯青&#xff0c;则可以进阶算法&#x1f449;专栏&#xff1a;算法知识和数据结构&#x1f449;专栏&…

stm32学习笔记---TIM输入捕获(代码部分)输入捕获模式测频率/PWMI模式测频率占空比

目录 第一个代码&#xff1a;输入捕获模式测频率 调整频率 PWM.c PWM.h 输入捕获 IC.c 输入捕获初始化步骤 TIM.h库函数 TIM_ICInit TIM_PWMIConfig TIM_ICStructInit TIM_SelectInputTrigger TIM_SelectOutputTrigger TIM_SelectSlaveMode 单独配置四个通道的分…

React Antd ProTable 如何设置类似于Excel的筛选框

React Antd ProTable 如何设置类似于Excel的筛选框 目标&#xff1a;在web页面的table表格中完成类似于EXCEL的Filter筛选功能。 示例图&#xff1a;点击标题列上方的漏斗状图标&#xff0c;即可对数据进行筛选。 ProTable 前景提要 ProTable API中有说明&#xff0c;是有…

一次关于k8s的node节点NotReady的故障排查

master现象 分析 kubectl get nodes -A 看了下pod的状态&#xff0c;好多CrashLoopBackOff kubectl get nodes -o wide 定位到那个具体node的IP地址&#xff0c;登录对应的IP去查看为什么会这样 node节点 journalctl -xe -f -u kubelet 查看此节点的 kubelet 服务&#xff…

Termius:现代化的SSH客户端,让服务器管理变得优雅简洁

Termius简介 是一款现代化的跨平台终端模拟器和SSH客户端。以下是对Terminus的介绍以及使用它的理由&#xff1a; 跨平台兼容性&#xff1a; Terminus支持Windows、macOS、Linux、IOS和Android&#xff0c;让用户在不同操作系统间保持一致的终端体验。优雅的用户界面&#xf…