我正在尝试学习 java 用于字节码检测的 asm 框架,但无法找到足够的文档或教程
I am trying to learn java asm framework for bytecode instrumentation but not able to find sufficient docs or tutorials on it
我正在尝试学习 java 用于字节码检测的 asm 框架,但找不到足够的文档或教程。
我研究了 ClassReader
、ClassWriter
和 ClassVisitor
以及一些更相似的 API,但不太清楚如何实现这些 API 以及如何编写相应的适配器。
假设我有一个 HelloWorld java class.
public class HelloWorld {
public static void main(String[] args) {
//some code.....
}
}
现在我想在字节码中插入一个变量"int i =10;"。请告诉我应该写什么Adapter/program。
提前致谢!
了解如何使用 ASM 的一个好方法是 运行使用 ASMifier 工具。
如果您只是想知道某些语言构造函数(例如变量初始值设定项)如何转换为字节码,创建一个简单的 Java class、编译它、找到它的 .class
文件和运行 javap
或用 IDE 打开它。
以下是向 class 添加附加字段的方法,例如 "int i = 10;"。
假设您正在使用 javaagent 来执行检测:
1) 使用以下作为 java agent
的 premain class
import java.lang.instrument.Instrumentation;
public class SimpleAgent {
public static void premain(String agentArgs, Instrumentation inst) {
ClassTransformer transformer = new ClassTransformer();
inst.addTransformer(transformer);
}
}
2)addTransformer调用ClassTransformer的transform方法class定义如下
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
public class ClassTransformer implements ClassFileTransformer{
public byte[] transform(ClassLoader loader,
String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] b)
throws IllegalClassFormatException {
try
{
ClassReader cr=new ClassReader(b);
ClassWriter cw = new ClassWriter(cr,ClassWriter.COMPUTE_MAXS);
AddField cp = new AddField(cw);
cr.accept(cp,0);
return cw.toByteArray();
}
catch(Exception e)
{
System.out.println(e);
}
return b;
}
}
3) 最后AddField 如下是负责向class
添加新字段的ClassVisitor
import static org.objectweb.asm.Opcodes.ASM4;
import org.objectweb.asm.ClassVisitor;
class AddField extends ClassVisitor{
static String className;
static String methName, descrip;
public AddField(ClassVisitor cv) {
super(ASM4, cv);
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
className = name;
cv.visit(version, access, name, signature, superName, interfaces);
}
public void visitEnd() {
cv.visitField(0, "i", "I", null , new Integer(10));
cv.visitEnd();
}
}
4。 ** 新编辑 ** 用于将变量添加到方法中。该变量必须存储到一个临时变量中,以后可以使用。以下适配器可用于此目的(查看 onMethodEnter):
import static org.objectweb.asm.Opcodes.ASM4;
import static org.objectweb.asm.Opcodes.*;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.AdviceAdapter;
public class MethodAdapter extends ClassVisitor {
public MethodAdapter(ClassVisitor cv) {
super(ASM4, cv);
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
cv.visit(version, access, name, signature, superName, interfaces);
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
MethodVisitor mv;
mv = cv.visitMethod(access, name, desc, signature, exceptions);
mv = new AddVariableAdapter(access, name, desc, mv);
return mv;
}
public void visitEnd() {
cv.visitEnd();
}
public class AddVariableAdapter extends AdviceAdapter{
public AddCallAdapter(int access, String name, String desc,
MethodVisitor mv) {
super(ASM4, mv, access, name, desc);
}
protected void onMethodEnter() {
mv.visitIntInsn(BIPUSH, 10); // pushes the number 10 on to the stack
mv.visitVarInsn(ISTORE, 1); // pops the top of the stack into a local variable indexed by 1
/* code to print the local variable
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitVarInsn(ILOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");*/
}
}
}
我正在尝试学习 java 用于字节码检测的 asm 框架,但找不到足够的文档或教程。
我研究了 ClassReader
、ClassWriter
和 ClassVisitor
以及一些更相似的 API,但不太清楚如何实现这些 API 以及如何编写相应的适配器。
假设我有一个 HelloWorld java class.
public class HelloWorld {
public static void main(String[] args) {
//some code.....
}
}
现在我想在字节码中插入一个变量"int i =10;"。请告诉我应该写什么Adapter/program。
提前致谢!
了解如何使用 ASM 的一个好方法是 运行使用 ASMifier 工具。
如果您只是想知道某些语言构造函数(例如变量初始值设定项)如何转换为字节码,创建一个简单的 Java class、编译它、找到它的 .class
文件和运行 javap
或用 IDE 打开它。
以下是向 class 添加附加字段的方法,例如 "int i = 10;"。 假设您正在使用 javaagent 来执行检测: 1) 使用以下作为 java agent
的 premain classimport java.lang.instrument.Instrumentation;
public class SimpleAgent {
public static void premain(String agentArgs, Instrumentation inst) {
ClassTransformer transformer = new ClassTransformer();
inst.addTransformer(transformer);
}
}
2)addTransformer调用ClassTransformer的transform方法class定义如下
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
public class ClassTransformer implements ClassFileTransformer{
public byte[] transform(ClassLoader loader,
String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] b)
throws IllegalClassFormatException {
try
{
ClassReader cr=new ClassReader(b);
ClassWriter cw = new ClassWriter(cr,ClassWriter.COMPUTE_MAXS);
AddField cp = new AddField(cw);
cr.accept(cp,0);
return cw.toByteArray();
}
catch(Exception e)
{
System.out.println(e);
}
return b;
}
}
3) 最后AddField 如下是负责向class
添加新字段的ClassVisitorimport static org.objectweb.asm.Opcodes.ASM4;
import org.objectweb.asm.ClassVisitor;
class AddField extends ClassVisitor{
static String className;
static String methName, descrip;
public AddField(ClassVisitor cv) {
super(ASM4, cv);
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
className = name;
cv.visit(version, access, name, signature, superName, interfaces);
}
public void visitEnd() {
cv.visitField(0, "i", "I", null , new Integer(10));
cv.visitEnd();
}
}
4。 ** 新编辑 ** 用于将变量添加到方法中。该变量必须存储到一个临时变量中,以后可以使用。以下适配器可用于此目的(查看 onMethodEnter):
import static org.objectweb.asm.Opcodes.ASM4;
import static org.objectweb.asm.Opcodes.*;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.AdviceAdapter;
public class MethodAdapter extends ClassVisitor {
public MethodAdapter(ClassVisitor cv) {
super(ASM4, cv);
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
cv.visit(version, access, name, signature, superName, interfaces);
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
MethodVisitor mv;
mv = cv.visitMethod(access, name, desc, signature, exceptions);
mv = new AddVariableAdapter(access, name, desc, mv);
return mv;
}
public void visitEnd() {
cv.visitEnd();
}
public class AddVariableAdapter extends AdviceAdapter{
public AddCallAdapter(int access, String name, String desc,
MethodVisitor mv) {
super(ASM4, mv, access, name, desc);
}
protected void onMethodEnter() {
mv.visitIntInsn(BIPUSH, 10); // pushes the number 10 on to the stack
mv.visitVarInsn(ISTORE, 1); // pops the top of the stack into a local variable indexed by 1
/* code to print the local variable
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitVarInsn(ILOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");*/
}
}
}