Skip to content

Instantly share code, notes, and snippets.

@Glavo
Last active November 23, 2021 10:43
Show Gist options
  • Save Glavo/aabbac7f206c56beeacd711c4726e260 to your computer and use it in GitHub Desktop.
Save Glavo/aabbac7f206c56beeacd711c4726e260 to your computer and use it in GitHub Desktop.
PanamaJIT Demo
import jdk.incubator.foreign.*;
import java.lang.invoke.*;
// Original code (C++): https://stackoverflow.com/a/40937610/7659948
public class PanamaJIT {
public static final int MEM_COMMIT = 0x00001000;
public static final int PAGE_READWRITE = 0x04;
public static final int PAGE_EXECUTE_READ = 0x20;
public static final int PAGE_SIZE = 4096;
private static final MethodHandle virtualAllocHandle;
private static final MethodHandle virtualProtectHandle;
static {
System.loadLibrary("Kernel32");
virtualAllocHandle = CLinker.getInstance().downcallHandle(
SymbolLookup.loaderLookup().lookup("VirtualAlloc").orElseThrow(UnsatisfiedLinkError::new),
MethodType.methodType(MemoryAddress.class, MemoryAddress.class, long.class, int.class, int.class),
FunctionDescriptor.of(CLinker.C_POINTER, CLinker.C_POINTER, CLinker.C_LONG_LONG, CLinker.C_LONG, CLinker.C_LONG)
);
virtualProtectHandle = CLinker.getInstance().downcallHandle(
SymbolLookup.loaderLookup().lookup("VirtualProtect").orElseThrow(UnsatisfiedLinkError::new),
MethodType.methodType(int.class, MemoryAddress.class, long.class, int.class, MemoryAddress.class),
FunctionDescriptor.of(CLinker.C_INT, CLinker.C_POINTER, CLinker.C_LONG_LONG, CLinker.C_LONG, CLinker.C_POINTER)
);
}
public static MemoryAddress VirtualAlloc(MemoryAddress lpAddress, long dwSize, int flAllocationType, int flProtect) {
try {
return (MemoryAddress) virtualAllocHandle.invokeExact(lpAddress, dwSize, flAllocationType, flProtect);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
public static boolean VirtualProtect(MemoryAddress lpAddress, long dwSize, int flNewProtect, MemoryAddress lpflOldProtect) {
try {
return (int) virtualProtectHandle.invokeExact(lpAddress, dwSize, flNewProtect, lpflOldProtect) != 0;
} catch (Throwable e) {
throw new AssertionError(e);
}
}
/*
* Return: () -> value
*/
private static byte[] compile(int value) {
/*
* movl $value, %eax
* retq
*/
return new byte[]{
(byte) 0xb8,
(byte) (value), (byte) (value >>> 8), (byte) (value >>> 16), (byte) (value >>> 24),
(byte) 0xc3
};
}
public static void main(String[] args) throws Throwable {
byte[] code = compile(Integer.parseInt(args[0]));
MemoryAddress buffer = VirtualAlloc(MemoryAddress.NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
buffer.asSegment(code.length, ResourceScope.globalScope()).copyFrom(MemorySegment.ofArray(code));
MemoryAddress dummy = CLinker.allocateMemory(4);
VirtualProtect(buffer, code.length, PAGE_EXECUTE_READ, dummy);
MethodHandle functionPtr = CLinker.getInstance().downcallHandle(
buffer,
MethodType.methodType(int.class),
FunctionDescriptor.of(CLinker.C_INT)
);
int result = (int) functionPtr.invokeExact();
assert result == Integer.parseInt(args[0]);
System.out.println("Result: " + result);
}
}
@Glavo
Copy link
Author

Glavo commented Nov 21, 2021

Platform: Windows AMD64, Java 17
Use java --add-modules jdk.incubator.foreign --enable-native-access=ALL-UNNAMED PanamaJIT.java <any integer> to run it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment