lundi 23 juillet 2018

Initialize java instrumentation on JRE 9+ in runtime

I'm looking for hack to get access to java instrumentation in runtime on JRE 9+ without messing around startup arguments etc. I don't actually have any goal to do this, I'm just curious if it is still possible.
For java 8 and lower this would look like this (with a bit of help from byte-buddy-agent library):

public static void main(String[] args) throws Exception {
    // inject tools to class loader (can be done using unsafe too)
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    addURL.setAccessible(true);
    addURL.invoke(systemClassLoader, new File("B:/Java/tools/j8/tools-min.jar").toURI().toURL());

    // append folder with attach(.dll) library in it
    System.setProperty("java.library.path", System.getProperty("java.library.path") + ';' + "B:/Java/tools/j8");

    // force reset sys_paths to allow for recreation on next library load
    Field sys_paths = ClassLoader.class.getDeclaredField("sys_paths");
    sys_paths.setAccessible(true);
    sys_paths.set(null, null);

    // load attach(.dll)
    System.loadLibrary("attach");

    // now byte buddy can do everything for you
    Instrumentation instrumentation = ByteBuddyAgent.install();
    System.out.println(instrumentation); // works!
}

Where tools.jar is a path to jdk8/lib/tools.jar from JDK for proper system - you don't need all classes too, so final .jar can be just few kb (35kB on windows) instead of around 17MB in case of windows. You can also extract and merge classes from multiple systems to create single tools.jar that would work on every system.
Method above should work fine for linux too (if you provide valid tools.jar and attach.so library), but seems that attach library is already present on many jre distributions on linux, so you can use this code instead:

public static void linux() {
    Instrumentation instrumentation = ByteBuddyAgent.install(() -> {
        File toolsJar = new File("B:/Java/tools/j8/tools-min.jar");
        try {
            if (toolsJar.isFile() && toolsJar.canRead()) {
                return Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, null));
            }
            return Accessor.Unavailable.INSTANCE;
        } catch (MalformedURLException e) { throw new RuntimeException(e); }
    });
    System.out.println(instrumentation); // works!
}

Modules and new system class loader in JRE 9+ changes a lot, and I only know that I need to somehow load attach.jmod from JDK to JRE.
But so far I didn't find a way to do it and I wonder if it is still possible.
Also additional hacks are needed on JRE 9 to disable self-attach protection but this is simple too, I just can't find a way to make attach provider actually return valid values, as services also changed from java 9.





Aucun commentaire:

Enregistrer un commentaire