目录
探针Java Agent原理概述与示例
基于Java Agent实现动态修改代码
基于Java Agent实现字节码注入
基于Java Agent实现内存Webshell注入
基于Java Agent实现内存Webshell检测
程序目标
通过Java Agent,动态修改程序返回结果,这里使用第三方 Byte Buddy 来实现动态修改:
Byte Buddy 是一个字节码生成与操作库,它无需编译器,能够在Java程序运行时创建与修改 class 文件;
Byte Buddy 库,是在ASM之上提供了更高级的抽象实现;
项目代码
使用IDEA新建一个maven项目,项目结构如下:
main程序和agent程序,可以分开成两个工程,这里为了简便就放在一个工程下。
main.java
其中main.java是需要被动态修改的源程序,agent.java为Java Agent程序,代码如下:
package main;public class Main { public static void main(String[] args) { System.out.println("=====main====="); System.out.println(logPrint()); } // 我们的目标是在运行时去修改它的返回值 public static String logPrint() { return "yyyyy"; }}
pom-main.xml
我们使用maven对main.java进行打包,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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>org.lynngroupId> <artifactId>JavaAgent_DynamicChangeartifactId> <version>1.0-SNAPSHOTversion> <properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <maven.compiler.source>1.8maven.compiler.source> <maven.compiler.target>1.8maven.compiler.target> <maven.compiler.compilerVersion>1.8maven.compiler.compilerVersion> properties> <dependencies> <dependency> <groupId>net.bytebuddygroupId> <artifactId>byte-buddyartifactId> <version>1.10.13version> dependency> dependencies> <build> <finalName>mainfinalName> <plugins> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-compiler-pluginartifactId> <version>3.8.1version> <configuration> <source>${maven.compiler.source}source> <target>${maven.compiler.target}target> configuration> plugin> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-jar-pluginartifactId> <version>3.2.0version> <configuration> <archive> <addMavenDescriptor>falseaddMavenDescriptor> <manifest> <mainClass>main.MainmainClass> manifest> archive> <excludes> <exclude>**/agent/exclude> excludes> configuration> plugin> plugins> build>project>
最后打包的结果,通过jd-gui反编译后的结果如下:
主要是Main-Class: main.Main
agent.java
下面编写Java Agent程序,通过Byte Buddy实现运行时动态修改代码功能,代码如下:
package agent;import net.bytebuddy.agent.builder.AgentBuilder;import net.bytebuddy.description.method.MethodDescription;import net.bytebuddy.description.type.TypeDescription;import net.bytebuddy.dynamic.DynamicType;import net.bytebuddy.implementation.FixedValue;import net.bytebuddy.matcher.ElementMatchers;import net.bytebuddy.utility.JavaModule;import java.lang.instrument.Instrumentation;public class Agent { public static void premain(String args, Instrumentation instrumentation) { System.out.println("======agent premain====="); new AgentBuilder.Default() .type(ElementMatchers.<TypeDescription>nameStartsWith("main.Main")) // 通过name查找类 .transform(new AgentBuilder.Transformer() { public DynamicType.Builder> transform( DynamicType.Builder> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) { return builder.method( ElementMatchers.<MethodDescription>named("logPrint")) // 查找需要修改的方法 .intercept(FixedValue.value("xxxxxxx")); // 修改/固定返回值 } }).installOn(instrumentation); }}
pom-agent.xml
同样的,我们使用maven对agent.java进行打包,因为涉及到写第三方依赖,我们这里使用更强大的maven-shade-plugin来将其打包成一个jar文件,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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>org.lynngroupId> <artifactId>JavaAgent_DynamicChangeartifactId> <version>1.0-SNAPSHOTversion> <properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <maven.compiler.source>1.8maven.compiler.source> <maven.compiler.target>1.8maven.compiler.target> <maven.compiler.compilerVersion>1.8maven.compiler.compilerVersion> <premain.class>agent.Agentpremain.class> <can.redefine.classes>truecan.redefine.classes> <can.retransform.classes>truecan.retransform.classes> properties> <dependencies> <dependency> <groupId>net.bytebuddygroupId> <artifactId>byte-buddyartifactId> <version>1.10.13version> dependency> dependencies> <build> <finalName>agentfinalName> <plugins> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-shade-pluginartifactId> <version>3.2.4version> <executions> <execution> <phase>packagephase> <goals> <goal>shadegoal> goals> <configuration> <createSourcesJar>falsecreateSourcesJar> <shadeSourcesContent>falseshadeSourcesContent> <shadedArtifactAttached>falseshadedArtifactAttached> <createDependencyReducedPom>falsecreateDependencyReducedPom> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Premain-Class>${premain.class}Premain-Class> <Can-Redefine-Classes>${can.redefine.classes}Can-Redefine-Classes> <Can-Retransform-Classes>${can.retransform.classes}Can-Retransform-Classes> manifestEntries> transformer> transformers> <filters> <filter> <artifact>net.bytebuddy:byte-buddyartifact> <excludes> <exclude>META-INF/versions/9/module-info.classexclude> excludes> filter> <filter> <artifact>*:*artifact> <excludes> <exclude>main/**exclude> <exclude>**/maven/exclude> excludes> filter> filters> configuration> execution> executions> plugin> plugins> build>project>
最后打包的结果,通过jd-gui反编译后的结果如下:
主要看,Premain-Class: agent.Agent、Can-XXX-Classes: XXX 等配置信息
运行示例
最后尝试运行我们的示例,可以看到实际main.jar的输出,已经被Java Agent给动态修改了。
E:\MyProject\Java\JavaAgent_DynamicChange\target>java -jar main.jar=====main=====yyyyyE:\MyProject\Java\JavaAgent_DynamicChange\target>java -jar agent.jaragent.jar中没有主清单属性E:\MyProject\Java\JavaAgent_DynamicChange\target>java -javaagent:agent.jar -jar main.jar======agent premain==========main=====xxxxxxxE:\MyProject\Java\JavaAgent_DynamicChange\target