Question

I am trying to make sure dynamically loaded classes are ran through my class transformer and in order to do so I need to modify the bytecode before it's loaded into a class

What I am trying to do is identify if there's defineClass called and call my bytecode transforming method on the byte array parameter before calling defineClass

However I am unable to identify where each parameter starts, it they're in clear order but I don't know how do I know where which parameter starts?

Here's and example I've created with ASMifier

//The first parameter
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
//second parameter, byte array, this is what I am looking for!!
mv.visitVarInsn(ALOAD, 4);
//third parameter
mv.visitInsn(ICONST_0);
//fourth parameter
mv.visitVarInsn(ALOAD, 4);
mv.visitInsn(ARRAYLENGTH);
//fifth parameter
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getProtectionDomain", "()Ljava/security/ProtectionDomain;");
mv.visitMethodInsn(INVOKEVIRTUAL, "b", "defineClass", "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;");

How can I detact which of those instructions is loading the byte array that's being given to defineClass as parameter in order to run it through my transformer and using the returning value?

I can't see clear separation between parameters, and I can't find any documentation regarding this..

I don't understand how even the JVM know when parameter starts and when parameter ends..

I can easily extract what's the byte array parameter index is but how by knowing that I can find the bytecode that loads the byte array?

Was it helpful?

Solution

There are two approaches to this:

  1. Track the instruction(s) that placed certain values into the stack (e.g. using SourceInterpreter from ASM bytecode manipulation framework)
  2. Access values on the stack at the point those values are used (e.g. right before INVOKEVIRTUAL for defineClass method)

Second approach is easier to implement, because method descriptor tells you what stack slot is used for each method parameter. Then you just need to load values from the stack, copy them for your own use and put them back as they were before.

The ASM bytecode framework provides LocalVariablesSorter helper that makes it easy to introduce new local variables in the bytecode.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top