在上篇文章中由于字数限制,没有将本文内容加进去,所以这里单独写一篇关于Java Agnet实际应用的文章。
如果你看完了上篇文章:关于Java Agent的使用、工作原理、及hotspot源码 解析,那么此篇的应用文章就相当轻松了 当然你需要使用过 mybatis plus 这个框架(因为我们本文是对这个框架的代码进行插桩) 不过我想干Java的这个(mybatis plus)应该是基本功,对这个框架就不多介绍了。
1、我们的目的:(写时加密,读时解密)
因为我这里使用baomidou(mybatis plus)开发的,所以直接找到这个方法(注意我可不是凭想象来的而是经过了对增删改查这几个方法的debug 最终发现baomidou的mybatis plus最终都会走com.baomidou.mybatisplus.core.override.MybatisMapperMethod
类的execute
方法,如下:) 所以说需要插桩的地方我们就找到了。接下来开干!
2、编写Java Agent
2.1、编写premain方法并实现ClassFileTransformer的transform类,以便类加载时回调到transform 从而对指定的类中的方法进行增强即 插桩!
```java
package com.xzll.agent.config;
import com.xzll.agent.config.advice.MysqlFieldEncryptAndDecryptAdvice; import javassist.*;
import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain;
/** * @Author: hzz * @Date: 2023/3/3 09:15:21 * @Description: MYSQL加解密 agent */ public class MysqlFieldCryptByExecuteBodyAgent {
/** * 实现了带Instrumentation参数的premain()方法。 */ public static void premain(String args, Instrumentation inst) throws Exception { //调用addTransformer()方法对启动时所有的类(应用层)进行拦截 inst.addTransformer(new MysqlReadWriteTransformer(), true); }
static class MysqlReadWriteTransformer implements ClassFileTransformer { /* * 如果事先知道哪些类需要修改,最简单的修改类方式如下: *
* 1、通过调用ClassPool.get()方法获取一个CtClass对象 * 2、修改它 * 3、调用CtClass对象的writeFile()或toBytecode()方法获取修改后的类文件 *
/ @Override public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //拦截指定要插桩 & 增强的类 if ("com/baomidou/mybatisplus/core/override/MybatisMapperMethod".equals(className)) { CtClass clazz = null; System.out.println("对MybatisMapperMethod执行插桩实现读解密,写加密。"); try { // 从ClassPool获得CtClass对象 (ClassPool对象是CtClass对象的容器,CtClass对象是类文件的抽象表示) final ClassPool classPool = ClassPool.getDefault(); //这一步必不可少 和类加载器有关系,且maven中要配置 addClasspath=true //不加的话插桩时找不到MysqlFieldEncryptAndDecryptAdvice这个类 classPool.insertClassPath(new ClassClassPath(MysqlFieldEncryptAndDecryptAdvice.class)); clazz = classPool.get("com.baomidou.mybatisplus.core.override.MybatisMapperMethod"); CtMethod getTime = clazz.getDeclaredMethod("execute"); String body = "{\n" + "return com.xzll.agent.config.advice.MysqlFieldEncryptAndDecryptAdvice.executeAgent($0,$1,$2);\n" + "}\n"; getTime.setBody(body); //通过CtClass的toBytecode(); 方法来获取 被修改后的字节码 return clazz.toBytecode(); } catch (Exception ex) { ex.printStackTr