Использование ASM для мониторинга java.lang.ProcessBuilder

Я надеялся создать монитор с использованием инструментов ASM для регистрации вызовов java.lang.ProcessBuilder. Однако мои попытки, кажется, терпят неудачу. Ниже приведен пример кода. По сути, этот код просто добавляет nop к конструктору java.lang.ProcessBuilder, а затем записывает новый (и исходный) файл класса в каталог модифицированного класса. Это полностью для тестирования, так как я хотел убедиться, что все работает правильно, и я мог проверить измененный байт-код вне запуска агента. Если я укажу этот образец кода на другой класс (не java.lang), все будет работать. Можно ли изменить java.lang.ProcessBuilder с помощью javaagent?

Заранее спасибо,

Джереми

public class Instrumentor {

public static void agentmain(String agentArgs, Instrumentation instrumentation) {
    instrument(instrumentation);
}

public static void premain(String agentArgument, Instrumentation instrumentation) {
    instrument(instrumentation);
}

private static void instrument(Instrumentation instrumentation) {
    try {
        instrumentation.addTransformer(new SampleTransformer());
    } catch (TransformerException ex) {
        Logger.getLogger(Instrumentor.class.getName()).log(Level.SEVERE, null, ex);
    }
}
}

//--------------------------------
public class SampleTransformer implements ClassFileTransformer {

public SampleTransformer() throws TransformerException {
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
        ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    if ("java/lang/ProcessBuilder".equals(className)) {
        System.out.println("attempting to process " + className);
        ClassReader cr = new ClassReader(classfileBuffer);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
        SampleClassAdapter adapter = new SampleClassAdapter(cw);
        cr.accept(adapter, 0);
        byte[] clz = cw.toByteArray();
        try {
            System.out.println("write " + className);
            File p = new File("target\\modified-classes\\");
            p.mkdirs();
            File f = new File(p, className.replace('/', '.') + ".class");
            File o = new File(p, className.replace('/', '.') + ".original.class");
            Files.write(Paths.get(f.getAbsolutePath()), clz);
            Files.write(Paths.get(o.getAbsolutePath()), classfileBuffer);
        } catch (IOException ex) {
            Logger.getLogger(SampleTransformer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return clz;
    }
    return classfileBuffer;
}
}
//------------------------
public class SampleClassAdapter extends ClassVisitor {

public SampleClassAdapter(ClassVisitor cv) {
    super(Opcodes.ASM5, cv);
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    super.visit(version, access, name, signature, superName, interfaces);
}

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
    if (mv != null && "<init>".equals(name)) {
        mv = new SampleMethodAdapter(mv, access, name, desc);
    }
    return mv;
}
}
//----------------------------------------
public class SampleMethodAdapter extends AdviceAdapter {

public SampleMethodAdapter(final MethodVisitor methodVisitor,
        final int access, final String name, final String descriptor) {
    super(Opcodes.ASM5, methodVisitor, access, name, descriptor);
}

@Override
protected void onMethodEnter() {
    mv.visitInsn(Opcodes.NOP);
}

}


person user1995422    schedule 16.01.2015    source источник


Ответы (2)


Вы можете изменить класс во время выполнения, но для начала я предлагаю попробовать скомпилировать собственную версию, которую вы переопределяете в пути к классу загрузки. После того, как вы это заработаете, вы сможете работать с тем, что ASM требуется для того, чтобы эта инъекция кода работала во время выполнения.

person Peter Lawrey    schedule 16.01.2015

Я понял, в чем проблема. Вызов ClassReader для принятия должен включать флаг EXPAND_FRAMES.

cr.accept(adapter, ClassReader.EXPAND_FRAMES);

После исправления этого вызова мне удалось успешно изменить байтовый код java.lang.ProcessBuilder.

person user1995422    schedule 17.01.2015