是否可以通过JDI检测Object类?

时间:2018-05-23 22:05:44

标签: java instrumentation javaagents jvmti jdi

我正在尝试创建一些检测工具。我想跟踪每个对象分配。我想到的最简单的想法是在每个对象调用它时重新转换Object构造函数(我知道数组的初始化方式不同)。

我尝试使用java代理机制,但它导致了java.lang.instrument.UnmodifiableClassException。显然java代理无法转换Object类,因为它是不可修改的。

然后我尝试使用 JDI ,我的调试程序看起来像:

public class First {

    public static int value = 1;

    public static void main(String... args) throws InterruptedException {
        while (true) {
            print();
            Thread.sleep(1000);
        }
    }

    public static void print() {
        System.out.println("Hello" + new Integer(value));

    }
}

调试器只做了这个:

    VirtualMachine vm = new VMAcquirer().connect(8000);

    List<ReferenceType> referenceTypes1 = vm.classesByName("java.lang.Object");
    ReferenceType object = referenceTypes1.get(0);
    if (vm.canRedefineClasses()) {
        ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.get("java.lang.Object");
        CtConstructor constructor = ctClass.getConstructors()[0];
        constructor.insertAfter("First.value += 1;");

        HashMap<ReferenceType, byte[]> redefine = new HashMap<>();
        redefine.put(object, ctClass.toBytecode());
        ctClass.writeFile();

        vm.redefineClasses(redefine);
    }
    vm.resume();

在目标程序退出后显示消息:

ERROR: JDWP Transport dt_socket failed to initialize, OUT_OF_MEMORY(110)

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

我在这里做错了吗?是否有可能以这种方式转换Object类? 我知道 JVMTI ,但我想避免使用C代码,那么还有其他方法不需要本机代码吗?

免责声明我知道这里已经提到了一些类似的问题(例如Hacking into java.lang.Object: calling custom external class crashes JVMJDI, Java Byte code instrumentation and Java agents (JWDP, JVMTI)),但他们没有向我解释一切。

--- --- EDIT

转化后的Object课程如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package java.lang;

import jdk.internal.HotSpotIntrinsicCandidate;

public class Object {
    private static native void registerNatives();

    @HotSpotIntrinsicCandidate
    public Object() {
        Object var2 = null;
        ++First.value;
    }

    @HotSpotIntrinsicCandidate
    public final native Class<?> getClass();

    @HotSpotIntrinsicCandidate
    public native int hashCode();

    public boolean equals(Object obj) {
        return this == obj;
    }

    @HotSpotIntrinsicCandidate
    protected native Object clone() throws CloneNotSupportedException;

    public String toString() {
        return this.getClass().getName() + "@" + 
        Integer.toHexString(this.hashCode());
    }

    @HotSpotIntrinsicCandidate
    public final native void notify();

    @HotSpotIntrinsicCandidate
    public final native void notifyAll();

    public final void wait() throws InterruptedException {
        this.wait(0L);
    }

    public final native void wait(long var1) throws InterruptedException;

    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0L) {
            throw new IllegalArgumentException("timeout value is negative");
        } else if (nanos >= 0 && nanos <= 999999) {
            if (nanos > 0) {
                ++timeout;
            }

            this.wait(timeout);
        } else {
            throw new IllegalArgumentException("nanosecond timeout value out of range");
        }
    }

    /** @deprecated */
    @Deprecated(
        since = "9"
    )
    protected void finalize() throws Throwable {
    }

    static {
        registerNatives();
    }
}

我还做了更多的测试,如果我放了int i = 1; int j = 2 + i;这样的东西,它就可以了。

我也试过修改Integer构造函数 - 这导致了另一个异常:

Exception in thread "main" java.lang.NoClassDefFoundError: First
    at java.base/java.lang.Integer.<init>(Integer.java:1075)
    at First.print(First.java:13)
    at First.main(First.java:7)

类已成功转换,但在运行时链接到类时出现问题。我不知道它是否以某种方式联系起来。当某些内部事物试图创建新实例时,Object可能发生类似的事情。

我对Object var2 = null;行感到好奇。 Javaassist总是放置ACONST_NULL字节码,但这不是问题的原因。

--- --- EDIT2

我尝试转换另一个Object方法。转换成功,但在运行时再次发生错误:

Exception in thread "main" java.lang.NoClassDefFoundError: First
    at java.base/java.lang.Object.toString(Object.java:246)
    at First.print(First.java:15)
    at First.main(First.java:7)

对我来说,真正的问题似乎是NoClassDefFoundError。我的假设是它与java(?)中的 classloader 系统有某种关系。我可以以某种方式避免这样的错误?我对类加载器知之甚少:/

0 个答案:

没有答案