Skip to content

Instantly share code, notes, and snippets.

@raphw
Last active March 26, 2024 06:56
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save raphw/34c0e2fffe2ee7b4f02f to your computer and use it in GitHub Desktop.
Save raphw/34c0e2fffe2ee7b4f02f to your computer and use it in GitHub Desktop.
An example agent that intercepts a method of the bootstrap class loader.
package net.bytebuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.Collections;
import java.util.concurrent.Callable;
public class BootstrapAgent {
public static void main(String[] args) throws Exception {
premain(null, ByteBuddyAgent.install());
HttpURLConnection urlConnection = (HttpURLConnection) new URL("http://www.google.com").openConnection();
System.out.println(urlConnection.getRequestMethod());
}
public static void premain(String arg, Instrumentation inst) throws Exception {
File temp = Files.createTempDirectory("tmp").toFile();
ClassInjector.UsingInstrumentation.of(temp, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, inst).inject(Collections.singletonMap(
new TypeDescription.ForLoadedType(MyInterceptor.class),
ClassFileLocator.ForClassLoader.read(MyInterceptor.class).resolve()));
new AgentBuilder.Default()
.ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
.enableBootstrapInjection(temp, inst)
.type(ElementMatchers.nameEndsWith(".HttpURLConnection"))
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader) {
return builder.method(ElementMatchers.named("getRequestMethod")).intercept(MethodDelegation.to(MyInterceptor.class));
}
}).installOn(inst);
}
public static class MyInterceptor {
public static String intercept(@SuperCall Callable<String> zuper) throws Exception {
System.out.println("Intercepted!");
return zuper.call();
}
}
}
@i36lib
Copy link

i36lib commented Jun 18, 2022

You probably have the class included in your agent jar and also attach it to the boot loader. This way it will be loaded in the system loader before it is attached to boot and therefore be loaded twice. With different class loaders, the two classes are different. Try not including it as a ".class" file in the boot loader.

how can I try not to including it as a ".class" file in the boot loader ?

@raphw
Copy link
Author

raphw commented Jun 19, 2022

Have a look at ClassInjector and Instrumentation which both offer APIs for that.

@i36lib
Copy link

i36lib commented Jun 20, 2022

Have a look at ClassInjector and Instrumentation which both offer APIs for that.

OK, thanks raphw.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment