ClassNode信息
类型 | 名称 | 说明 |
---|---|---|
int | version | class文件的major版本(编译的java版本) |
int | access | 访问级 |
String | name | 类名,采用全地址,如java/lang/String |
String | signature | 签名,通常是null |
String | superName | 父类类名,采用全地址 |
List | interfaces | 实现的接口,采用全地址 |
String | sourceFile | 源文件,可能为null |
String | sourceDebug | debug源,可能为null |
String | outerClass | 外部类 |
String | outerMethod | 外部方法 |
String | outerMethodDesc | 外部方法描述(包括方法参数和返回值) |
List | visibleAnnotations | 可见的注解 |
List | invisibleAnnotations | 不可见的注解 |
List | attrs | 类的Attribute |
List | innerClasses | 类的内部类列表 |
List | fields | 类的字段列表 |
List | methods | 类的方法列表 |
FieldNode信息
类型 | 名称 | 说明 |
---|---|---|
int | access | 访问级 |
String | name | 字段名 |
String | signature | 签名,通常是 null |
String | desc | 类型描述,例如 Ljava/lang/String、D(double)、F(float) |
Object | value | 初始值,通常为 null |
List | visibleAnnotations | 可见的注解 |
List | invisibleAnnotations | 不可见的注解 |
List | attrs | 字段的 Attribute |
MethodNode信息
类型 | 名称 | 说明 |
---|---|---|
int | access | 访问级 |
String | name | 方法名 |
String | desc | 方法描述,其包含方法的返回值和参数 |
String | signature | 签名,通常是null |
List | exceptions | 可能返回的异常列表 |
List | visibleAnnotations | 可见的注解列表 |
List | invisibleAnnotations | 不可见的注解列表 |
List | attrs | 方法的Attribute列表 |
Object | annotationDefault | 默认的注解 |
List[] | visibleParameterAnnotations | 可见的参数注解列表 |
List[] | invisibleParameterAnnotations | 不可见的参数注解列表 |
InsnList | instructions | 操作码列表 |
List | tryCatchBlocks | try-catch块列表 |
int | maxStack | 最大操作栈的深度 |
int | maxLocals | 最大局部变量区的大小 |
List | localVariables | 本地(局部)变量节点列表 |
Instructions指令码信息
名称 | 说明 | 参数 |
---|---|---|
FieldInsnNode | 用于 GETFIELD 和 PUTFIELD 之类的字段操作的字节码 | String owner 字段所在的类 String name 字段的名称 String desc 字段的类型 |
FrameNode | 栈映射帧的对应的帧节点 | 待补充 |
IincInsnNode | 用于 IINC 变量自加操作的字节码 | int var:目标局部变量的位置 int incr: 要增加的数 |
|
| InsnNode | 一切无参数值操作的字节码,例如 ALOAD0,DUP(注意不包含 POP) | 无 |
| IntInsnNode | 用于 BIPUSH、SIPUSH 和 NEWARRAY 这三个直接操作整数的操作 | int operand:操作的整数值 |
| InvokeDynamicInsnNode | 用于 Java7 新增的 INVOKEDYNAMIC 操作的字节码 | String name:方法名称
String desc:方法描述
Handle bsm:句柄
Object[] bsmArgs:参数常量 |
| JumpInsnNode | 用于 IFEQ 或 GOTO 等跳转操作字节码 | LabelNode lable:目标 lable |
| LabelNode | 一个用于表示跳转点的 Label 节点 | 无 |
| LdcInsnNode | 使用 LDC 加载常量池中的引用值并进行插入的字节码 | Object cst:引用值 |
| LineNumberNode | 表示行号的节点 | int line:行号
LabelNode start:对应的第一个 Label |
| LookupSwitchInsnNode | 用于实现 LOOKUPSWITCH 操作的字节码 | LabelNode dflt:default 块对应的 Lable
List keys 键列表
List labels:对应的 Label 节点列表 |
| MethodInsnNode | 用于 INVOKEVIRTUAL ,_INVOKESTATIC,INVOKESPECIAL
等传统方法调用操作的字节码,不适用于 Java7 新增的 INVOKEDYNAMIC | String owner :方法所在的类
String name :方法名称
String desc:方法描述 |
| MultiANewArrayInsnNode | 用于 MULTIANEWARRAY 操作的字节码 | String desc:类型描述
int dims:维数 |
| TableSwitchInsnNode | 用于实现 TABLESWITCH 操作的字节码 | int min:键的最小值
int max:键的最大值
LabelNode dflt:default 块对应的 Lable
List labels:对应的 Label 节点列表 |
| TypeInsnNode | 用于实现 NEW、ANEWARRAY 和 CHECKCAST 等类型相关操作的字节码 | String desc:类型
| | VarInsnNode | 用于实现 ALOAD、ASTORE 等局部变量操作的字节码 | int var:局部变量 |
指令码操作
添加
add(AbstractInsnNode insn)
: 将一个操作码添加到 InsnList 的末尾。insert(AbstractInsnNode insn)
: 将一个操作码插入到这个 InsnList 的开头。insert(AbstractInsnNode insnNode,AbstractInsnNode insn)
: 将一个操作码插入到另一个操作码的下面。insertBefore(AbstractInsnNode insnNode,AbstractInsnNode insn)
将一个操作码插入到另一个操作码的上面
比如要将
thread.setName("helo name");
替换为
thread.setName(ShadowThread.makeThreadName("helo name", "\u200bnet.mikaelzero.myapplication.Test"));
通过javap得出对应的字节码
ldc #6 // String helo name
invokevirtual #7 // Method java/lang/Thread.setName:(Ljava/lang/String;)V
19 ldc #26 <helo name>
21 ldc #21 <net.mikaelzero.myapplication.Test>
23 invokestatic #30 <com/didiglobal/booster/instrument/ShadowThread.makeThreadName>
26 invokevirtual #36 <java/lang/Thread.setName>
因此我们可以在原字节码操作列表的 invokevirtual 节点的前面插入,比如
method.instructions.insertBefore(this, LdcInsnNode(makeThreadName(klass.className)))
method.instructions.insertBefore(this, MethodInsnNode(Opcodes.INVOKESTATIC, SHADOW_THREAD, "setThreadName", "(Ljava/lang/Thread;Ljava/lang/String;)Ljava/lang/Thread;", false))