介是啥米东东

使用ASM修改一个.class文件

Java admin 3591℃ 0评论

ASM可以在字节层面修改.class文件,以此来修改一些类的行为。

首先导入asm的jar包(http://mirrors.ibiblio.org/pub/mirrors/maven2/asm/asm/3.2/asm-3.2.jar)

GeneralClassAdapter.java 主要用来拦截(代理)要修改的方法,并修改:

[java]
package com.znn.mv;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

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("sayHello")) {
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("Zhangningning");
// 将栈顶的"zhangzhuo"赋值给name属性
mv.visitFieldInsn(Opcodes.PUTFIELD,
Type.getInternalName(Person.class), "name",
Type.getDescriptor(String.class));
}

}
}
[/java]

GenerateNewPerson.java 加载.class文件执行修改<p/>

[java]
package com.znn.mv;

import java.io.File;
import java.io.FileOutputStream;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

public class GenerateNewPerson {
public static void main(String[] args) throws Exception {
// 使用全限定名,创建一个ClassReader对象
// Person person = new Person();
// person.sayName();
ClassReader classReader = new ClassReader(
"com.znn.mv.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(
"bin/com/znn/mv/Person.class");
FileOutputStream stream = new FileOutputStream(file);
// File f = new File("");
// System.out.println(f.getAbsolutePath());
stream.write(classFile);
stream.close();
// Person person = new Person();
// person.sayName();
System.out.println("Modify finish…");
}
}
[/java]

Person.java

[java]
package com.znn.mv;
public class Person {
private String name;

public void sayHello() {
System.out.println("Hello,"+name);
}
}
[/java]

测试类:Test.java

[java]
package com.znn.mv;

public class Test {
public static void main(String[] args) {
Person person = new Person();
person.sayHello();
}
}

[/java]

测试方法:
1.clean工程,重新编译
2.执行Test.java
屏幕快照 2014-05-05 下午1.37.37
null默认为空
3.执行GenerateNewPerson.java,将name的值改成zhangningning
4.再次执行Test.java
屏幕快照 2014-05-05 下午1.40.03

转载请注明:Z/RANDY » 使用ASM修改一个.class文件

喜欢 (0)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址