ddostest123

0x01 Java Agent

JavaAgent有两种使用方式。

  1. 第一种是在 JVM启动的时候加载,通过 javaagent 启动参数,在程序main方法执行之前执行agent 中的premain 方法。

  2. 第二种方式是在 JVM启动后进行Attach,通过Attach API进行加载,在agent加载以后执行agentmain 方法。

0x02 javaagent

对于第一种方式,javaagent是java命令的其中一个参数,-javaagent用于指定一个 jar 包,可装载多个agent。

其与java.lang.instrument有关,java.lang.instrument在jre中lib里面的rt.jar包。

image-20221127010052017

对于javaagent的jar包,其需满足:

  • MANIFEST.MF文件必须指定Premain-Class。

  • Premain-Class指定的类必须实现一个公共静态premain方法。

image-20221127011151878

https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html

JVM初始化后,执行premain方法,再执行main方法。
该premain方法的定义为:

public static void premain(String agentArgs, Instrumentation inst);
public static void premain(String agentArgs);

JVM初始化后会先加载定义了Instrumentation的第一种类型方法,加载成功则忽略第二种。

如果第一种类型没定义,则加载第二种方法。

image-20221127013127872

在rt.jar包的java.lang.instrument中,Instrumentation接口定义了若干个方法:

image-20221127013442172

https://www.cnblogs.com/rickiyang/p/11368932.html

public interface Instrumentation {
    void addTransformer(ClassFileTransformer var1, boolean var2);
    void addTransformer(ClassFileTransformer var1);
    boolean removeTransformer(ClassFileTransformer var1);
    boolean isRetransformClassesSupported();
    void retransformClasses(Class<?>... var1) throws UnmodifiableClassException;
    boolean isRedefineClassesSupported();
    void redefineClasses(ClassDefinition... var1) throws ClassNotFoundException, UnmodifiableClassException;
    boolean isModifiableClass(Class<?> var1);
    Class[] getAllLoadedClasses();
    Class[] getInitiatedClasses(ClassLoader var1);
    long getObjectSize(Object var1);
    void appendToBootstrapClassLoaderSearch(JarFile var1);
    void appendToSystemClassLoaderSearch(JarFile var1);
    boolean isNativeMethodPrefixSupported();
    void setNativeMethodPrefix(ClassFileTransformer var1, String var2);
}

其中,常用的方法的作用如下:

  1. 增加Class文件的转换器,用于改变 Class 二进制流的数据,参数 canRetransform 设置是否允许重新转换。

void addTransformer(ClassFileTransformer var1, boolean var2);

  1. 增加Class文件的转换器,在类加载之前,重新定义 Class 文件,ClassDefinition 表示对一个类新的定义。

void addTransformer(ClassFileTransformer var1);

  1. 读取Class文件的转换器,读取重新定义 的Class 文件。

void redefineClasses(ClassDefinition... var1) throws ClassNotFoundException, UnmodifiableClassException;

  1. 重读取Class文件的转换器,如果在类加载之后,需要使用 retransformClasses 方法重新定义。对于已经加载过的类,可以使用retransformClasses来重新触发这个Transformer的拦截。

void retransformClasses(Class<?>... var1) throws UnmodifiableClassException;

  1. 删除Class文件的转换器,删除重新定义 的Class 文件。

boolean removeTransformer(ClassFileTransformer var1);

0x03 Before main

1、测试demo

image-20221127020223527

2、测试agent

image-20221127020350545

3、装载agent

image-20221127020638912

可以看到premain方法先main方法执行。

0x04 Replace Return

1、测试demo

image-20221127180015536

通过Javaagent,在main方法加载执行前,将num方法中的返回值修改为2。

2、测试agent

image-20221127180500558

通过premain方法,调用增加Class文件的转换器addTransformer来改变 Class 二进制流的数据。

接着继承和重写ClassFileTransformer类中的transform方法,

在定位修改的目标类和方法后,通过使用javassist来修改目标方法中的代码和返回值。

3、装载agent

image-20221127181419465

最后成功修改目标方法的代码和返回值。