17

ASM 4.0を使用してクラスのバイトコードを書き直し、すべてのnativeメソッドを非nativeスタブに置き換えて、これを実行しようとしています。

これまでのところ私はこれを持っています:

class ClassAdapter extends ClassVisitor {

    public ClassAdapter(ClassVisitor cv) {
        super(Opcodes.ASM4, cv);
    }

    @Override
    public MethodVisitor visitMethod(int access, String base, String desc, String signature, String[] exceptions) {
        return cv.visitMethod(access & ~Opcodes.ACC_NATIVE, base, desc, signature, exceptions);
    }

}

によって実行されます

private static byte[] instrument(byte[] originalBytes, ClassLoader loader) {
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    ClassAdapter adapter = new ClassAdapter(cw);

    ClassReader cr = new ClassReader(originalBytes);
    cr.accept(adapter, ClassReader.SKIP_FRAMES);

    return cw.toByteArray();
}

これは十分に単純なようです。ACC_NATIVEメソッドを削除し、visitMethod()他のすべては変更しません。しかし、これを行うjava.lang.Objectと、

Exception in thread "main" 
Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"

StackOverflowは、実行時ではなく、インストルメンテーション時に発生します。これはかなり珍しいことだと思います。ただし、修飾子を削除すると、書き換えられ(この場合は変更されません)、完全に実行されます。& ~Opcodes.ACC_NATIVEjava.lang.Object

明らかに私は正しいことをしていません。nativeメソッドを非nativeメソッドに置き換えるのは、メソッドの修飾子を取り除くほど簡単ではありませんnativeが、どこから始めればよいのかわかりません。ASM Docsは、nativeメソッドの操作についてはまったく説明していません。nativeASMを使用した経験のある人は、メソッドの書き直しを機能させるために私が何をする必要があるかを知っていますか?

編集

申し訳ありませんが、その短くて役に立たないメッセージがe.printStackTrace()私に与えられたものでしたが、私を使用e.getStackTrace()して何か有用なものを得ることができました:

java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:332)
java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1124)
java.util.Collections$SetFromMap.add(Collections.java:3903)
sandbox.classloader.MyClassLoader.instrument(Unknown Source)
sandbox.classloader.MyClassLoader.loadClass(Unknown Source)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:791)
java.lang.ClassLoader.defineClass(ClassLoader.java:634)
sandbox.classloader.MyClassLoader.findClass(Unknown Source)
sandbox.classloader.MyClassLoader.loadClass(Unknown Source)
sandbox.Tester.main(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

したがって、エラーは実際には実行時に発生していたように見えます(たとえば、インストルメンテーション時に発生したと誤解されていました)。これは、を呼び出した結果ですhashCode()。たまたま、hashCode()私が(おそらく間違って)native修飾子を取り除いたネイティブメソッドの1つ。したがって、明らかに、問題の原因となっている-strippedメソッドを呼び出しています。native

本当に奇妙に思えるのは、スタックトレースの深さが16フレームしかないことです。それがだったことを考えると、私はもう少し期待していたでしょうStackOverflowError

4

2 に答える 2

2
  • ネイティブコードをスタブに置き換えるのはそれほど簡単ではありませんが、そう遠くはありません

  • ClassVisitor #visitMethod(int access、String name、String desc、String シグニチャ、String []例外) を見ると、MethodVisitor

  • あなたが今利用しなければならないMethodVisitor 。抽象スタブを作成する場合は、少なくともへの呼び出しを追加する必要がありますmethodVisitor.visitEnd()

  • 空のスタブを作成する場合はvisitCode、必要に応じて値を追加して返す必要があります

于 2012-11-11T19:36:56.563 に答える
1

ここで受け入れられた答えを詳しく説明するのは、ASMを使用してネイティブメソッドjava.net.NetworkInterface#getHardwareAddress()を固定値を返すスタブに置き換えるインストルメンテーションエージェントの完全に機能する例です。

public class MacModifyAgent {

    private static final String TARGET = "java/net/NetworkInterface";

    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader l, String name, Class<?> c, ProtectionDomain d, byte[] b)
                    throws IllegalClassFormatException {
                if (TARGET.equals(name)) {
                    return instrument(b);
                }
                return b;
            }
        });
    }

    private static byte[] instrument(byte[] originalBytes) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        ClassAdapter adapter = new ClassAdapter(cw);

        ClassReader cr = new ClassReader(originalBytes);
        cr.accept(adapter, ClassReader.SKIP_FRAMES);

        return cw.toByteArray();
    }

    public static class ClassAdapter extends ClassVisitor implements Opcodes {
        public ClassAdapter(ClassVisitor cv) {
            super(ASM4, cv);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
                String[] exceptions) {

            if ("getHardwareAddress".equals(name)) {
                MethodVisitor mv = super.visitMethod(access & ~ACC_NATIVE, name, descriptor, signature, exceptions);

                MethodVisitor special = new StubReturnValue(mv, new byte[] { 1, 2, 3, 4, 5, 6 });
                return special;
            } else {
                return super.visitMethod(access, name, descriptor, signature, exceptions);
            }
        }
    }

    public static class StubReturnValue extends MethodVisitor implements Opcodes {
        private final MethodVisitor target;
        private byte[] mac;

        public StubReturnValue(MethodVisitor target, byte [] mac) {
            super(ASM4, null);
            this.target = target;
        }

        @Override
        public void visitCode() {
            target.visitCode();
            target.visitVarInsn(BIPUSH, 6);
            target.visitIntInsn(NEWARRAY, T_BYTE);

            for (int i = 0; i < 6; i++) {
                target.visitInsn(DUP);
                target.visitIntInsn(BIPUSH, i);
                target.visitIntInsn(BIPUSH, mac[i]);
                target.visitInsn(BASTORE);
            }

            target.visitInsn(ARETURN);
            target.visitEnd();
        }
    }
}
于 2018-02-09T12:55:10.080 に答える