Hack Forums
[Java] Replacing "native" classes at runtime - Printable Version

+- Hack Forums (https://hackforums.net)
+-- Forum: Tech (https://hackforums.net/forumdisplay.php?fid=444)
+--- Forum: Coding (https://hackforums.net/forumdisplay.php?fid=151)
+---- Forum: Software Development (https://hackforums.net/forumdisplay.php?fid=118)
+---- Thread: [Java] Replacing "native" classes at runtime (/showthread.php?tid=5728812)



Replacing "native" classes at runtime - matt - Oct 1, 2017

Is it possible to replace a native class at runtime with my own? I'm trying to make my own sanboxed environment so if I load an application in to it I can see method calls to things such as Sockets, the Runtime class, FileStreams etc, I've tried replacing the class in a classloader but I always get a java security manager exception, can you use a java agent to accomplish this? I've also heard you can do it using OSGI but I'd like to stay away from 3rd party applications


* - clrlslwi - Oct 1, 2017

I don't think this is possible. Agents can only modify method bodies during runtime afaik. Stick to modifying everything beforehand.


* - matt - Oct 2, 2017

(Oct 1, 2017 11:34 PM)Demmonic Wrote:  I don't think this is possible. Agents can only modify method bodies during runtime afaik. Stick to modifying everything beforehand.

How would I go about modifying method bodies? I could just print out the parameters of the method and then return null or something along the lines so all the subsequent code wouldn't be ran.


I've been looking in to it and I decided to go the easy route and use Javassist over ASM and here's what I've come up with

Code
package ca.midnight.av;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class AgentMain {

    public static void premain(String args, Instrumentation inst) {
        inst.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader classLoader, String name, Class<?> klass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
                if(name.equals("java/awt/Desktop")) {
                    try {
                        ClassPool cp = ClassPool.getDefault();
                        CtClass cc = cp.get("java.awt.Desktop");
                        CtMethod m = cc.getDeclaredMethod("browse");
                        m.setBody("System.out.println(\"Attempting to open URL: \" + $1);");
                        byte[] byteCode = cc.toBytecode();
                        cc.debugWriteFile("/home/hayden/workspace/AV/");
                        cc.detach();
                        return byteCode;
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                return null;
            }
        });
    }
}

Theoretically shouldn't that set the entire method body to only print out the first argument opposed to opening the link?
However it's not doing anything and I can't figure out why


* - clrlslwi - Oct 2, 2017

(Oct 2, 2017 12:10 AM)Midnight Blue™ Wrote:  How would I go about modifying method bodies? I could just print out the parameters of the method and then return null or something along the lines so all the subsequent code wouldn't be ran.


I've been looking in to it and I decided to go the easy route and use Javassist over ASM and here's what I've come up with

Code
package ca.midnight.av;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class AgentMain {

    public static void premain(String args, Instrumentation inst) {
        inst.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader classLoader, String name, Class<?> klass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
                if(name.equals("java/awt/Desktop")) {
                    try {
                        ClassPool cp = ClassPool.getDefault();
                        CtClass cc = cp.get("java.awt.Desktop");
                        CtMethod m = cc.getDeclaredMethod("browse");
                        m.setBody("System.out.println(\"Attempting to open URL: \" + $1);");
                        byte[] byteCode = cc.toBytecode();
                        cc.debugWriteFile("/home/hayden/workspace/AV/");
                        cc.detach();
                        return byteCode;
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                return null;
            }
        });
    }
}

Theoretically shouldn't that set the entire method body to only print out the first argument opposed to opening the link?
However it's not doing anything and I can't figure out why

I don't know, I've only ever used ASM.


* - GenericSkid - Oct 3, 2017

Would you be willing to incorperate the vm arg xbootpath? It's sounds like it could do what you want.

https://docs.oracle.com/cd/E15289_01/doc.40/e15062/optionx.htm#i1018570


* - matt - Oct 3, 2017

(Oct 3, 2017 10:21 AM)Lord Pankake Wrote:  Would you be willing to incorperate the vm arg xbootpath? It's sounds like it could do what you want.

https://docs.oracle.com/cd/E15289_01/doc.40/e15062/optionx.htm#i1018570

Yes I am, but I'm not totally on the same page with you, how would that help?


Wait so I can create classes in jre packages with the same name and xbootpath will load those classes before the standard jre classes correct? and then it will proceed to use my classes instead of the standard ones? that's what I'm understanding


(Oct 3, 2017 10:21 AM)Lord Pankake Wrote:  Would you be willing to incorperate the vm arg xbootpath? It's sounds like it could do what you want.

https://docs.oracle.com/cd/E15289_01/doc.40/e15062/optionx.htm#i1018570

Woooo thank you so much, this works perfectly, here's my code for if somebody wants to accomplish the same thing
Code
package java.awt;

import java.net.URI;

public class Desktop {

    private static final Desktop desktop;
    
    static {
        desktop = new Desktop();
    }
    
    public static Desktop getDesktop() {
        return desktop;
    }
    
    public void browse(URI uri) {
        System.out.println("attempting to open url: " + uri);
    }
}

Then I execute whatever jar with
Code
java -Xbootclasspath/p:"./xboot.jar" -jar "target-application.jar"

And I'm left with the following output
Code
attempting to open url: https://hackforums.net

Great! 😁😁


* - clrlslwi - Oct 5, 2017

(Oct 3, 2017 09:43 PM)Midnight Blue™ Wrote:  -snip-


If you don't need real runtime support, I believe you can also use an agent with startup capabilities as well.