1. 準備工作
idea安裝插件:ASM ByteCode Outline,用于將class生成ASM相關代碼,供參考使用。寫好代碼,Build編譯后,在類上面右鍵Show Bytecode Outline
jadx:用于反編譯修改好的class,看是否修改成功
2. ClassVisitor文檔備注(待完善)
ClassVisitor 類的方法必須按以下順序調(diào)用(在這個類的 Javadoc 中規(guī)定):
visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )*
(visitInnerClass | visitField | visitMethod )*
visitEnd
這意味著必須首先調(diào)用 visit,
然后是對 visitSource 的最多一個調(diào)用,
接下來是對visitOuterClass的最多一個調(diào)用,
然后是可按任意順序?qū)?visitAnnotation 和visitAttribute 的任意多個訪問,
接下來是可按任意順序?qū)?visitInnerClass、visitField 和 visitMethod 的任意多個調(diào)用,
最后以一個 visitEnd 調(diào)用結束。
//待完善
public abstract class ClassVisitor {
/**
*
* @param api
*/
public ClassVisitor(int api) {}
/**
*
* @param api
* @param cv
*/
public ClassVisitor(int api, ClassVisitor cv) {}
/**
*
* @param version
* @param access
* @param name
* @param signature
* @param superName
* @param interfaces
*/
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {}
/**
*
* @param source
* @param debug
*/
public void visitSource(String source, String debug){}
/**
*
* @param owner
* @param name
* @param desc
*/
public void visitOuterClass(String owner, String name, String desc){}
/**
*
* @param desc
* @param visible
* @return
*/
AnnotationVisitor visitAnnotation(String desc, boolean visible){}
/**
*
* @param attr
*/
public void visitAttribute(Attribute attr){}
/**
*
* @param name
* @param outerName
* @param innerName
* @param access
*/
public void visitInnerClass(String name, String outerName, String innerName, int access){}
/**
*
* @param access
* @param name
* @param desc
* @param signature
* @param value
* @return
*/
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value){}
/**
*
* @param access
* @param name
* @param desc
* @param signature
* @param exceptions
* @return
*/
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions){}
/**
*
*/
void visitEnd(){}
}
3. MethodVisitor文檔備注
visitAnnotationDefault?
( visitAnnotation | visitParameterAnnotation | visitAttribute )*
( visitCode
( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn |
visitLocalVariable | visitLineNumber )*
visitMaxs )?
visitEnd
這就意味著,對于非抽象方法,如果存在注釋和屬性的話,必須首先訪問它們,
然后是該方法的字節(jié)代碼。
對于這些方法,其代碼必須按順序訪問,
位于對 visitCode 的調(diào)用(有且僅有一個調(diào)用)與對 visitMaxs 的調(diào)用(有且僅有一個調(diào)用)之間。
//MethodVisitor備忘文檔,待完善
abstract class MethodVisitor {
/**
*
* @param api
*/
MethodVisitor(int api);
/**
*
* @param api
* @param mv
*/
MethodVisitor(int api, MethodVisitor mv);
/**
*
* @return
*/
AnnotationVisitor visitAnnotationDefault();
/**
*
* @param desc
* @param visible
* @return
*/
AnnotationVisitor visitAnnotation(String desc, boolean visible);
/**
*
* @param parameter
* @param desc
* @param visible
* @return
*/
AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible);
/**
*
* @param attr
*/
void visitAttribute(Attribute attr);
/**
*
*/
void visitCode();
/**
*
* @param type
* @param nLocal
* @param local
* @param nStack
* @param stack
*/
void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack);
/**
*
* @param opcode
*/
void visitInsn(int opcode);
/**
*
* @param opcode
* @param operand
*/
void visitIntInsn(int opcode, int operand);
/**
*
* @param opcode
* @param var
*/
void visitVarInsn(int opcode, int var);
/**
*
* @param opcode
* @param desc
*/
void visitTypeInsn(int opcode, String desc);
/**
*
* @param opc
* @param owner
* @param name
* @param desc
*/
void visitFieldInsn(int opc, String owner, String name, String desc);
/**
*
* @param opc
* @param owner
* @param name
* @param desc
*/
void visitMethodInsn(int opc, String owner, String name, String desc);
/**
*
* @param name
* @param desc
* @param bsm
* @param bsmArgs
*/
void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs);
/**
*
* @param opcode
* @param label
*/
void visitJumpInsn(int opcode, Label label);
/**
*
* @param label
*/
void visitLabel(Label label);
/**
*
* @param cst
*/
void visitLdcInsn(Object cst);
/**
*
* @param var
* @param increment
*/
void visitIincInsn(int var, int increment);
/**
*
* @param min
* @param max
* @param dflt
* @param labels
*/
void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels);
/**
*
* @param dflt
* @param keys
* @param labels
*/
void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels);
/**
*
* @param desc
* @param dims
*/
void visitMultiANewArrayInsn(String desc, int dims);
/**
*
* @param start
* @param end
* @param handler
* @param type
*/
void visitTryCatchBlock(Label start, Label end, Label handler, String type);
/**
*
* @param name
* @param desc
* @param signature
* @param start
* @param end
* @param index
*/
void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index);
/**
*
* @param line
* @param start
*/
void visitLineNumber(int line, Label start);
/**
*
* @param maxStack
* @param maxLocals
*/
void visitMaxs(int maxStack, int maxLocals);
/**
*
*/
void visitEnd();
}
| 字段名 | 格式 | 備注 |
|---|---|---|
| owner | "java/lang/System" | |
| name | "out" | |
| descriptor | "Ljava/io/PrintStream;" |

指令轉(zhuǎn)換為ASM代碼解釋
| 指令 | ASM方法 | 備注 |
|---|---|---|
| LDC | mv.visitLdcInsn("字符串") | |
| ALOAD 0 | ||
| ASTORE 1 | ||
| ICONST_0 | ||
| ICONST_3 | ||
| ALOAD 1 | ||
| ILOAD 2 | ||
| ASTORE 3 | ||
| int x = newLocal(Type.LONG_TYPE); | 創(chuàng)建一個long型的局部變量, 返回值是varIndex(局部變量編號) |