JavaAgent
0x00 Intro
IAST(Interactive Application Security Testing)交互式应用程序安全测试
RASP(Runtime application self-protection)运行时应用自我保护。
RASP是一种植入到应用程序内部或其运行时环境的安全技术。RASP可将自身注入到应用程序中,与应用程序融为一体,实时监测、阻断攻击,使程序自身拥有自保护的能力。区别于传统的WAF防护,RASP检测更全面精准、不易被绕过、可预防未知漏洞。
JavaAgent是其背后的技术支持
在Java SE 5及后续版本中,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在JVM上的程序,还能够修改字节码,动态修改已加载或未加载的类以及它们的属性和方法。
0x01 Basic Concept
Java Agent 有两种加载方式:
premain, 以指示代理类的方式启动JVM。agentmain, 在JVM启动后的某个时间提供启动代理
premain相当于在main前类加载时进行字节码修改,而agentmain则是main后在类调用前通过重新转换类完成字节码修改。由于加载方式不同,所以premain只能在程序启动时指定Agent文件进行部署,而agentmain需要通过Attach API在程序运行后根据进程ID动态注入agent到jvm中。
关键Instrumentation类(java.lang.instrument):
Java agent通过Instrumentation类和JVM进行交互,从而到达修改字节码的目的。
public interface Instrumentation {
//增加一个Class 文件的转换器,转换器用于改变 Class 二进制流的数据,参数 canRetransform 设置是否允许重新转换。
void addTransformer(ClassFileTransformer transformer, boolean canRetransform);
//在类加载之后,可以使用 retransformClasses 方法重新定义类。addTransformer方法配置之后,后续的类加载都会被Transformer拦截。对于已经加载过的类,可以执行retransformClasses来重新触发这个Transformer的拦截。类加载的字节码被修改后,除非再次被retransform,否则不会恢复。
void addTransformer(ClassFileTransformer transformer);
//删除一个类转换器
boolean removeTransformer(ClassFileTransformer transformer);
boolean isRetransformClassesSupported();
// 在类加载之后,重新定义Class。该方法是1.6之后加入的,事实上,该方法是 update 了一个类。可以修改方法体,但是不能变更方法签名、增加和删除方法/类的成员属性
void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;
// 获取目标已经加载的类。
@SuppressWarnings("rawtypes")
Class[] getAllLoadedClasses();
}启动时加载-premain
Agent构造
实现premain方法
manifest清单中包含
Premain-Class字段
加载Agent
添加-javaagent参数指定Agent(jar包)
在运行main方法前会先调用Agent的premain方法
jar打包方式:
法一:maven + POM 配置manifestEntries参数
Premain-Class:包含
premain方法的类,需要配置为类的全路径Agent-Class:包含
agentmain方法的类,需要配置为类的全路径Can-Redefine-Classes:为
true时表示能够重新定义ClassCan-Retransform-Classes:为
true时表示能够重新转换Class,实现字节码替换Can-Set-Native-Method-Prefix:为
true时表示能够设置native方法的前缀
执行
mvn clean package法二:MANIFEST.MF配置文件 在资源目录(resources)下,新建目录
META-INF在META-INF目录下,新建文件MANIFEST.MFjavac .\com\demo\myAgent\MyAgent.java
jar -cvf MyAgent.jar -C ./ .
运行上加上参数VM options:-javaagent
-javaagent:path\JavaAgent01-1.0-SNAPSHOT.jar

或者通过命令行执行
java -javaagent:path\JavaAgent01-1.0-SNAPSHOT.jar MainTest
注意-javaagent:path要放在MainTest前面

执行main方法之前会加载所有的类,包括系统类和自定义类;
在ClassFileTransformer中会去拦截系统类和自己实现的类对象;
要对某些类对象进行改写,在拦截的时候抓住该类使用字节码编译工具即可实现。
agentmain
在 Java SE 6 的 Instrumentation 当中,提供了一个新的代理操作方法:agentmain,可以在 main 函数开始运行之后再运行。
agentmain需要通过Attach API在程序运行后根据进程ID动态注入agent到jvm中,利用com.sun.tools.attach.VirtualMachine的attach方法连接目标虚拟机
通过VirtualMachine类的attach(pid)方法,便可以attach到一个运行中的java进程上,之后便可以通过loadAgent(agentJarPath)来将agent的jar包注入到对应的进程,然后对应的进程会调用agentmain方法。
同上面一样打包为jar
main函数执行起来的时候进程名为当前类名,所以通过这种方式可以去找到当前的进程id。
若找不到com.sun.tools,在POM中加入tool.jar外部依赖,指定本地tools.jar路径
Main测试类
先启动Main测试类,再启动AttachMain来注入jar

由于 tools.jar 并不会在 JVM 启动的时候默认加载,尝试利用URLClassloader来加载tools.jar
Last updated
Was this helpful?