Javassist是一个开源的、用于分析、编辑和创建Java字节码的类库
Javassist的使用
Maven
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
jar
https://gitee.com/mirrors/Javassist.git
核心的类
含义如其名:Javassist的类池,使用ClassPool类可以跟踪和控制所操作的类,工作方式与JVM类装载器类似
该容器的键为类名称,值为CtClass对象
常用方法
static ClassPool getDefault()
// 返回默认的类池
ClassPath insertClassPath(java.lang.String pathname)
// 在搜索路径的开头插入目录或jar(或zip)文件
ClassPath insertClassPath(ClassPath cp)
// ClassPath在搜索路径的开头插入一个对象
java.lang.ClassLoader getClassLoader()
// 获取类加载器toClass(),getAnnotations()在 CtClass等
CtClass get(java.lang.String classname)
// 从源中读取类文件,并返回对CtClass 表示该类文件的对象的引用
ClassPath appendClassPath(ClassPath cp)
// 将ClassPath对象附加到搜索路径的末尾
CtClass makeClass(java.lang.String classname)
// 创建一个新的public类
CtClass提供了对类的操作,如在类中添加新字段、方法和构造函数,改变父类和接口的方法等
一般一个CtClass类用于处理一个class文件,CtClass对象可以从ClassPool获得
常用方法
void setSuperclass(CtClass clazz)
// 更改超类,除非此对象表示接口
java.lang.Class<?> toClass(java.lang.invoke.MethodHandles.Lookup lookup)
// 将此类转换为java.lang.Class对象
byte[] toBytecode()
// 将该类转换为类文件
void writeFile()
// 将由此CtClass对象表示的类文件写入当前目录
void writeFile(java.lang.String directoryName)
// 将由此CtClass对象表示的类文件写入本地磁盘
CtConstructor makeClassInitializer()
// 制作一个空的类初始化程序(静态构造函数)
类的属性
通过该类可以修改类的属性,给类创建新的属性,还可以修改访问控制符等
常用方法
// 获取已知类的属性
CtField ctField = ctClass.getDeclaredField("name");
// 构建新的类的成员变量
CtField ctFieldNew = new CtField(CtClass.intType,"age",ctClass);
// 设置类的访问修饰符为public
ctFieldNew.setModifiers(Modifier.PUBLIC);
// 将属性添加到类中
ctClass.addField(ctFieldNew);
类的方法
通过该类可以修改类中的方法,给类创建新的方法,修改访问控制符,甚至还可以修改方法体的内容
常用方法
// 获取已有方法
// 创建新的方法, 参数1:方法的返回类型,参数2:名称,参数3:方法的参数,参数4:方法所属的类
CtMethod ctMethod = new CtMethod(CtClass.intType, "calc", new CtClass[] {CtClass.intType,CtClass.intType}, tClass);
// 设置方法的访问修饰
ctMethod.setModifiers(Modifier.PUBLIC);
// 将新建的方法添加到类中
ctClass.addMethod(ctMethod);
// 方法体内容代码 $1代表第一个参数,$2代表第二个参数
ctMethod.setBody("return $1 + $2;");
类的构造方法,与CtMethod类似
获取类文件的搜索路径
测试类
编写一个测试类
javassistTest.java
package com.audit;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtField;
import javassist.Modifier;
import javassist.CtNewMethod;
import javassist.CtConstructor;
public class javassistTest {
public static void createt4rrega() throws Exception {
// 创建一个ClassPool对象,用于后续创建类、字段、构造方法等
ClassPool pool = ClassPool.getDefault();
// 创建一个空类,makeClass的值为全类名
CtClass ctClass = pool.makeClass("com.javassist.t4rrega");
// 新增一个字段 private String name;
// 字段名为name
CtField param = new CtField(pool.get("java.lang.String"), "name", ctClass);
// 修饰符是 private
param.setModifiers(Modifier.PRIVATE);
// 初始值是 "t4rrega"
ctClass.addField(param, CtField.Initializer.constant("t4rrega"));
// 生成 param参数的getter&setter方法
ctClass.addMethod(CtNewMethod.setter("setName", param));
ctClass.addMethod(CtNewMethod.getter("getName", param));
// 添加类的无参的构造函数
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
ctConstructor.setBody("{name = "t4rrega";}");
ctClass.addConstructor(ctConstructor);
// 添加有参的构造函数
ctConstructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, ctClass);
// $0=this / $1,$2,$3代表方法参数
ctConstructor.setBody("{$0.name = $1;}");
ctClass.addConstructor(ctConstructor);
// 创建一个名为printName方法,无参数,无返回值,输出name值
CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, ctClass);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{System.out.println(name);}");
ctClass.addMethod(ctMethod);
// 将该类编译为class文件到指定目录下
ctClass.writeFile("./");
}
public static void main(String[] args) throws Exception {
createt4rrega();
}
}
编译运行,生成的字节码文件如下
原文始发于微信公众号(安全宇宙):【创宇小课堂】代码审计-Javassist
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论