Changing Java Class Names at Runtime with Javassist

I0veD
cyber security researcherยท
ยท
2 min read
Article

Jhook:

package com.binklac.jhook;

import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Field;
import java.util.HashMap;

public class JHook {
private static JHook SelfInstance = null;
private static Class<?> GlobalInstance = null;
private static Class<?> GlobalAgent = null;
private static final JHookTransformer HookTransformer = new JHookTransformer();
private static final HashMap<String, byte[]> ModifyMap = new HashMap<>();

private JHook() {
}

public synchronized static JHook Instance() {
    if(SelfInstance == null){
        try {
            SelfInstance = new JHook();

            if (SelfInstance.getClass().getClassLoader().equals(ClassLoader.getSystemClassLoader())) {
                Boolean LoadSystemLibraryResult = JHookDynamicallyLoader.TryLoadSystemLibrary();
                Boolean InitializeJHookEnvironmentResult = JHookAgentLoader.InitializeJHookEnvironment();

                if (!(LoadSystemLibraryResult &amp;&amp; InitializeJHookEnvironmentResult)) {
                    SelfInstance = null;
                }

                GlobalInstance = SelfInstance.getClass();
            } else {
                GlobalInstance = Class.forName(JHook.class.getCanonicalName(), false, ClassLoader.getSystemClassLoader());
            }
        } catch(ClassNotFoundException e) {
            try {
                Boolean LoadSystemLibraryResult = JHookDynamicallyLoader.TryLoadSystemLibrary();
                Boolean InitializeJHookEnvironmentResult = JHookAgentLoader.InitializeJHookEnvironment();

                if (!(LoadSystemLibraryResult &amp;&amp; InitializeJHookEnvironmentResult)) {
                    SelfInstance = null;
                }

                GlobalInstance = Class.forName(JHook.class.getCanonicalName(), false, ClassLoader.getSystemClassLoader());
            } catch (ClassNotFoundException ex) {
                SelfInstance = null;
            }
        }
    }

    return SelfInstance;
}

protected byte[] GetModifyClass(String Name) {
    try {
        Field GlobalModifyMap = GlobalInstance.getDeclaredField(&quot;ModifyMap&quot;);
        GlobalModifyMap.setAccessible(true);
        HashMap&lt;String, byte[]&gt; GModifyMap = (HashMap&lt;String, byte[]&gt;) GlobalModifyMap.get(null);
        return GModifyMap.remove(Name);
    } catch (Exception e) {
        return null;
    }
}

public Boolean ModifyClass(String className, byte[] newClassBytes) {
    try {
        Class&lt;?&gt; clazz = Class.forName(className);

        if(GlobalAgent == null) {
            GlobalAgent = Class.forName(JHookAgent.class.getCanonicalName(), false, ClassLoader.getSystemClassLoader());
        }

        Field instrumentationField = GlobalAgent.getDeclaredField(&quot;instrumentation&quot;);
        instrumentationField.setAccessible(true);
        Instrumentation instrumentation = (Instrumentation) instrumentationField.get(null);

        Field globalModifyMapField = GlobalInstance.getDeclaredField(&quot;ModifyMap&quot;);
        globalModifyMapField.setAccessible(true);
        HashMap&lt;String, byte[]&gt; modifyMap = (HashMap&lt;String, byte[]&gt;) globalModifyMapField.get(null);

        if (instrumentation != null &amp;&amp; instrumentation.isModifiableClass(clazz)) {
            modifyMap.put(clazz.getCanonicalName(), newClassBytes);
            instrumentation.addTransformer(HookTransformer, true);
            instrumentation.retransformClasses(clazz);
            while (modifyMap.get(clazz.getCanonicalName()) != null) {
                Thread.sleep(1);
            }
            instrumentation.removeTransformer(HookTransformer);
            return true;
        }
        return false;
    } catch (UnmodifiableClassException | InterruptedException | ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
        return false;
    }
}

public Instrumentation getInstrumentation() {
    try {
        if (GlobalAgent == null) {
            GlobalAgent = Class.forName(JHookAgent.class.getCanonicalName(), false, ClassLoader.getSystemClassLoader());
        }
        Field instrumentationField = GlobalAgent.getDeclaredField(&quot;instrumentation&quot;);
        instrumentationField.setAccessible(true);
        return (Instrumentation) instrumentationField.get(null);
    } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
        return null;
    }
}

}


jhookclassname_change

package com.binklac.jhook.test;

import com.binklac.jhook.JHook;
import com.binklac.jhook.Utils;
import javassist.*;

import java.io.IOException;
import java.lang.instrument.Instrumentation;

public class JHookClassNameChanger {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
if (args.length != 2) {
System.out.println("Usage: java com.binklac.jhook.test.JHookClassNameChanger <oldClassName> <newClassName>");
return;
}

    String oldClassName = args[0];
    String newClassName = args[1];

    System.out.println(&quot;[#] JHook operating environment check.&quot;);

    ClassPool defaultClassPool = ClassPool.getDefault();
    defaultClassPool.appendClassPath(Utils.GetJHookJarPath());

    try {
        Instrumentation instrumentation = JHook.Instance().getInstrumentation();
        if (instrumentation == null) {
            System.out.println(&quot;[X] Instrumentation is null. Ensure JHook is properly initialized.&quot;);
            return;
        }

        Class&lt;?&gt;[] allLoadedClasses = instrumentation.getAllLoadedClasses();
        for (Class&lt;?&gt; clazz : allLoadedClasses) {
            if (clazz.getName().equals(oldClassName)) {
                CtClass ctClass = defaultClassPool.get(oldClassName);
                ctClass.setName(newClassName);
                byte[] modifiedClassBytes = ctClass.toBytecode();
                if (!JHook.Instance().ModifyClass(oldClassName, modifiedClassBytes)) {
                    System.out.println(&quot;[X] Failed to modify class: &quot; + oldClassName);
                } else {
                    System.out.println(&quot;[#] Successfully modified class: &quot; + oldClassName + &quot; to &quot; + newClassName);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println(&quot;[X] An error occurred during class modification.&quot;);
    }
}

}

Comments(0)

Join the discussion by logging into your account.

No comments yet. Be the first to comment!

I0veD
I0veD

cyber security researcher

Cloud Native & AI Sec Researcher Red Team | BAS | K8s | Evasion 20+ CVEs | CNVD/CNNVD Contributor ๐Ÿ›ก๏ธ AI-Driven Blue Team ๐Ÿ‘‡ Works

Subscribe to I0veD's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.