在ASM的Core API中使用的是访问者模式来实现对类的操作,主要包含如下类:
一、ClassVisitor接口:
在这个接口中主要提供了和类结构同名的一些方法,这些方法可以对相应的类结构进行操作。如下:
public interface ClassVisitor {
void visit(int version,int access,String name,String signature,String superName,String[] interfaces);
void visitSource(String source, String debug);
void visitOuterClass(String owner, String name, String desc);
AnnotationVisitor visitAnnotation(String desc, boolean visible);
void visitAttribute(Attribute attr);
void visitInnerClass(String name,String outerName,String innerName,int access);
FieldVisitor visitField(int access,String name,String desc,String signature,Object value);
MethodVisitor visitMethod(int access,String name,String desc,String signature,String[] exceptions);
void visitEnd();
}
这里定义的方法调用是有顺序的,在ClassVisitor中定义了调用的顺序和每个方法在可以出现的次数,如下:
visit
[ visitSource
] [
visitOuterClass
] ( visitAnnotation
|
visitAttribute
)* (visitInnerClass
|
visitField
| visitMethod
)* visitEnd。
二、ClassReader类:
这个类会提供你要转变的类的字节数组,它的accept方法,接受一个具体的ClassVisitor,并调用实现中具体的visit,
visitSource,
visitOuterClass,
visitAnnotation,
visitAttribute,
visitInnerClass,
visitField,
visitMethod和
visitEnd方法。
三、ClassWriter类:
这个类是ClassVisitor的一个实现类,这个类中的toByteArray方法会将最终修改的字节码以byte数组形式返回,在这个类的构造时可以指定让系统自动为我们计算栈和本地变量的大小(COMPUTE_MAXS),也可以指定系统自动为我们计算栈帧的大小(COMPUTE_FRAMES)。
四、ClassAdapter类:
这个类也是ClassVisitor的一个实现类,这个类可以看成是一个事件过滤器,在这个类里,它对ClassVisitor的实现都是委派给一个具体的ClassVisitor实现类,即调用那个实现类实现的方法。
五、AnnotationVisitor接口:
这个接口中定义了和Annotation结构想对应的方法,这些方法可以操作Annotation中的定义,如下:
public interface AnnotationVisitor {
void visit(String name, Object value);
void visitEnum(String name, String desc, String value);
AnnotationVisitor visitAnnotation(String name, String desc);
AnnotationVisitor visitArray(String name);
void visitEnd();
}
调用顺序如下:
(visit | visitEnum |
visitAnnotation | visitArray)* visitEnd
六、FieldVisitor接口:
这个接口定义了和属性结构相对应的方法,这些方法可以操作属性,如下:
public interface FieldVisitor {
AnnotationVisitor visitAnnotation(String desc, boolean visible);
void visitAttribute(Attribute attr);
void visitEnd();
}
调用顺序:
( visitAnnotation
|
visitAttribute
)* visitEnd
.
七、MethodVisitor接口:
这个接口定义了和方法结构相对应的方法,这些方法可以去操作源方法,具体的可以查看一下源码。
八、操作流程:
一般情况下,我们需要操作一个类时,首先是获得其二进制的字节码,即用ClassReader来读取一个类,然后需要一个能将二进制字节码写回的类,即用ClassWriter类,最后就是一个事件过滤器,即ClassAdapter。事件过滤器中的某些方法可以产生一个新的XXXVisitor对象,当我们需要修改对应的内容时只要实现自己的XXXVisitor并返回就可以了。
九、例子:
在这个例子中,我们将对Person类的sayName方法做出一些修改,源类:
public class Person {
private String name;
public void sayName() {
System.out.println(name);
}
}
如果我们定义一个Person类然后调用其sayName()方法将会得到的是一个null,行成的二进制字节码如下:
public void sayName();
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #17; //Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: getfield #23; //Field name:Ljava/lang/String;
7: invokevirtual #25; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
}
我们修改一下这个方法,让它输出"zhangzhuo",代码如下:
public class GenerateNewPerson {
public static void main(String[] args) throws Exception {
// 使用全限定名,创建一个ClassReader对象
ClassReader classReader = new ClassReader(
"org.victorzhzh.core.ic.Person");
// 构建一个ClassWriter对象,并设置让系统自动计算栈和本地变量大小
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter classAdapter = new GeneralClassAdapter(classWriter);
classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
byte[] classFile = classWriter.toByteArray();
// 将这个类输出到原先的类文件目录下,这是原先的类文件已经被修改
File file = new File(
"target/classes/org/victorzhzh/core/ic/Person.class");
FileOutputStream stream = new FileOutputStream(file);
stream.write(classFile);
stream.close();
}
}
public class GeneralClassAdapter extends ClassAdapter {
public GeneralClassAdapter(ClassVisitor cv) {
super(cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
// 当是sayName方法是做对应的修改
if (name.equals("sayName")) {
MethodVisitor newMv = new SayNameMethodAdapter(mv);
return newMv;
} else {
return mv;
}
}
// 定义一个自己的方法访问类
class SayNameMethodAdapter extends MethodAdapter {
public SayNameMethodAdapter(MethodVisitor mv) {
super(mv);
}
// 在源方法前去修改方法内容,这部分的修改将加载源方法的字节码之前
@Override
public void visitCode() {
// 记载隐含的this对象,这是每个JAVA方法都有的
mv.visitVarInsn(Opcodes.ALOAD, 0);
// 从常量池中加载“zhangzhuo”字符到栈顶
mv.visitLdcInsn("zhangzhuo");
// 将栈顶的"zhangzhuo"赋值给name属性
mv.visitFieldInsn(Opcodes.PUTFIELD,
Type.getInternalName(Person.class), "name",
Type.getDescriptor(String.class));
}
}
}
这时,我们在查看一下Person的字节码:
public void sayName();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: ldc #13; //String zhangzhuo
3: putfield #15; //Field name:Ljava/lang/String;
=============以上是我们新增加的内容================================
6: getstatic #21; //Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_0
10: getfield #15; //Field name:Ljava/lang/String;
13: invokevirtual #27; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
16: return
}
再次调用Person对象,输出结果为:zhangzhuo
分享到:
相关推荐
ASM设计用于字节码的改写、生成。其有两套API一套基于访问者模式、一套基于树的数据结构。
这个工具基于访问者模式实现,可以对字节码进行各种操作和分析。 ASM库提供了一套基于树API的类分析框架和几个预定义的类分析器,这些都被包含在`org.objectweb.asm.tree.analysis`包中。在这个包里,你可以找到...
神秘的组装者具有类似于汇编的语法的解释器。指数下载链接签出我们的最新版本。 您可以在此处找到安装说明。 从下载ZIP文件。 或者从获取可执行文件。如何使用? 执行asm path/to/file ,其中asm是命令(或二进制可...
书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不仅能使读者更深刻地认识操作系统的核心原理,而且使整个开发过程少走弯路。全书共分7章。 本书适合各类程序员、程序开发爱好者阅读,也可作为高等院校...
在过去的14年中,他与IanAbramson和MichaelCorey为OraclePress合著了一系列图书.Abbey在国际Oracle用户团体非常活跃,经常出席COLLABORATE、OraclecOpenWorld和区域性用户组会议. Michael J.Corey是Ntirety...
环境配置 Windows 7 及以上版本:建议...Linux/Mac:请访问 DOSBOX 官网的 Download 界面,寻找自己系统对应的版本安装。 编译、链接,以 test.asm 为例。 masm test.asm link test.obj 习题 建议:在解决问题本身的
这些对象称为访问者。 每个访问者函数名称都包含相应的指令名称,但有一些变体: OpType 指令将转换为CodeVisitor :: visit <TypeName> Type( args ... ) OpExecutionMode没有与相应指令完全相同的参数:操作...
环境配置 Windows 7 及以上版本:建议...Linux/Mac:请访问 DOSBOX 官网的 Download 界面,寻找自己系统对应的版本安装。 编译、链接,以 test.asm 为例。 masm test.asm link test.obj 习题 建议:在解决问题本身的
RAR 是一个让你在命令行模式中管理压缩文件的控制台应用。RAR 提供压缩、加 密、数据恢复和许多其它此手册中描述的其它功能。 RAR 只支持 RAR 格式压缩文件,它默认有 .rar 扩展名。不支持ZIP 和其他格 式。即使...
这个命令将从当前路径中的 RAR 压缩文件解压所有的 *.asm 文件: rar e '*.rar' '*.asm' 命令可以是下列中的任何一个: a 添加文件到压缩文件中。 例子: 1) 从当前目录添加所有的 *.hlp 文件到 help.rar ...
CruiseYoung提供的带有详细书签的电子书籍目录 ... OCPOCA认证考试指南全册:Oracle Database 11g(1Z0-051,1Z0-... 12.1 使用同等联接和非同等联接编写SELECT语句访问多个表的数据 398 12.1.1 联接的类型 398 12.1.2 ...
CruiseYoung提供的带有详细书签的电子书籍目录 ... 对应的书籍资料见: OCPOCA认证考试指南全册:Oracle Database 11g(1Z0-051... 12.1 使用同等联接和非同等联接编写SELECT语句访问多个表的数据 398 12.1.1 联接的类型...
这个命令将从当前路径中的 RAR 压缩文件解压所有的 *.asm 文件: rar e '*.rar' '*.asm' 命令可以是下列中的任何一个: a 添加文件到压缩文件中。 例子: 创建或更新已存在的压缩文件 myarch,...
《Oracle Database 11g初学者指南》能使读者快捷地掌握Oracle Database 11g的基础知识。通过自我评估教程,介绍了核心数据库技术、管理员职责、高可用性以及大型数据库特性。《Oracle Database 11g初学者指南》带领...
****创建表 1 和表 2(使用 ASM 的访问者 API 生成任意 Scala 案例类的步骤表):通过删除任何现有的 .class 文件来创建字节码生成代码,使用值成员更新案例类不同类型(手动),然后在新的 .class 文件上运行 ...
考虑到反向工程任务的多功能性,Kam1n0 v2.x服务器当前提供三种不同类型的克隆搜索应用程序: Asm-Clone , Sym1n0和Asm2Vec以及基于Asm2Vec的可执行分类。 可以将新的应用程序类型进一步添加到平台。 用户可以创建...
HDInsight(注意:ASM模式下的HDInsight命令已弃用,并将于2017年1月删除) 钥匙库 批量 服务结构管理(当前仅适用于Linux群集,即将在Windows群集上推出) 注意:功能列表可能不是最新的。 有关准确的命令详细...
本书尤其适合作为你的引路书籍,因为它翔实地介绍了初学者入门时所必需的知识积累,而这些知识在《操作系统:设计与实现》一书中是没有涉及的,笔者本人是把这本书作为写操作系统的主要参考书籍之一,所以在本书中对...