ASM修改class信息

Java asm修改class信息

[TOC]

1 asm中提供了ClassReader和ClassVisitor用来获取class信息,如果要修改class信息就要用到ClassWriter

1.1 ClassWriter的构造方法

1public ClassWriter(final int flags) 2public ClassVisitor(final int api, final ClassVisitor cv)

2 BusIndex.class反编译后的代码为

1public final class BusIndex extends a { 2 public BusIndex() { 3 } 4 5 public d generateSubscribeMethodIndex(Object var1) { 6 d var2 = new d(); 7 Class var3 = var1.getClass(); 8 Class var4 = null; 9 Class var5 = null; 10 String var6 = null; 11 if(var3 == MainActivity.class) { 12 var4 = com.sample.app.MainActivity.a.class; 13 var5 = com.a.a.d.a.class; 14 var6 = "showMessage"; 15 var2.a(var6, var4, var5, new com.eventbus.gen.a(this, var1, var6, var4, var5)); 16 var4 = com.sample.app.MainActivity.a.class; 17 var5 = com.a.a.d.a.class; 18 var6 = "showMessagedd"; 19 var2.a(var6, var4, var5, new b(this, var1, var6, var4, var5)); 20 return var2; 21 } else if(var3 == Main2Activity.class) { 22 var4 = com.sample.app.MainActivity.a.class; 23 var5 = com.a.a.d.a.class; 24 var6 = "showMessage"; 25 var2.a(var6, var4, var5, new c(this, var1, var6, var4, var5)); 26 var4 = com.sample.app.MainActivity.a.class; 27 var5 = com.a.a.d.a.class; 28 var6 = "showMessagedd"; 29 var2.a(var6, var4, var5, new com.eventbus.gen.d(this, var1, var6, var4, var5)); 30 return var2; 31 } else { 32 return var2; 33 } 34 } 35}

3 使用asm将generateSubscribeMethodIndex方法中String变量的值都加上前缀

3.1 首先加载BusIndex.class

ClassReader classReader = new ClassReader(BusIndex.class.getName());

3.2 使用ClassReader的accept方法查找generateSubscribeMethodIndex方法

如果有多个generateSubscribeMethodIndex重载方法,查找方法时必须验证方法的 desc signature等其他参数

1ClassReader classReader = new ClassReader(BusIndex.class.getName()); 2classReader.accept(new ClassVisitorAdapter(null), 0); 3 4public class ClassVisitorAdapter extends ClassVisitor { 5 6 public ClassVisitorAdapter(ClassWriter classWriter) { 7 super(Opcodes.ASM6, classWriter); 8 } 9 10 @Override 11 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 12 MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); 13 if (name.equals("generateSubscribeMethodIndex")) { 14 //methodVisitor = new MethodVisitorAdapter(methodVisitor); 15 return methodVisitor; 16 } 17 18 return methodVisitor; 19 } 20}

3.3 使用自定义MethodVisitor遍历generateSubscribeMethodIndex方法的具体信息

1public class ClassVisitorAdapter extends ClassVisitor { 2 3 public ClassVisitorAdapter(ClassWriter classWriter) { 4 super(Opcodes.ASM6, classWriter); 5 } 6 7 @Override 8 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 9 MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); 10 if (name.equals("generateSubscribeMethodIndex")) { 11 methodVisitor = new MethodVisitorAdapter(methodVisitor); 12 return methodVisitor; 13 } 14 15 return methodVisitor; 16 } 17} 18 19public class MethodVisitorAdapter extends MethodVisitor { 20 public MethodVisitorAdapter(MethodVisitor methodVisitor) { 21 super(Opcodes.ASM6, methodVisitor); 22 } 23 24 25 @Override 26 public void visitCode() { 27 super.visitCode(); 28 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName()); 29 30 } 31 32 33 @Override 34 public void visitEnd() { 35 super.visitEnd(); 36 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName()); 37 38 System.out.println(csts); 39 } 40 41 42 @Override 43 public void visitInsn(int opcode) { 44 super.visitInsn(opcode); 45 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName() + ", opcode:" + Optcodes.options.get(opcode)); 46 47 } 48 49 50 @Override 51 public void visitJumpInsn(int opcode, Label label) { 52 super.visitJumpInsn(opcode, label); 53 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName() + ", opcode:" + Optcodes.options.get(opcode)); 54 } 55 56 @Override 57 public void visitLdcInsn(Object cst) { 58 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName() + ", cst:" + cst); 59 60 } 61 62 @Override 63 public void visitMaxs(int maxStack, int maxLocals) { 64 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName() + " ,maxstack:" + maxStack); 65 66 super.visitMaxs(maxStack, maxLocals); 67 } 68 69}

3.4 运行查看输出结果

1visitCode 2visitInsn, opcode:DUP 3visitInsn, opcode:ACONST_NULL 4visitInsn, opcode:ACONST_NULL 5visitInsn, opcode:ACONST_NULL 6visitLdcInsn, cst:Lcom/sample/app/MainActivity; 7visitJumpInsn, opcode:IF_ACMPNE 8visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 9visitLdcInsn, cst:Lcom/a/a/d/a; 10visitLdcInsn, cst:showMessage 11visitInsn, opcode:DUP 12visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 13visitLdcInsn, cst:Lcom/a/a/d/a; 14visitLdcInsn, cst:showMessagedd 15visitInsn, opcode:DUP 16visitInsn, opcode:ARETURN 17visitLdcInsn, cst:Lcom/sample/app/Main2Activity; 18visitJumpInsn, opcode:IF_ACMPNE 19visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 20visitLdcInsn, cst:Lcom/a/a/d/a; 21visitLdcInsn, cst:showMessage 22visitInsn, opcode:DUP 23visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 24visitLdcInsn, cst:Lcom/a/a/d/a; 25visitLdcInsn, cst:showMessagedd 26visitInsn, opcode:DUP 27visitInsn, opcode:ARETURN 28visitInsn, opcode:ARETURN 29visitMaxs ,maxstack:11 30visitEnd

3.5 输出的结果中可以看到visitLdcInsn 指令给变量的赋值操作

1visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 2visitLdcInsn, cst:Lcom/a/a/d/a; 3visitLdcInsn, cst:showMessage 4 5visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 6visitLdcInsn, cst:Lcom/a/a/d/a; 7visitLdcInsn, cst:showMessagedd 8 9visitLdcInsn, cst:Lcom/sample/app/Main2Activity; 10 11visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 12visitLdcInsn, cst:Lcom/a/a/d/a; 13visitLdcInsn, cst:showMessage 14 15visitLdcInsn, cst:Lcom/sample/app/MainActivity$a; 16visitLdcInsn, cst:Lcom/a/a/d/a; 17visitLdcInsn, cst:showMessagedd 18

3.6 MethodVisitorAdapter的visitLdcInsn方法中获取cst的类型

1if(cst instanceof Type){ 2 System.out.println("cst value type:"+((Type)cst).getClassName()); 3}else { 4 System.out.println("cst value type:"+cst.getClass()); 5}

3.7 在MethodVisitorAdapter的visitLdcInsn方法中给showMessage开头并且为String类型的cst加上前缀modify,然后通过父类的visitLdcInsn写回class

1if (cst instanceof String) { 2 if(cst != null && cst.toString().startsWith("showMessage")){ 3 super.visitLdcInsn("modify"+cst); 4 }else{ 5 super.visitLdcInsn(cst); 6 } 7} else { 8 super.visitLdcInsn(cst); 9}

3.8 ClassReader遍历class信息时传入ClassWriter,并输出修改后的class

1ClassReader classReader = new ClassReader(BusIndex.class.getName()); 2ClassWriter classWriter = new ClassWriter(0); 3classReader.accept(new ClassVisitorAdapter(classWriter), 0); 4System.out.println("修改后的字节码:\n"+new String(classWriter.toByteArray()));

3.9 输出结果

1修改后的字节码: 2���� 3 6 com/eventbus/gen/BusIndex com/a/a/c/a 3SourceFile com/eventbus/gen/d com/eventbus/gen/c  com/eventbus/gen/b 4 com/eventbus/gen/a com/sample/app/MainActivity$a com/sample/app/MainActivity a <init> ()V 5 generateSubscribeMethodIndex !(Ljava/lang/Object;)Lcom/a/a/c/d; com/a/a/c/d 6 java/lang/Object getClass ()Ljava/lang/Class; 7 com/a/a/d/a " modifyshowMessage $ d(Lcom/eventbus/gen/BusIndex;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Class;)V & 8 ' D(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Class;Lcom/a/a/b/a;)V ) 9 * modifyshowMessagedd , 10 ' com/sample/app/Main2Activity/ 11 '

3.10 将修改后的class写入文件

1Files.write(Paths.get(System.getProperty("user.dir")+"/BusIndex.class"), classWriter.toByteArray()); 2System.out.println("修改后的字节码成功保存到:\n"+Paths.get(System.getProperty("user.dir")+"/BusIndex.class"));

3.11 反编译生成的BusIndex.class

1public final class BusIndex extends a { 2 public BusIndex() { 3 } 4 5 public d generateSubscribeMethodIndex(Object var1) { 6 d var2 = new d(); 7 Class var3 = var1.getClass(); 8 Class var4 = null; 9 Class var5 = null; 10 String var6 = null; 11 if(var3 == MainActivity.class) { 12 var4 = com.sample.app.MainActivity.a.class; 13 var5 = com.a.a.d.a.class; 14 var6 = "modifyshowMessage"; 15 var2.a(var6, var4, var5, new com.eventbus.gen.a(this, var1, var6, var4, var5)); 16 var4 = com.sample.app.MainActivity.a.class; 17 var5 = com.a.a.d.a.class; 18 var6 = "showMessagedd"; 19 var2.a(var6, var4, var5, new b(this, var1, var6, var4, var5)); 20 return var2; 21 } else if(var3 == Main2Activity.class) { 22 var4 = com.sample.app.MainActivity.a.class; 23 var5 = com.a.a.d.a.class; 24 var6 = "modifyshowMessage"; 25 var2.a(var6, var4, var5, new c(this, var1, var6, var4, var5)); 26 var4 = com.sample.app.MainActivity.a.class; 27 var5 = com.a.a.d.a.class; 28 var6 = "showMessagedd"; 29 var2.a(var6, var4, var5, new com.eventbus.gen.d(this, var1, var6, var4, var5)); 30 return var2; 31 } else { 32 return var2; 33 } 34 } 35}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )