java agent-03-Java Instrumentation 结合 bytekit 实战条记 agent attach ...

打印 上一主题 下一主题

主题 881|帖子 881|积分 2643

java agent 系列

java agent 先容
java agent-02-Java Instrumentation API
java agent-03-Java Instrumentation 结合 bytekit 实战条记 agent attach
java agent-03-Java Instrumentation 结合 bytekit 实战条记 agent premain
拓展阅读

前面几篇文档,我们简朴先容了一下 java Instrumentation。
java agent 先容
Java Instrumentation API
本篇我们结合一下 bytekit 进行现实的文件修改。
测试代码

团体目次
  1.     │  │  └─com
  2.     │  │      └─github
  3.     │  │          └─houbb
  4.     │  │              └─bytekit
  5.     │  │                  └─learn
  6.     │  │                      └─agentattach
  7.     │  │                          │  AgentAttachMain.java
  8.     │  │                          │  MyAttachMain.java
  9.     │  │                          │  MyClassFileTransformer.java
  10.     │  │                          │  package-info.java
  11.     │  │                          │
  12.     │  │                          └─interceptor
  13.     │  │                                  SampleInterceptor.java
  14.     │  │
  15.     │  └─resources
  16.     │      └─META-INF
  17.     │              MANIFEST.MF
  18.     │
  19.     └─test
  20.         └─java
  21.             └─com.github.houbb.bytekit.learn.agentattach
  22.                     Sample.java
  23.                     TestMain.java
复制代码
MANIFEST.MF
  1. Manifest-Version: 1.0
  2. Agent-Class: com.github.houbb.bytekit.learn.agentattach.AgentAttachMain
  3. Can-Redefine-Classes: true
  4. Can-Retransform-Classes: true
复制代码
AgentAttachMain-核心入口

这里指定了核心入口 AgentAttachMain

  • AgentAttachMain.java
动态 Attach 的 agent 与通过 JVM 启动 javaagent 参数指定的 agent jar 包的方式有所差异,动态 Attach 的 agent 会执行 agentmain 方法,而不是 premain 方法。
  1. package com.github.houbb.bytekit.learn.agentattach;
  2. import java.lang.instrument.ClassFileTransformer;
  3. import java.lang.instrument.Instrumentation;
  4. import java.lang.instrument.UnmodifiableClassException;
  5. public class AgentAttachMain {
  6.     /**
  7.      * 动态 Attach 的 agent 会执行 agentmain 方法,而不是 premain 方法。
  8.      *
  9.      * @param agentArgs
  10.      * @param inst
  11.      * @throws ClassNotFoundException
  12.      * @throws UnmodifiableClassException
  13.      */
  14.     public static void agentmain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException {
  15.         System.out.println("agentmain called");
  16.         Class classes[] = inst.getAllLoadedClasses();
  17.         for (int i = 0; i < classes.length; i++) {
  18.             String className = classes[i].getName();
  19.             System.out.println(className);
  20.             // 这里是正常的全称
  21.             if (className.equals("com.github.houbb.bytekit.learn.agentattach.Sample")) {
  22.                 System.out.println("Reloading start: " + className);
  23.                 // 真实的替换
  24.                 final ClassFileTransformer transformer = new MyClassFileTransformer();
  25.                 inst.addTransformer(transformer, true);
  26.                 inst.retransformClasses(classes[i]);
  27.                 inst.removeTransformer(transformer);
  28.                 System.out.println("Reloading done: " + className);
  29.                 break;
  30.             }
  31.         }
  32.     }
  33. }
复制代码
MyClassFileTransformer 和上一篇雷同,这里不外利用 bytekit 时要区分一下 install 的方式,或者会卡主。
此处不再赘述。
attach-main

创建MyAttachMain类,实现attach到目标进程 (为了方便我还是放在agent项目中)
由于是跨进程通信,Attach 的发起端是一个独立的 java 程序,这个 java 程序会调用 VirtualMachine.attach 方法开始和目标 JVM 进行跨进程通信。
下面的PID通过jps查看对应的进程ID,如11901
jarPath 为当前 agent 的完备包路径。
  1. package com.github.houbb.bytekit.learn.agentattach;
  2. import com.github.houbb.bytekit.tool.utils.AttachHelper;
  3. import com.sun.tools.attach.VirtualMachine;
  4. public class MyAttachMain {
  5.     /**
  6.      * 指定 pid 进行 attch
  7.      *
  8.      * @param args
  9.      * @throws Exception
  10.      */
  11.     public static void main(String[] args) throws Exception {
  12.         String pid = "15708";
  13.         String jarPath = "D:\\github\\bytekit-learn\\bytekit-learn-agentattach\\target\\bytekit-learn-agentattach-1.0-SNAPSHOT.jar";
  14.         AttachHelper.attach(jarPath, pid);
  15.         // 通过 jps 查看
  16.         VirtualMachine vm = VirtualMachine.attach(pid);
  17.         try {
  18.             vm.loadAgent(jarPath);
  19.         } finally {
  20.             vm.detach();
  21.         }
  22.     }
  23. }
复制代码
测试

启动测试类

为了演示 attach,我们提供一个不绝循环的测试类:
  1. public class TestMain {
  2.     public static void main(String[] args) throws InterruptedException {
  3.         while (true) {
  4.             Sample sample = new Sample();
  5.             String result = sample.hello("123", false);
  6.             System.out.println(result);
  7.             TimeUnit.SECONDS.sleep(3);
  8.         }
  9.     }
  10. }
复制代码
首先启动测试类。通过 jps 获取对应的信息
  1. 14028 RemoteMavenServer36
  2. 15100 Launcher
  3. 15708 TestMain
复制代码
编译 agent

通过 mvn clean install 编译我们的 agent 包,生成在路径:
  1. D:\\github\\bytekit-learn\\bytekit-learn-agentattach\\target\\bytekit-learn-agentattach-1.0-SNAPSHOT.jar
复制代码
修改 attach-main 并启动

直接把 MyAttachMain 的 pid + agent 路径修改为对应的。启动测试:
对应的日记如下,实现已经被替换了
  1. com.github.houbb.bytekit.learn.agentattach.Sample
  2. Reloading start: com.github.houbb.bytekit.learn.agentattach.Sample
  3. start transform name=== com/github/houbb/bytekit/learn/agentattach/Sample
  4. /*
  5. * Decompiled with CFR.
  6. */
  7. package com.github.houbb.bytekit.learn.agentattach;
  8. public class Sample {
  9.     private int exceptionCount = 0;
  10.     /*
  11.      * WARNING - void declaration
  12.      */
  13.     public String hello(String string, boolean bl) {
  14.         try {
  15.             String string2;
  16.             void str;
  17.             void exception;
  18.             try {
  19.                 String string3 = "(Ljava/lang/String;Z)Ljava/lang/String;";
  20.                 String string4 = "hello";
  21.                 Object[] objectArray = new Object[]{string, new Boolean(bl)};
  22.                 Class<Sample> clazz = Sample.class;
  23.                 Sample sample = this;
  24.                 System.out.println("atEnter, args[0]: " + objectArray[0]);
  25.             }
  26.             catch (RuntimeException runtimeException) {
  27.                 Class<Sample> clazz = Sample.class;
  28.                 RuntimeException runtimeException2 = runtimeException;
  29.                 System.out.println("exception handler: " + clazz);
  30.                 runtimeException2.printStackTrace();
  31.             }
  32.             if (exception != false) {
  33.                 ++this.exceptionCount;
  34.                 throw new RuntimeException("test exception, str: " + (String)str);
  35.             }
  36.             String string5 = string2 = "hello " + (String)str;
  37.             System.out.println("atExit, returnObject: " + string5);
  38.             return string2;
  39.         }
  40.         catch (RuntimeException runtimeException) {
  41.             int n = this.exceptionCount;
  42.             RuntimeException runtimeException3 = runtimeException;
  43.             System.out.println("atExceptionExit, ex: " + runtimeException3.getMessage() + ", field exceptionCount: " + n);
  44.             throw runtimeException;
  45.         }
  46.     }
  47. }
  48. end transform name=== com/github/houbb/bytekit/learn/agentattach/Sample
  49. Reloading done: com.github.houbb.bytekit.learn.agentattach.Sample
  50. atEnter, args[0]: 123
  51. atExit, returnObject: hello 123
  52. hello 123
  53. atEnter, args[0]: 123
  54. atExit, returnObject: hello 123
  55. hello 123
  56. atEnter, args[0]: 123
  57. atExit, returnObject: hello 123
  58. hello 123
  59. atEnter, args[0]: 123
  60. atExit, returnObject: hello 123
  61. hello 123
复制代码
拓展阅读

VirtualMachine 类不存在

添加jdk tools.jar解决com.sun.tools.attach.VirtualMachine 类找不到的标题
发现设置了 java_home 及相关信息还是不可,可以手动在项目中引入。
idea 就是 libs 种添加依赖。
参考资料

https://blog.51cto.com/zhangxueliang/5667216
https://www.cnblogs.com/756623607-zhang/p/12575509.html

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表