破解 Java Agent 探针黑科技( 二 )


 

破解 Java Agent 探针黑科技

文章插图
 
 
Java Agent 所使用的 Instrumentation 依赖 JVMTI 实现 , 当然也可以绕过 Instrumentation 直接使用 JVMTI 实现 Agent 。因此 , JVMTI 与 JDI 组成了 Java 平台调试体系(JPDA)的主要能力 。
如果想要深入了解 Java Agent,就得需要了解 JVMTI 以及 JVMTIAgent , 下面分别介绍下:
JVMTIJVMTI 是 JVM Tool Interface 的缩写 , 是 JVM 暴露出来给用户扩展使用的接口集合 , JVMTI 是基于事件驱动的 , JVM 每执行一定的逻辑就会调用一些事件的回调接口 , 这些接口可以给用户自行扩展来实现自己的逻辑 。JVMTI 是实现 Debugger、Profiler、Monitor、Thread Analyser 等工具的统一基础 , 在主流 Java 虚拟机中都有实现 。
JVMTIAgentJVMTI 并不一定在所有的 Java 虚拟机上都有实现 , 不同的虚拟机的实现也不尽相同 。不过在一些主流的虚拟机中 , 比如 Sun 和 IBM , 以及一些开源的如 Apache Harmony DRLVM 中 , 都提供了标准 JVMTI 实现 。
 
JVMTI 是一套本地代码接口 , 因此使用 JVMTI 需要我们与 C/C++ 以及 JNI 打交道 。事实上 , 开发时一般采用建立一个 Agent 的方式来使用 JVMTI , 它使用 JVMTI 函数 , 设置一些回调函数 , 并从 Java 虚拟机中得到当前的运行态信息 , 并作出自己的判断 , 最后还可能操作虚拟机的运行态 。把 Agent 编译成一个动态链接库之后 , 我们就可以在 Java 程序启动的时候来加载它(启动加载模式) , 也可以在 Java 5 之后使用运行时加载(活动加载模式) 。
 
-agentlib:agent-lib-name=options
-agentpath:path-to-agent=options
 
JVMTIAgent主要有三个方法:
  • Agent_OnLoad 方法 , 如果 agent 在启动时加载 , 就执行这个方法
  • Agent_OnAttach方法 , 如果agent不是在启动的时候加载的 , 是我们先attach到目标线程上 , 然后对对应的目标进程发送load命令来加载agent , 在加载过程中调用Agent_OnAttach函数
  • Agent_OnUnload 方法 , 在 agent 做卸载掉时候调用
Instrument Agent说到 javaagent , 必须要讲的是一个叫做 instrument 的 JVMTIAgent(linux下对应的动态库是 libinstrument.so)instrument agent 实现了上面 Agent_OnLoad 方法和 Agent_OnAttach 方法 , 也就是即能在启动的时候加载 agent , 也可以在运行期来加动态加载 agent , 运行期动态加载 agent 依赖 JVM 的 attach 机制实现 , 通过发送 load 命令来加载 agent
那么什么是 JVM Attach 机制?
JVM Attach 机制Jvm attach 机制是指 JVM 提供的一种 JVM 进程间通信的功能 , 能让一个进程传命令给另一个进程 , 并进行一些内部的操作 , 比如进行线程 dump , 那么就需要执行 jstack 进行 , 然后把 pid 等参数传递给需要 dump 的线程来执行 , 这就是一种 java attach 。
四、可以实现 Java Agent 的技术框架有哪些?原理了解清楚了就需要实现 , Java Agent 从实现上来看主要涉及到字节码增强的过程 , 其到过程大概是:
  • 修改字节码
  • 加载新的字节码
  • 替换旧的字节码
 
通过上面对 Java Agent 介绍之后 , 是不是发现 , 我想要实现一个 Java Agent 还得去深入学习那么多东西吗?
 
当然不用 , 这里就介绍几个常用的字节码增强工具:
  • ASM:对于需要手动操纵字节码的需求 , 可以使用 ASM , 它可以直接生成 .class 字节码文件 , 也可以在类被加载入 JVM 之前动态修改类行为 。

破解 Java Agent 探针黑科技

文章插图