Created
June 2, 2018 11:07
-
-
Save raphw/00ce640762eea23ab3301a6b9c387ca4 to your computer and use it in GitHub Desktop.
Twist transformer order
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package sun.instrument; | |
import net.bytebuddy.agent.ByteBuddyAgent; | |
import net.bytebuddy.agent.builder.AgentBuilder; | |
import net.bytebuddy.asm.Advice; | |
import net.bytebuddy.description.type.TypeDescription; | |
import net.bytebuddy.dynamic.DynamicType; | |
import net.bytebuddy.implementation.StubMethod; | |
import net.bytebuddy.implementation.bytecode.assign.Assigner; | |
import net.bytebuddy.utility.JavaModule; | |
import java.lang.instrument.ClassFileTransformer; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Method; | |
import java.security.ProtectionDomain; | |
import java.util.ArrayList; | |
import java.util.List; | |
import static net.bytebuddy.matcher.ElementMatchers.*; | |
public class Experiment { | |
@Advice.OnMethodExit | |
static void exit(@Advice.FieldValue(value = "mTransformerList", readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] mTransformerList, | |
@Advice.This TransformerManager manager, | |
@Advice.Argument(0) ClassFileTransformer transformer) throws Exception { | |
Class<?> info = Class.forName("sun.instrument.TransformerManager$TransformerInfo"); | |
Method getTransformer = info.getDeclaredMethod("transformer"); | |
getTransformer.setAccessible(true); | |
Object[] newList = (Object[]) Array.newInstance(info, mTransformerList.length + 1); | |
List<Object> delayed = new ArrayList<Object>(); | |
int index = 0; | |
for (Object element : mTransformerList) { | |
Class<?>[] ifaces = getTransformer.invoke(element).getClass().getInterfaces(); | |
if (ifaces.length > 0 && ifaces[0].getSimpleName().equals("PrivTransformer")) { | |
delayed.add(element); | |
} else { | |
newList[index++] = element; | |
} | |
} | |
Constructor<?> make = info.getDeclaredConstructor(TransformerManager.class, ClassFileTransformer.class); | |
make.setAccessible(true); | |
Class<?>[] ifaces = transformer.getClass().getInterfaces(); | |
boolean priv = ifaces.length > 0 && ifaces[0].getSimpleName().equals("PrivTransformer"); | |
if (!priv) { | |
newList[index++] = make.newInstance(manager, transformer); | |
} | |
for (Object element : delayed) { | |
newList[index++] = element; | |
} | |
if (priv) { | |
newList[index] = make.newInstance(manager, transformer); | |
} | |
mTransformerList = newList; | |
} | |
public static void main(String[] args) throws Exception { | |
new AgentBuilder.Default() | |
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) | |
.disableClassFormatChanges() | |
.ignore(none()) | |
.type(is(TransformerManager.class)) | |
.transform(new AgentBuilder.Transformer() { | |
@Override | |
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, | |
TypeDescription typeDescription, | |
ClassLoader classLoader, | |
JavaModule module) { | |
return builder.method(named("addTransformer")).intercept(Advice.to(Experiment.class).wrap(StubMethod.INSTANCE)); | |
} | |
}).installOn(ByteBuddyAgent.install()); | |
ByteBuddyAgent.install().retransformClasses(TransformerManager.class); | |
ByteBuddyAgent.install().addTransformer(new PrivTransformer() { | |
@Override | |
public byte[] transform(ClassLoader loader, | |
String className, | |
Class<?> classBeingRedefined, | |
ProtectionDomain protectionDomain, | |
byte[] classfileBuffer) { | |
System.out.println("foo"); | |
return null; | |
} | |
}, true); | |
ByteBuddyAgent.install().addTransformer(new ClassFileTransformer() { | |
@Override | |
public byte[] transform(ClassLoader loader, | |
String className, | |
Class<?> classBeingRedefined, | |
ProtectionDomain protectionDomain, | |
byte[] classfileBuffer) { | |
System.out.println("bar"); | |
return null; | |
} | |
}, true); | |
ByteBuddyAgent.install().addTransformer(new ClassFileTransformer() { | |
@Override | |
public byte[] transform(ClassLoader loader, | |
String className, | |
Class<?> classBeingRedefined, | |
ProtectionDomain protectionDomain, | |
byte[] classfileBuffer) { | |
System.out.println("qux"); | |
return null; | |
} | |
}, true); | |
System.out.println("Loading bar..."); | |
Class.forName("Bar"); | |
} | |
interface PrivTransformer extends ClassFileTransformer { } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment