本科毕设作过Python的RASP以后,对这项技术颇有兴趣,当时OpenRASP开始出现,而且Java的实现很是接近真正的运行时防护的概念。一直没有时间和足够的动力学习Java,最近一口气学了很多Java相关的东西,准备从反序列化和RASP两个方向继续深刻学一下Java。这边笔记主要也是记录整个学习过程,目标是仿照OpenRASP的java实现,完成一个Java的RASP。html
javaagent是java命令提供的一个参数,这个参数能够指定一个jar包,在真正的程序没有运行以前先运行指定的jar包。而且对jar包有两个要求:java
这个premain方法会在java命令行指定的main函数以前运行。c++
在java命令参数种,还能够看到其它参数,例如apache
-agentlib:<libname>[=<选项>] 加载本机代理库 <libname>, 例如 -agentlib:hprof 另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help -agentpath:<pathname>[=<选项>] 按完整路径名加载本机代理库 -javaagent:<jarpath>[=<选项>] 加载 Java 编程语言代理, 请参阅 java.lang.instrument
javaagent能够指定不少个,jvm会依次执行不一样的jar。前面提到的premain方法有两种定义方式编程
public static void premain(String agentArgs, Instrumentation inst) public static void premain(String agentArgs)
根据sun.instrument.InstrumentationImpl 的源代码,能够知道,会优先调用第一种写法。这种方法能够在JDK1.5及以后的版本使用jvm
使用javaagent须要几个步骤:maven
在premain方法执行时,获取的Instrumentation对象还会加载大部分类,包括后面main方法执行时须要加载的各类类,可是抓不到系统类。也就是说,在这个位置在main方法执行前,就能够拦截或者重写类,结合ASM、javassist、cglib方式就能够实现对类的改写或者插桩。编程语言
如今来实现一下,目录结构以下ide
-java-agent ----src ----|----main ----|----------java ----|--------------com ----|-------------------bitterz ----|----------------------PreMain ----|pom.xml
pom.xml使用idea建立maven项目自带的pom.xml便可,而后加入以下配置函数
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestEntries> <Premain-Class>com.bitterz.PreMain</Premain-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
修改里面的premain便可,这样配置以后,直接使用idea的maven->package就能够打包成一个可使用的agent.jar。
com.bitterz.PreMain以下:
package com.bitterz; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; public class PreMain { public static void premain(String agentArgs, Instrumentation inst){ System.out.println("agentArgs:" + agentArgs); inst.addTransformer(new DefineTransformer(), true); } static class DefineTransformer implements ClassFileTransformer{ @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { System.out.println("premain load Class: " + className); // 注意这里的输出 return classfileBuffer; } } }
而后再建立一个要执行的main
package com.bitterz; public class Main { public static void main(String[] args) { System.out.println("Main.main() in test project"); } }
一样修改pom.xml配置,只须要再<manifestEntries>
标签下添加一个<Main-Class>
便可用idea的maven打包成一个jar,而且指定了main类。
两个项目用maven打包后,在命令行执行一下
能够看到premain先输出了加载的各类类,包括com.bitterz.Main,而后才是真正的main执行,最后结束时,premain还加载了一些结束时须要的类。到此,在启动main方法前,实现对后续类的加载或进一步修改操做,已经有了雏形
前面的方法须要在main函数启动前,执行agent,但有些时候,jvm已经启动了,并且服务不能轻易暂停,但这个时候仍是想对jvm中的类作一些修改应该怎么办呢?
这就要引入attch机制了,jdk1.6以后在Instrumentation中添加了一种agentmain的代理方法,能够在main函数执行以后再运行。和premain函数同样,开发者能够编写一个包含agentmain函数的Java类,它也有两种写法:
public static void agentmain (String agentArgs, Instrumentation inst) public static void agentmain (String agentArgs)
一样的,带有Instrumentation的方法会被优先调用,开发者必须再MANIFEST.MF文件中设置Agent-Class
来指定包含agentmain函数的类。
这种attach机制的具体实如今com.sun.tools.attach
中,有以下两个类:
VirtualMachine
字面意义表示一个Java 虚拟机,也就是程序须要监控的目标虚拟机,提供了获取系统信息(好比获取内存dump、线程dump,类信息统计(好比已加载的类以及实例个数等), loadAgent,Attach 和 Detach (Attach 动做的相反行为,从 JVM 上面解除一个代理)等方法,能够实现的功能能够说很是之强大 。该类容许咱们经过给attach方法传入一个jvm的pid(进程id),远程链接到jvm上
代理类注入操做只是它众多功能中的一个,经过loadAgent
方法向jvm注册一个代理程序agent,在该agent的代理程序中会获得一个Instrumentation实例,该实例能够 在class加载前改变class的字节码,也能够在class加载后从新加载。在调用Instrumentation实例的方法时,这些方法会使用ClassFileTransformer接口中提供的方法进行处理。
VirtualMachineDescriptor
则是一个描述虚拟机的容器类,配合 VirtualMachine 类完成各类功能
具体实现过程:经过VirtualMachine类的attach(pid)
方法,即可以attach到一个运行中的java进程上,以后即可以经过loadAgent(agentJarPath)
来将agent的jar包注入到对应的进程,而后对应的进程会调用agentmain方法。
从jdk根目录的lib/tools.jar源码一路追踪了一下VirtualMachine.attach方法,发现传入一个pid以后,在Windows下会经过WindowsVirtualMachine
这个类的构造函数,调用native方法,实现对jvm进程的attach
底层方法还得靠c/c++来实现(滑稽),了解这个机制以后,回到前面的agentmain的实现流程。首先启动一个一直运行的jvm
package com.bitterz; public class Main { public static void main(String[] args) throws InterruptedException { System.out.println("Main.main() in test project start!!"); Thread.sleep(300000000); System.out.println("Main.main() in test project end!!"); } }
启动以后,把再写一个agentmain,而且还要写好MANIFEST.MF文件配置,代码和pom.xml以下:
package com.bitterz; import java.lang.instrument.Instrumentation; public class AgentMain { public static void agentmain(String agentArgs, Instrumentation instrumentation) { System.out.println("agentmain start!"); System.out.println(instrumentation.toString()); } }
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestEntries> <Agent-Class>com.bitterz.AgentMain</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
使用maven package打包成一个jar文件便可
再开启动另外一个java程序,使用进程号attach到前面一直运行的jvm,并使用loadAgent给这个jvm添加代理jar:
package com.bitterz.attach; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; import java.io.IOException; public class AttachTest { public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException { VirtualMachine attach = VirtualMachine.attach("12244"); // 命令行找到这个jvm的进程号 attach.loadAgent("C:\\Users\\helloworld\\Desktop\\java learn\\java-attach\\target\\java-attach-1.0-SNAPSHOT.jar"); attach.detach(); } }
运行这个java文件,会看到前面一直sleep运行的jvm会输出agentmain里面给定的输出!
这里也就说明,经过attach机制,咱们能够对指定运行中的jvm添加agent,而在premain方法中获取到Instrumentation对象,经过对Instrumentation对象添加transformer类,能够实现类转换(Class Transform),也就是在transform函数中结合修改字节码的方法(ASM、Javassist、cglib等)能够进一步实现RASP!
后续的文章将会写一写如何实现这些对指定类方法的Hook,以及如何运行时对底层函数的参数进行过滤。
http://www.javashuo.com/article/p-dzoqxtxo-gu.html
https://www.cnblogs.com/kendoziyu/p/maven-auto-build-javaagent-jar.html