基本环境配置

runwu2204 Lv6

instrumentation

Java探针技术-instrutment中retransformClasses和redefineClasses - 洛神灬殇 - 博客园

探秘 Java 热部署三(Java agent agentmain) - 莫那-鲁道 - 博客园

1000个字带你一次性搞懂JavaAgent技术,反正我是彻底服了-腾讯云开发者社区-腾讯云

jar包封装方式可参考封装jar包 | Runwu2204

premain

先于main执行

在MANIFEST中插入

1
Premain-Class: xxx.xxx.xxx

对应类中需要带有

1
public static void Agentmain(String agentArgs, Instrumentation inst)

调用方式

在-jar前面加入 -javaagent:xxx.jar

具体类似java -javaagent:agent.jar -jar main.jar(agent jar指对应带Agent-Class或者Premain-Class的jar包 而main.jar指的是对应带main 也就是需要被hook的jar包)

主要使用transform(相当于加载class前需要调用的函数)来实现加载对应class时调用修改函数

则需要加入

Can-Retransform-Classes: true Can-Redefine-Classes: true

否则会报unsupported

1
2
3
Premain-Class: xxx.xxx.xxx
Can-Retransform-Classes: true
Can-Redefine-Classes: true

agentmain

在类加载后执行

在MANIFEST中插入

1
Agent-Class: xxx.xxx.xxx

对应类中需要带有

1
public static void agentmain(String agentArgs, Instrumentation instrumentation)

调用方式

使用

1
2
VirtualMachine vm = VirtualMachine.attach("xxx");
vm.loadAgent("xxx.jar");//会调用里面注册好的agentmain方法

exp:

使用premain修改构造函数,添加新函数

AgentMainTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package org.example;
import javassist.*;

import java.lang.instrument.ClassDefinition;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class AgentMainTest {
static {

}
public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
System.out.println("开始代理 Agent");
instrumentation.addTransformer(new Transformer(),true);

}
static class Transformer implements ClassFileTransformer{
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(className.contains("java/util/Date")){
try{
System.out.println("IN:"+className);
ClassPool classPool=ClassPool.getDefault();
CtClass clazz=classPool.get("java.util.Date");
//动态添加test函数
CtMethod ctMethod = new CtMethod(CtClass.intType, "test", new CtClass[]{CtClass.intType}, clazz);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{return $1;}");
clazz.addMethod(ctMethod);
//动态修改构造函数
CtConstructor ctConstructor=clazz.getDeclaredConstructor(new CtClass[]{});
ctConstructor.setBody("this(0L);");
return clazz.toBytecode();
}catch (Exception e){
System.out.println("error:"+className);
}
}
else{
try{
//其他情况直接返回
ClassPool classPool=ClassPool.getDefault();
CtClass clazz=classPool.get(className);
return clazz.toBytecode();
}catch (Exception e){

}
}
return null;
}
}
}

Main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.example;
import javassist.*;

import java.lang.instrument.Instrumentation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Date dt=new Date();
Method nmethod=Date.class.getDeclaredMethod("test",new Class[]{int.class});

System.out.println(String.valueOf(dt));
System.out.println(nmethod.invoke(dt,1));

// Press Shift+F10 or click the green arrow button in the gutter to run the code.
}
}

MANIFEST.MF

1
2
3
4
5
6
7
8
Manifest-Version: 1.0
Can-Redefine-Classes: true
Premain-Class: org.example.AgentMainTest
Can-Retransform-Classes: true
Can-Redefine-Classes: true
Main-Class: org.example.Main
Class-Path: javassist-3.25.0-GA.jar

jar包结构

image-20241123023901306

运行结果

image-20241123023930393

使用agentmain动态补丁

注意需要导入对应版本java的lib下的tools.jar

image-20241123144439254

导入方式类似这样

image-20241123145025676

项目结构

image-20241123145311019

AgentMainTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.example;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;

public class AgentMainTest {
public AgentMainTest() {
}

public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
System.out.println("premain 开始代理 Agent");
instrumentation.addTransformer(new Transformer(), true);
}

public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
System.out.println("agentmain 开始代理 Agent");
instrumentation.addTransformer(new Transformer(), true);
}

static class Transformer implements ClassFileTransformer {
Transformer() {
}

public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
ClassPool classPool;
CtClass clazz;
if (className.contains("java/util/Date")) {
try {
System.out.println("IN:" + className);
classPool = ClassPool.getDefault();
clazz = classPool.get("java.util.Date");
CtMethod ctMethod = new CtMethod(CtClass.intType, "test", new CtClass[]{CtClass.intType}, clazz);
ctMethod.setModifiers(1);
ctMethod.setBody("{return $1;}");
clazz.addMethod(ctMethod);
CtConstructor ctConstructor = clazz.getDeclaredConstructor(new CtClass[0]);
ctConstructor.setBody("this(0L);");
return clazz.toBytecode();
} catch (Exception var10) {
System.out.println("error:" + className);
}
} else {
try {
classPool = ClassPool.getDefault();
clazz = classPool.get(className);
return clazz.toBytecode();
} catch (Exception var11) {
}
}

return null;
}
}
}

Main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package org.example;
import javassist.*;
import com.sun.tools.attach.*;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {

public static void main(String[] args) throws Exception {
String name = ManagementFactory.getRuntimeMXBean().getName();//会获得pid@计算机id
String Pid=name.split("@")[0];//获取pid
// 使用VirtualMachine类来attach到当前进程
VirtualMachine vm = VirtualMachine.attach(Pid);
//加载agent
vm.loadAgent("unnamed.jar");
Date dt=new Date();
Method nmethod=Date.class.getDeclaredMethod("test",new Class[]{int.class});
System.out.println(String.valueOf(dt));
System.out.println(nmethod.invoke(dt,1));
}
}

MANIFEST.MF

1
2
3
4
5
6
7
8
9
Manifest-Version: 1.0
Can-Redefine-Classes: true
Premain-Class: org.example.AgentMainTest
Agent-Class: org.example.AgentMainTest
Can-Retransform-Classes: true
Can-Redefine-Classes: true
Main-Class: org.example.Main
Class-Path: javassist-3.25.0-GA.jar tools.jar

Class-Path 注意路径就是当前路径的相对地址 此处我直接在unamed文件夹调用的所以直接用这个地址

image-20241123145338596

运行效果

image-20241123145551638

  • 标题: 基本环境配置
  • 作者: runwu2204
  • 创建于 : 2024-11-22 23:15:58
  • 更新于 : 2024-11-23 15:05:39
  • 链接: https://runwu2204.github.io/2024/11/22/开发/JAVA/JAVA-agent/基本环境配置/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论