Last active
May 13, 2023 18:29
-
-
Save JNNGL/b3b7b503d105e188681da20a01631e3a to your computer and use it in GitHub Desktop.
JNI binding generation at runtime PoC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
void hello() { | |
puts("Hello, world!"); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.objectweb.asm.*; | |
import java.io.File; | |
import java.net.URL; | |
import java.net.URLClassLoader; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.util.Comparator; | |
import java.util.stream.Stream; | |
import static org.objectweb.asm.Opcodes.*; | |
public class Main { | |
public static void main(String[] args) throws Throwable { | |
ClassWriter cw = new ClassWriter(0); | |
cw.visit(49, ACC_PUBLIC + ACC_SUPER, "Test", null, "java/lang/Object", null); | |
// public static native void hello(); | |
cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_NATIVE, "hello", "()V", null, null).visitEnd(); | |
// public static void loadLibrary(String lib) { System.load(lib); } | |
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "loadLibrary", "(Ljava/lang/String;)V", null, null); | |
mv.visitVarInsn(ALOAD, 0); | |
mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "load", "(Ljava/lang/String;)V", false); | |
mv.visitInsn(RETURN); | |
mv.visitMaxs(1, 1); | |
mv.visitEnd(); | |
cw.visitEnd(); | |
Path directory = Files.createTempDirectory("test"); | |
Files.write(directory.resolve("Test.class"), cw.toByteArray()); | |
String bindingCode = """ | |
#include <jni.h> | |
extern void hello(); | |
JNIEXPORT void JNICALL Java_Test_hello(JNIEnv* env, jclass class) { | |
hello(); | |
}"""; | |
String targetLib = new File("hello.so").getAbsolutePath(); | |
Files.writeString(directory.resolve("glue.c"), bindingCode); | |
ProcessBuilder processBuilder = new ProcessBuilder("bash", "-c", "gcc -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -Os -fPIC -shared glue.c -o binding.so " + targetLib); | |
processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home")); | |
processBuilder.redirectErrorStream(true); | |
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); | |
processBuilder.directory(directory.toFile()); | |
processBuilder.start().waitFor(); // TODO: Write native library directly in binary form | |
try (URLClassLoader classLoader = new URLClassLoader(new URL[]{directory.toUri().toURL()})) { | |
Class<?> nativeBinding = classLoader.loadClass("Test"); | |
nativeBinding.getMethod("loadLibrary", String.class) | |
.invoke(null, directory.resolve("binding.so").toFile().getAbsolutePath()); | |
nativeBinding.getMethod("hello").invoke(null); | |
} | |
try (Stream<Path> stream = Files.walk(directory)) { | |
stream.sorted(Comparator.reverseOrder()) | |
.map(Path::toFile) | |
.forEach(File::deleteOnExit); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment