使用ASM重写Java本机方法

Li *_*oyi 17 java java-native-interface bytecode metaprogramming sandbox

我试图通过使用ASM 4.0重写类的字节码来替换所有nativenative存根方法.

到目前为止我有这个:

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

由执行

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();
}
Run Code Online (Sandbox Code Playgroud)

这似乎很简单:我删除ACC_NATIVE了方法visitMethod()并保留其他所有内容.然而,当我这样做时java.lang.Object,它会死于

Exception in thread "main" 
Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"
Run Code Online (Sandbox Code Playgroud)

StackOverflow发生在检测时,而不是在运行时,我觉得这很不寻常.但是,如果我删除& ~Opcodes.ACC_NATIVE修饰符,则会java.lang.Object重写(在这种情况下保持不变)并完美执行.

很明显,我没有做正确的事情,用nativenative方法替换方法并不像native在方法上剥离修饰符那么简单,但我不知道从哪里开始.该ASM文档不谈论与工作native方法的.有没有使用ASM经验的人知道我需要做什么才能让native方法重写工作吗?

编辑

对不起,这条简短无用的消息是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)
Run Code Online (Sandbox Code Playgroud)

所以在我看来,错误实际上是在执行时发生的(例如,我认为它是在仪表时间错误)并且是调用的结果hashCode().正如它所发生的那样,hashCode()我(可能错误地)剥离了它的native修饰符之一的本机方法.很明显,它正在调用native导致问题的-stripped方法.

看起来奇怪的是,堆栈跟踪只有16帧深; 鉴于它是一个,我会更加期待StackOverflowError.

tjl*_*tjl 2