├── .gitignore ├── Doxyfile ├── LICENSE ├── Makefile ├── README.md ├── cleanup.c ├── cleanup.h ├── config.h ├── debugnet.c ├── debugnet.h ├── linker.x ├── load.c ├── load.h ├── nidcache-169.h ├── nidcache-3xx.h ├── nidcache.h ├── relocate.c ├── relocate.h ├── resolve.c ├── resolve.h ├── scefuncs.c ├── scefuncs.h ├── types.h ├── utils.c ├── utils.h ├── uvloader.c ├── uvloader.h └── uvloader.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | ._* 3 | *.obj 4 | *.o 5 | *.bin 6 | uvloader 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX=arm-vita-eabi 2 | CC=$(PREFIX)-gcc 3 | CFLAGS=-DUVLOADER -fPIE -fno-zero-initialized-in-bss -std=gnu99 -mcpu=cortex-a9 -D DEBUG -D FW_3XX -mthumb-interwork 4 | CFLAGS_THUMB=-mthumb 5 | LD=$(PREFIX)-gcc 6 | LDFLAGS=-T linker.x -nodefaultlibs -nostdlib -pie 7 | OBJCOPY=$(PREFIX)-objcopy 8 | OBJCOPYFLAGS= 9 | TARGET_LIB=libUVLoader_stub.a 10 | 11 | OBJ=uvloader.o cleanup.o load.o relocate.o resolve.o utils.o scefuncs.o debugnet.o 12 | 13 | all: uvloader 14 | 15 | scefuncs.o: scefuncs.c 16 | $(CC) -c -o $@ $< $(CFLAGS) 17 | 18 | %.o: %.c 19 | $(CC) -c -o $@ $< $(CFLAGS) $(CFLAGS_THUMB) 20 | 21 | uvloader: $(OBJ) 22 | $(LD) -o $@ $^ $(LDFLAGS) 23 | $(OBJCOPY) -O binary $@ $@.bin 24 | 25 | $(TARGET_LIB): uvloader.json 26 | mkdir build_lib 27 | vita-libs-gen uvloader.json build_lib 28 | cd build_lib && make 29 | mv build_lib/$(TARGET_LIB) $(TARGET_LIB) 30 | rm -rf build_lib 31 | 32 | check-env: 33 | ifndef VITASDK 34 | $(error VITASDK is not set) 35 | endif 36 | 37 | install_lib: check-env $(TARGET_LIB) uvloader.json uvloader.h 38 | cp $(TARGET_LIB) $(VITASDK)/arm-vita-eabi/lib 39 | cp uvloader.h $(VITASDK)/arm-vita-eabi/include/psp2/uvl.h 40 | cp uvloader.json $(VITASDK)/share/uvloader.json 41 | @echo "Installed!" 42 | 43 | .PHONY: clean 44 | 45 | clean: 46 | rm -rf *~ *.o *.elf *.bin *.s build_lib $(TARGET_LIB) uvloader 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Userland Vita Loader 1.1.0 2 | =============================================================================== 3 | 4 | ## What's new? 5 | 6 | ### Version 1.1.0 7 | 8 | * Added Unity PSM cleanup code (thanks Netrix) 9 | 10 | ### Version 1.0.1 11 | 12 | * Added support for multiple loads (stacked homebrew loading) 13 | 14 | ### Version 1.0.0 15 | 16 | * Relocatable ELF (ET_SCE_RELEXEC) support 17 | * ARM relocation resolving 18 | * SceLibKernel NID cache database (for NID poison bypass) 19 | * Library reloading (another NID antidote technique) 20 | * UVL custom exports (code alloc, icache flush, logging via USB) 21 | 22 | ### Version 0.1.0 23 | 24 | * Initial release 25 | 26 | ## What is this? 27 | 28 | In short, this is a loader that allows running homebrew games on the Vita using 29 | save-file exploits or similar methods where there is no access to the system 30 | loader functions (which are found in the kernel). UVL does this by hooking on 31 | to functions and API calls imported by the running game and passing them to 32 | the homebrew being loader. This is **not** a way to run backups or pirated 33 | games as that is not only wrong to do, but also because UVL does not and can 34 | not decrypt content nor can it do dynamic linking or other sophisticated things 35 | that the system loader does. 36 | 37 | ## How do I run it? 38 | 39 | UVL is designed to work with any userland exploit with little configuration. 40 | However, you should check with the developer of the exploit who ported UVL 41 | to see how to use it. UVL cannot do anything by itself, it is simply a 42 | payload that is executed by an exploit to run homebrews unmodified. 43 | 44 | ## How can I call UVL API functions from my homebrew? 45 | 46 | Make sure `$VITASDK` points to where the toolchain is installed. Then run 47 | `make install_lib` to install the UVL stub library to the right place. Then you 48 | can include `psp2/uvl.h` into your project and build with `-lUVLoader_stub`. 49 | Finally to create the resulting VELF, you need to pass the UVL JSON database 50 | as the parameter to `vita-elf-create` (`$(VITASDK)/share/uvloader.json`). 51 | See the documentation for details on the exported functions and when to use 52 | them. The library exposes functions for logging and dynamic code generation 53 | that is otherwise missing from the SDK. 54 | 55 | ## How do I port UVL? 56 | 57 | If you have an exploit for the Vita (not the PSP emulator as UVL does not work 58 | on that), then you should be able to port the exploit by finding a couple of 59 | memory addresses for some API calls and passing them to the config file. 60 | More information will be available when the time comes... 61 | 62 | ## How do I compile UVL? 63 | 64 | First of all, be aware that it is impossible to use UVL without an exploit, 65 | but once you have that and need a payload, all you need to do is modify 66 | the Makefile to point to your ARM toolchain and run "make". The toolchain 67 | that is tested with is . 68 | 69 | ## Who's responsible for this? 70 | 71 | This project is based heavily off of 72 | [Half Byte Loader](http://valentine-hbl.googlecode.com/) for the PSP. 73 | Some code is ripped from the 74 | [Bionic](https://github.com/android/platform_bionic/) libc project. 75 | The project is started by [Yifan Lu](http://yifan.lu/) with thanks to 76 | the following people for their contribution. (Apologies for those 77 | forgotten.) 78 | 79 | ### Thanks To 80 | 81 | * Davee for many ideas and help 82 | * Proxima for module reloading NID antidote method 83 | * naehrwert for some code snippets and programming help 84 | * roxfan for finding structures 85 | * Netrix for Unity cleanup code 86 | * anyone in #vitadev who answered my stupid questions 87 | -------------------------------------------------------------------------------- /cleanup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cleanup.c - Frees used memory by the game 3 | * Copyright 2012 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "uvloader.h" 19 | #include "cleanup.h" 20 | #include "resolve.h" 21 | #include "scefuncs.h" 22 | #include "utils.h" 23 | 24 | static u32_t unity_player_seg1 = 0x0; 25 | static int unity_version = 0x0; 26 | 27 | typedef u32_t (*cleanup_graphics_func)(void*); 28 | static cleanup_graphics_func cleanup_graphics; 29 | static int graphics_finished_cleaning = 0; 30 | 31 | typedef u32_t (*sceCtrlPeekBufferPositive_func)(int, u32_t*, int); 32 | static sceCtrlPeekBufferPositive_func sceCtrlPeekBufferPositive_syscall; 33 | 34 | /********************************************//** 35 | * \brief Convert L and R button values to what is expected. 36 | ***********************************************/ 37 | u32_t 38 | uvl_wrapper_sceCtrlPeekBufferPositive(int port, 39 | u32_t *pad_data, 40 | int count) 41 | { 42 | int res = sceCtrlPeekBufferPositive_syscall(port, pad_data, count); 43 | pad_data[2] |= (pad_data[2] & 0xF00) >> 2; // 0x400 (L) becomes 0x100 and 0x800 (R) becomes 0x200. 44 | pad_data[2] &= ~0xC00; 45 | 46 | return res; 47 | } 48 | 49 | /********************************************//** 50 | * \brief Add the resolved function to the table. 51 | ***********************************************/ 52 | void 53 | uvl_add_func_by_ptr(u32_t nid, 54 | u16_t type, 55 | void* func_ptr) 56 | { 57 | resolve_entry_t resolve_entry; 58 | resolve_entry.nid = nid; 59 | resolve_entry.type = type; 60 | resolve_entry.value.func_ptr = func_ptr; 61 | 62 | uvl_resolve_table_add(&resolve_entry); 63 | } 64 | 65 | void 66 | uvl_add_syscall_relative(u32_t nid, 67 | u32_t base_nid, 68 | int delta) 69 | { 70 | resolve_entry_t new_entry; 71 | new_entry.type = RESOLVE_TYPE_SYSCALL; 72 | 73 | // First make sure that the NID has not already been resolved. 74 | resolve_entry_t* entry = uvl_resolve_table_get(nid); 75 | if (entry == NULL) 76 | { 77 | resolve_entry_t* entry = uvl_resolve_table_get(base_nid); 78 | if (entry != NULL) 79 | { 80 | new_entry.nid = nid; 81 | new_entry.value.syscall = entry->value.syscall + delta; 82 | uvl_resolve_table_add(&new_entry); 83 | } 84 | } 85 | } 86 | 87 | /********************************************//** 88 | * \brief Check the Unity modules. 89 | * 90 | * Manually resolve functions from the modules. 91 | ***********************************************/ 92 | int 93 | uvl_cleanup_check_module(PsvUID modid, ///< UID of the module 94 | int index) ///< An OR combination of flags (see defined "Search flags for importing loaded modules") directing the search 95 | { 96 | loaded_module_info_t m_mod_info; 97 | m_mod_info.size = sizeof (loaded_module_info_t); // should be 440 98 | 99 | if (sceKernelGetModuleInfo(modid, &m_mod_info) < 0) 100 | { 101 | LOG("Error getting info for mod 0x%08X", modid); 102 | return -1; 103 | } 104 | 105 | if (strcmp(m_mod_info.module_name, "UnityPlayer") == 0) 106 | { 107 | uvl_unlock_mem(); 108 | 109 | unity_version = 0x105; // For now, it is assumed that this is version 1.05 since 1.06 has a different module name for UnityPlayer... 110 | unity_player_seg1 = (u32_t)m_mod_info.segments[1].vaddr; 111 | 112 | uvl_lock_mem(); 113 | } 114 | else if (strcmp(m_mod_info.module_name, "UnityPlayer_4370_Develop") == 0) 115 | { 116 | uvl_unlock_mem(); 117 | 118 | unity_version = 0x106; 119 | unity_player_seg1 = (u32_t)m_mod_info.segments[1].vaddr; 120 | 121 | u32_t unitybaseseg0 = (u32_t) m_mod_info.segments[0].vaddr; 122 | 123 | void* sceCtrlPeekBufferPositive_ptr = &uvl_wrapper_sceCtrlPeekBufferPositive; 124 | uvl_add_func_by_ptr(0xA9C3CED6, RESOLVE_TYPE_FUNCTION, (void*) (sceCtrlPeekBufferPositive_ptr)); // sceCtrlPeekBufferPositive 125 | sceCtrlPeekBufferPositive_syscall = (sceCtrlPeekBufferPositive_func) (unitybaseseg0 + 0x9E91CC); 126 | 127 | uvl_lock_mem(); 128 | } 129 | 130 | return 0; 131 | } 132 | 133 | /********************************************//** 134 | * \brief Hook for the Unity graphics thread 135 | * 136 | * Call the Unity graphics class destructor. 137 | ***********************************************/ 138 | void 139 | uvl_cleanup_graphics_thread_hook(void* r0) 140 | { 141 | IF_DEBUG LOG("Hooked the Unity graphics thread."); 142 | 143 | cleanup_graphics(r0); 144 | 145 | uvl_unlock_mem(); 146 | graphics_finished_cleaning = 1; 147 | uvl_lock_mem(); 148 | 149 | sceKernelExitDeleteThread(0); 150 | } 151 | 152 | /********************************************//** 153 | * \brief Clean up Unity 154 | * 155 | * Check if Unity PSM is running and cleans it. 156 | ***********************************************/ 157 | void 158 | uvl_clean_unity() 159 | { 160 | PsvUID mod_list[MAX_LOADED_MODS]; 161 | u32_t num_loaded = MAX_LOADED_MODS; 162 | 163 | if (sceKernelGetModuleList(0xFF, mod_list, &num_loaded) < 0) 164 | { 165 | LOG("Failed to get module list."); 166 | return; 167 | } 168 | 169 | int i; 170 | for (i = 0; i < num_loaded; i++) 171 | { 172 | if (uvl_cleanup_check_module(mod_list[i], i) < 0) 173 | { 174 | LOG("Failed to add module %u: 0x%08X. Continuing.", i, mod_list[i]); 175 | continue; 176 | } 177 | } 178 | 179 | if (unity_version != 0x0) 180 | { 181 | IF_DEBUG LOG("Unity Version: 0x%x", unity_version); 182 | 183 | uvl_unlock_mem(); 184 | 185 | uvl_add_syscall_relative(0x5795E898, 0x7D9864A8, -0x5); // sceDisplayWaitVblankStart 186 | uvl_add_syscall_relative(0x64167F11, 0x5BC341E4, 0x2); // sceAudioOutSetVolume 187 | 188 | u32_t setConfigModeNid = 0x3ce187b6; 189 | 190 | uvl_add_syscall_relative(0x2085d15d, setConfigModeNid, -0x4); // scePowerGetBatteryLifePercent 191 | uvl_add_syscall_relative(0x87440F5E, setConfigModeNid, 0xB); // scePowerIsPowerOnline 192 | 193 | if (unity_version == 0x106) 194 | { 195 | uvl_add_syscall_relative(0x1b04a1d6, setConfigModeNid, -0x7); // scePowerGetGpuClockFrequency 196 | uvl_add_syscall_relative(0x478fe6f5, setConfigModeNid, 0x2); // scePowerGetBusClockFrequency 197 | uvl_add_syscall_relative(0xb8d7b3fb, setConfigModeNid, 0x6); // scePowerSetGpuClockFrequency 198 | uvl_add_syscall_relative(0x74db5ae5, setConfigModeNid, 0x7); // scePowerSetArmClockFrequency 199 | uvl_add_syscall_relative(0xabc6f88f, setConfigModeNid, 0x11); // scePowerGetArmClockFrequency 200 | uvl_add_syscall_relative(0x717db06c, setConfigModeNid, 0x15); // scePowerSetBusClockFrequency 201 | } 202 | 203 | uvl_lock_mem(); 204 | 205 | u32_t cleanup_hook_ptr = (u32_t) &uvl_cleanup_graphics_thread_hook; 206 | u32_t new_graphics_class_vtable[250]; 207 | 208 | int i; 209 | for (i = 0; i < 250; ++i) 210 | { 211 | new_graphics_class_vtable[i] = cleanup_hook_ptr; 212 | } 213 | 214 | u32_t* graphics_class = *(u32_t**) (unity_player_seg1 + 0xEB8); 215 | u32_t* graphics_class_vtable = (u32_t*) *graphics_class; 216 | 217 | uvl_unlock_mem(); 218 | cleanup_graphics = (cleanup_graphics_func) (*(graphics_class_vtable + 1)); 219 | uvl_lock_mem(); 220 | 221 | // Overwrite the graphics class vtable. At some point after doing this, the graphics thread will call 'cleanup_graphics'. 222 | *graphics_class = (u32_t)new_graphics_class_vtable; 223 | 224 | // Give the graphics thread time to be hooked and exit. 225 | while (graphics_finished_cleaning == 0) 226 | { 227 | // sceKernelDelayThread should be used here, but it doesn't seem to work. 228 | } 229 | 230 | IF_DEBUG LOG("Finished cleaning Unity"); 231 | } 232 | } 233 | 234 | /********************************************//** 235 | * \brief Clean up used resources. 236 | ***********************************************/ 237 | void 238 | uvl_pre_clean () 239 | { 240 | uvl_clean_unity(); 241 | } 242 | 243 | /********************************************//** 244 | * \brief Free up the RAM 245 | * 246 | * Frees up memory used by the loaded game. 247 | * \returns Zero on success, otherwise error 248 | ***********************************************/ 249 | int 250 | uvl_cleanup_memory () 251 | { 252 | // close and delete all threads 253 | if (uvl_unload_all_modules () < 0) 254 | { 255 | LOG ("Failed to unload all modules."); 256 | return -1; 257 | } 258 | // free allocated memory 259 | // delete event flags, semaphors, mutexs, etc 260 | // close all file handles 261 | } 262 | 263 | /********************************************//** 264 | * \brief Unloads loaded modules 265 | * 266 | * \returns Zero on success, otherwise error 267 | ***********************************************/ 268 | int 269 | uvl_unload_all_modules () 270 | { 271 | loaded_module_info_t m_mod_info; 272 | PsvUID mod_list[MAX_LOADED_MODS]; 273 | u32_t num_loaded = MAX_LOADED_MODS; 274 | int status; 275 | int i; 276 | 277 | if (sceKernelGetModuleList (0xFF, mod_list, &num_loaded) < 0) 278 | { 279 | LOG ("Failed to get module list."); 280 | return -1; 281 | } 282 | for (i = 0; i < num_loaded; i++) 283 | { 284 | if (sceKernelStopUnloadModule (mod_list[i], 0, NULL, &status, NULL) < 0) 285 | { 286 | LOG ("Failed to unload module %X, continuing...", mod_list[i]); 287 | continue; 288 | } 289 | } 290 | return 0; 291 | } -------------------------------------------------------------------------------- /cleanup.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file cleanup.h 3 | /// \brief Functions to clean up memory 4 | /// \defgroup cleanup Memory Cleanup 5 | /// \brief Frees memory before loading 6 | /// @{ 7 | /// 8 | #ifndef UVL_CLEANUP 9 | #define UVL_CLEANUP 10 | 11 | #include "types.h" 12 | 13 | int uvl_cleanup_memory (); 14 | int uvl_unload_all_modules(); 15 | void uvl_pre_clean(); 16 | 17 | #endif 18 | /// @} 19 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file config.h 3 | /// \brief Constants specific to current exploit 4 | /// @{ 5 | /// 6 | #ifndef UVL_CONFIG 7 | #define UVL_CONFIG 8 | 9 | #define UVL_HOMEBREW_PATH "cache0:/VitaDefilerClient/Documents/homebrew.self" ///< Where to load the homebrew. 10 | #define UVL_LOG_PATH "cache0:/VitaDefilerClient/Documents/uvloader.log" ///< Where to print the log 11 | 12 | #endif 13 | /// @} 14 | -------------------------------------------------------------------------------- /debugnet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * debugnet library for PSP2 3 | * Copyright (C) 2010,2015 Antonio Jose Ramos Marquez (aka bigboss) @psxdev on twitter 4 | * Repository https://github.com/psxdev/debugnet 5 | */ 6 | 7 | #include "uvloader.h" 8 | #include "scefuncs.h" 9 | #include "debugnet.h" 10 | 11 | static int debugnet_initialized = 0; 12 | static int SocketFD = -1; 13 | static u8_t net_memory[NET_INIT_SIZE]; 14 | static SceNetInAddr vita_addr; 15 | static struct SceNetSockaddrIn stSockAddr; 16 | 17 | int debugNetSetup() 18 | { 19 | uvl_scefuncs_resolve_debugnet(); 20 | 21 | uvl_set_debug_log_func(&uvl_debugnet_log); 22 | 23 | return debugNetInit("255.255.255.255", 18194); 24 | } 25 | 26 | int uvl_debugnet_log(const char *line) 27 | { 28 | debugNetUDPPrintf("%s\n", line); 29 | return 0; 30 | } 31 | 32 | int debugNetSend(const char* line, u32_t size) 33 | { 34 | int res = sceNetSendto(SocketFD, line, size, 0, (struct SceNetSockaddr *)&stSockAddr, sizeof stSockAddr); 35 | if (res < 0) 36 | return res; 37 | 38 | return 0; 39 | } 40 | 41 | /** 42 | * UDP printf for debugnet library 43 | * 44 | * @par Example: 45 | * @code 46 | * debugNetUDPPrintf("This is a test\n"); 47 | * @endcode 48 | */ 49 | void debugNetUDPPrintf(const char* fmt, ...) 50 | { 51 | char buffer[0x800]; 52 | va_list arg; 53 | va_start(arg, fmt); 54 | sceClibVsnprintf(buffer, sizeof(buffer), fmt, arg); 55 | va_end(arg); 56 | 57 | debugNetSend(buffer, strlen(buffer)); 58 | } 59 | 60 | /** 61 | * Init debugnet library 62 | * 63 | * @par Example: 64 | * @code 65 | * int ret; 66 | * ret = debugNetInit("172.26.0.2", 18194); 67 | * @endcode 68 | * 69 | * @param serverIP - your pc/mac server ip 70 | * @param port - udp port server 71 | */ 72 | int debugNetInit(const char *serverIp, u16_t port) 73 | { 74 | int ret; 75 | SceNetInitParam initparam; 76 | SceNetCtlInfo info; 77 | if (debugnet_initialized) { 78 | return debugnet_initialized; 79 | } 80 | 81 | /*net initialazation code from xerpi at https://github.com/xerpi/FTPVita/blob/master/ftp.c*/ 82 | /* Init Net */ 83 | if (sceNetShowNetstat() == PSP2_NET_ERROR_ENOTINIT) { 84 | initparam.memory = net_memory; 85 | initparam.size = NET_INIT_SIZE; 86 | initparam.flags = 0; 87 | 88 | ret = sceNetInit(&initparam); 89 | 90 | //printf("sceNetInit(): 0x%08X\n", ret); 91 | } else { 92 | //printf("Net is already initialized.\n"); 93 | } 94 | 95 | /* Init NetCtl */ 96 | ret = sceNetCtlInit(); 97 | //printf("sceNetCtlInit(): 0x%08X\n", ret); 98 | 99 | /* Get IP address */ 100 | ret = sceNetCtlInetGetInfo(PSP2_NETCTL_INFO_GET_IP_ADDRESS, &info); 101 | //printf("sceNetCtlInetGetInfo(): 0x%08X\n", ret); 102 | 103 | /* Save the IP of PSVita to a global variable */ 104 | sceNetInetPton(PSP2_NET_AF_INET, info.ip_address, &vita_addr); 105 | 106 | uvl_unlock_mem(); 107 | 108 | /* Create datagram udp socket*/ 109 | SocketFD = sceNetSocket("debugnet_socket", 110 | PSP2_NET_AF_INET, PSP2_NET_SOCK_DGRAM, PSP2_NET_IPPROTO_UDP); 111 | 112 | memset(&stSockAddr, 0, sizeof stSockAddr); 113 | 114 | /*Populate SceNetSockaddrIn structure values*/ 115 | stSockAddr.sin_family = PSP2_NET_AF_INET; 116 | stSockAddr.sin_port = sceNetHtons(port); 117 | 118 | int broadcast = 1; 119 | sceNetSetsockopt(SocketFD, PSP2_NET_SOL_SOCKET, PSP2_NET_SO_BROADCAST, &broadcast, sizeof(broadcast)); 120 | 121 | sceNetInetPton(PSP2_NET_AF_INET, serverIp, &stSockAddr.sin_addr); 122 | 123 | /*Show log on pc/mac side*/ 124 | /*debugNetUDPPrintf("debugnet initialized\n"); 125 | debugNetUDPPrintf("Copyright (C) 2010,2015 Antonio Jose Ramos Marquez aka bigboss @psxdev\n"); 126 | debugNetUDPPrintf("This Program is subject to the terms of the Mozilla Public\n" 127 | "License, v. 2.0. If a copy of the MPL was not distributed with this\n" 128 | "file, You can obtain one at http://mozilla.org/MPL/2.0/.\n"); 129 | debugNetUDPPrintf("ready to have a lot of fun...\n");*/ 130 | 131 | /*library debugnet initialized*/ 132 | debugnet_initialized = 1; 133 | uvl_lock_mem(); 134 | 135 | return debugnet_initialized; 136 | } 137 | 138 | /** 139 | * Finish debugnet library 140 | * 141 | * @par Example: 142 | * @code 143 | * debugNetFinish(); 144 | * @endcode 145 | */ 146 | void debugNetFinish() 147 | { 148 | if (debugnet_initialized) { 149 | 150 | sceNetCtlTerm(); 151 | sceNetTerm(); 152 | 153 | uvl_unlock_mem(); 154 | debugnet_initialized = 0; 155 | uvl_lock_mem(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /debugnet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * debugnet library for PSP2 3 | * Copyright (C) 2010,2015 Antonio Jose Ramos Marquez (aka bigboss) @psxdev on twitter 4 | * Repository https://github.com/psxdev/debugnet 5 | */ 6 | #ifndef _DEBUGNET_H_ 7 | #define _DEBUGNET_H_ 8 | 9 | #include "types.h" 10 | #include "utils.h" 11 | 12 | #define PSP2_NET_AF_INET 2 13 | #define PSP2_NET_SOCK_DGRAM 2 14 | #define PSP2_NET_IPPROTO_UDP 17 15 | #define PSP2_NET_SOL_SOCKET 0xffff 16 | #define PSP2_NET_SO_BROADCAST 0x00000020 17 | #define PSP2_NET_ERROR_ENOTINIT 0x804101C8 18 | #define PSP2_NETCTL_INFO_GET_IP_ADDRESS 15 19 | #define PSP2_NETCTL_INFO_CONFIG_NAME_LEN_MAX 64 20 | #define PSP2_NETCTL_INFO_SSID_LEN_MAX 32 21 | 22 | typedef struct SceNetInitParam { 23 | void *memory; 24 | s32_t size; 25 | s32_t flags; 26 | } SceNetInitParam; 27 | 28 | typedef struct SceNetInAddr { 29 | u32_t s_addr; 30 | } SceNetInAddr; 31 | 32 | typedef struct SceNetSockaddrIn { 33 | u8_t sin_len; 34 | u8_t sin_family; 35 | u16_t sin_port; 36 | SceNetInAddr sin_addr; 37 | u16_t sin_vport; 38 | s8_t sin_zero[6]; 39 | } SceNetSockaddrIn; 40 | 41 | typedef struct SceNetEtherAddr { 42 | u8_t data[6]; 43 | } SceNetEtherAddr; 44 | 45 | typedef union SceNetCtlInfo { 46 | s8_t cnf_name[PSP2_NETCTL_INFO_CONFIG_NAME_LEN_MAX + 1]; 47 | u32_t device; 48 | SceNetEtherAddr ether_addr; 49 | u32_t mtu; 50 | u32_t link; 51 | SceNetEtherAddr bssid; 52 | s8_t ssid[PSP2_NETCTL_INFO_SSID_LEN_MAX + 1]; 53 | u32_t wifi_security; 54 | u32_t rssi_dbm; 55 | u32_t rssi_percentage; 56 | u32_t channel; 57 | u32_t ip_config; 58 | s8_t dhcp_hostname[256]; 59 | s8_t pppoe_auth_name[128]; 60 | s8_t ip_address[16]; 61 | s8_t netmask[16]; 62 | s8_t default_route[16]; 63 | s8_t primary_dns[16]; 64 | s8_t secondary_dns[16]; 65 | u32_t http_proxy_config; 66 | s8_t http_proxy_server[256]; 67 | u32_t http_proxy_port; 68 | } SceNetCtlInfo; 69 | 70 | 71 | #define NET_INIT_SIZE 1*1024*1024 72 | 73 | int debugNetSetup(); 74 | int debugNetInit(const char *serverIp, u16_t port); 75 | void debugNetFinish(); 76 | int debugNetSend(const char* line, u32_t size); 77 | void debugNetUDPPrintf(const char* fmt, ...); 78 | int uvl_debugnet_log(const char *line); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /linker.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | ENTRY(uvl_start) 5 | 6 | SECTIONS 7 | { 8 | .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } 9 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 10 | .data : { *(.data .data.* .gnu.linkonce.d.*) } 11 | .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } 12 | } 13 | -------------------------------------------------------------------------------- /load.c: -------------------------------------------------------------------------------- 1 | /* 2 | * load.c - Parses and loads an ELF to memory 3 | * Copyright 2012 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "load.h" 18 | #include "relocate.h" 19 | #include "resolve.h" 20 | #include "scefuncs.h" 21 | #include "utils.h" 22 | #include "uvloader.h" 23 | 24 | static module_imports_t *g_import_start; 25 | static void *g_import_end; 26 | 27 | /********************************************//** 28 | * \brief Loads file to memory 29 | * 30 | * \returns Zero on success, otherwise error 31 | ***********************************************/ 32 | int 33 | uvl_load_file (const char *filename, ///< File to load 34 | void **data, ///< Output pointer to data 35 | PsvSSize *size) ///< Output pointer to data size 36 | { 37 | PsvUID fd; 38 | PsvUID memblock; 39 | char *base; 40 | PsvOff filesz; 41 | PsvOff nread; 42 | PsvSSize nbytes; 43 | 44 | fd = sceIoOpen (filename, PSP2_O_RDONLY, 0); 45 | if (fd < 0) 46 | { 47 | LOG ("Failed to open %s for reading.", filename); 48 | return -1; 49 | } 50 | filesz = sceIoLseek (fd, 0LL, PSP2_SEEK_END); 51 | if (filesz < 0) 52 | { 53 | LOG ("Failed to find file size: 0x%X", filesz); 54 | return -1; 55 | } 56 | sceIoLseek (fd, 0LL, PSP2_SEEK_SET); 57 | memblock = sceKernelAllocMemBlock ("UVLTemp", 0xC20D060, (filesz + 0xFFF) & ~0xFFF, NULL); 58 | if (memblock < 0) 59 | { 60 | LOG ("Failed allocate %u bytes of memory.", memblock); 61 | return -1; 62 | } 63 | if (sceKernelGetMemBlockBase (memblock, &base) < 0) 64 | { 65 | LOG ("Failed to locate base for block 0x%08X.", memblock); 66 | return -1; 67 | } 68 | base = (char *)(((u32_t)base + 0xFFF) & ~0xFFF); // align memory base 69 | nbytes = 0; 70 | while ((nread = sceIoRead (fd, base+nbytes, filesz)) < filesz-nbytes) 71 | { 72 | nbytes += nread; 73 | } 74 | if (nbytes < 0) 75 | { 76 | LOG ("Failed to read %s: 0x%08X", filename, nbytes); 77 | return -1; 78 | } 79 | IF_DEBUG LOG ("Read %u bytes from %s", nbytes, filename); 80 | if (sceIoClose (fd) < 0) 81 | { 82 | LOG ("Failed to close file."); 83 | return -1; 84 | } 85 | 86 | *data = base; 87 | *size = nbytes; 88 | 89 | return 0; 90 | } 91 | 92 | /********************************************//** 93 | * \brief Frees data pointer created by load 94 | * 95 | * \returns Zero on success, otherwise error 96 | ***********************************************/ 97 | static inline int 98 | uvl_free_data (void *data) ///< Data allocated by @c uvl_load_file 99 | { 100 | PsvUID block; 101 | 102 | block = sceKernelFindMemBlockByAddr (data, 0); 103 | if (block < 0) 104 | { 105 | LOG ("Cannot find block id: 0x%08X", block); 106 | } 107 | if (sceKernelFreeMemBlock (block) < 0) 108 | { 109 | LOG ("Cannot free block: 0x%08X", block); 110 | return -1; 111 | } 112 | return 0; 113 | } 114 | 115 | /********************************************//** 116 | * \brief Loads an supported executable 117 | * 118 | * This function identifies and loads a 119 | * executable at the given file. 120 | * Currently supports ELF and SCE executable. 121 | * \returns Zero on success, otherwise error 122 | ***********************************************/ 123 | int 124 | uvl_load_exe (const char *filename, ///< Absolute path to executable 125 | void **entry, ///< Returned pointer to entry pointer 126 | uvl_loaded_t *loaded) ///< Pointer to loaded info 127 | { 128 | void *data; 129 | PsvSSize size; 130 | char *magic; 131 | u32_t offset; 132 | 133 | *entry = NULL; 134 | IF_DEBUG LOG ("Opening %s for reading.", filename); 135 | if (uvl_load_file (filename, &data, &size) < 0) 136 | { 137 | LOG ("Cannot load file."); 138 | return -1; 139 | } 140 | 141 | magic = (char*)data; 142 | IF_VERBOSE LOG ("Magic number: 0x%02X 0x%02X 0x%02X 0x%02X", magic[0], magic[1], magic[2], magic[3]); 143 | 144 | if (magic[0] == ELFMAG0) 145 | { 146 | if (magic[1] == ELFMAG1 && magic[2] == ELFMAG2 && magic[3] == ELFMAG3) 147 | { 148 | IF_DEBUG LOG ("Found a ELF, loading."); 149 | if (uvl_load_elf (data, entry, loaded) < 0) 150 | { 151 | LOG ("Cannot load ELF."); 152 | return -1; 153 | } 154 | } 155 | } 156 | else if (magic[0] == SCEMAG0) 157 | { 158 | if (magic[1] == SCEMAG1 && magic[2] == SCEMAG2 && magic[3] == SCEMAG3) 159 | { 160 | offset = ((u32_t*)data)[4]; 161 | IF_DEBUG LOG ("Loading FSELF. ELF offset at 0x%08X", offset); 162 | if (uvl_load_elf ((void*)((u32_t)data + offset), entry, loaded) < 0) 163 | { 164 | LOG ("Cannot load FSELF."); 165 | return -1; 166 | } 167 | } 168 | } 169 | else 170 | { 171 | LOG ("Invalid magic."); 172 | return -1; 173 | } 174 | 175 | // free data 176 | if (uvl_free_data (data) < 0) 177 | { 178 | LOG ("Cannot free data"); 179 | return -1; 180 | } 181 | return 0; 182 | } 183 | 184 | /********************************************//** 185 | * \brief Loads an ELF file 186 | * 187 | * Performs both loading and resolving NIDs 188 | * \returns Zero on success, otherwise error 189 | ***********************************************/ 190 | int 191 | uvl_load_elf (void *data, ///< ELF data start 192 | void **entry, ///< Returned pointer to entry pointer 193 | uvl_loaded_t *loaded) ///< Pointer to loaded info 194 | { 195 | Elf32_Ehdr_t *elf_hdr; 196 | u32_t i; 197 | int addend; 198 | *entry = NULL; 199 | 200 | // get headers 201 | IF_VERBOSE LOG ("Reading headers."); 202 | elf_hdr = data; 203 | IF_DEBUG LOG ("Checking headers."); 204 | if (uvl_elf_check_header (elf_hdr) < 0) 205 | { 206 | LOG ("Check header failed."); 207 | return -1; 208 | } 209 | 210 | // get program headers 211 | Elf32_Phdr_t *prog_hdrs; 212 | IF_VERBOSE LOG ("Reading program headers."); 213 | prog_hdrs = (void*)((u32_t)data + elf_hdr->e_phoff); 214 | loaded->numsegs = elf_hdr->e_phnum; 215 | if (sizeof (PsvUID) * loaded->numsegs + sizeof (*loaded) > LOADED_INFO_SIZE) 216 | { 217 | LOG ("Too many segments: %d", elf_hdr->e_phnum); 218 | return -1; 219 | } 220 | 221 | // actually load the ELF 222 | PsvUID memblock; 223 | void *blockaddr; 224 | u32_t length; 225 | if (elf_hdr->e_phnum < 1) 226 | { 227 | LOG ("No program sections to load!"); 228 | return -1; 229 | } 230 | IF_DEBUG LOG ("Loading %u program segments.", elf_hdr->e_phnum); 231 | for (i = 0; i < elf_hdr->e_phnum; i++) 232 | { 233 | if (prog_hdrs[i].p_type == PT_LOAD) 234 | { 235 | length = prog_hdrs[i].p_memsz; 236 | length = (length + 0xFFFFF) & ~0xFFFFF; // Align to 1MB 237 | if (prog_hdrs[i].p_flags & PF_X == PF_X) // executable section 238 | { 239 | memblock = sceKernelAllocCodeMemBlock ("UVLHomebrew", length); 240 | } 241 | else // data section 242 | { 243 | memblock = sceKernelAllocMemBlock ("UVLHomebrew", 0xC20D060, length, NULL); 244 | } 245 | if (memblock < 0) 246 | { 247 | LOG ("Error allocating memory. 0x%08X", memblock); 248 | return -1; 249 | } 250 | if (sceKernelGetMemBlockBase (memblock, &blockaddr) < 0) 251 | { 252 | LOG ("Error getting memory block address."); 253 | } 254 | 255 | // remember where we're loaded 256 | loaded->segs[i] = memblock; 257 | prog_hdrs[i].p_vaddr = blockaddr; 258 | 259 | IF_DEBUG LOG ("Allocated memory at 0x%08X, attempting to load segment %u.", (u32_t)blockaddr, i); 260 | uvl_segment_write (&prog_hdrs[i], 0, (void*)((u32_t)data + prog_hdrs[i].p_offset), prog_hdrs[i].p_filesz); 261 | uvl_unlock_mem (); 262 | memset ((void*)((u32_t)blockaddr + prog_hdrs[i].p_filesz), 0, prog_hdrs[i].p_memsz - prog_hdrs[i].p_filesz); 263 | uvl_lock_mem (); 264 | } 265 | else if (prog_hdrs[i].p_type == PT_SCE_RELA) 266 | { 267 | uvl_relocate ((void*)((u32_t)data + prog_hdrs[i].p_offset), prog_hdrs[i].p_filesz, prog_hdrs); 268 | } 269 | else 270 | { 271 | IF_DEBUG LOG ("Segment %u is not loadable. Skipping.", i); 272 | continue; 273 | } 274 | } 275 | 276 | // get mod_info 277 | module_info_t *mod_info; 278 | int idx; 279 | IF_DEBUG LOG ("Getting module info."); 280 | if ((idx = uvl_elf_get_module_info (elf_hdr, prog_hdrs, &mod_info)) < 0) 281 | { 282 | LOG ("Cannot find module info section."); 283 | return -1; 284 | } 285 | IF_DEBUG LOG ("Module name: %s, export table offset: 0x%08X, import table offset: 0x%08X", mod_info->modname, mod_info->ent_top, mod_info->stub_top); 286 | 287 | // resolve NIDs 288 | uvl_unlock_mem (); 289 | g_import_start = (void*)(prog_hdrs[idx].p_vaddr + mod_info->stub_top); 290 | g_import_end = (void*)(prog_hdrs[idx].p_vaddr + mod_info->stub_end); 291 | uvl_lock_mem (); 292 | 293 | module_imports_t *import = g_import_start; 294 | void *end = g_import_end; 295 | 296 | for (; (void *)import < end; import = IMP_GET_NEXT (import)) 297 | { 298 | IF_DEBUG LOG ("Resolving imports for %s", IMP_GET_NAME (import)); 299 | if (uvl_resolve_imports (import) < 0) 300 | { 301 | LOG ("Failed to resolve imports for %s", IMP_GET_NAME (import)); 302 | return -1; 303 | } 304 | } 305 | 306 | // find the entry point 307 | *entry = (void*)(prog_hdrs[idx].p_vaddr + mod_info->mod_start); 308 | if (*entry == NULL) 309 | { 310 | LOG ("Invalid module entry function.\n"); 311 | return -1; 312 | } 313 | 314 | return 0; 315 | } 316 | 317 | int 318 | uvl_resolve_import_by_name(const char *name) 319 | { 320 | module_imports_t *import = g_import_start; 321 | void *end = g_import_end; 322 | 323 | for (; (void *)import < end; import = IMP_GET_NEXT (import)) 324 | { 325 | if (strcmp(name, IMP_GET_NAME (import)) == 0) { 326 | IF_DEBUG LOG ("Resolving imports for %s", IMP_GET_NAME (import)); 327 | if (uvl_resolve_imports (import) < 0) 328 | { 329 | LOG ("Failed to resolve imports for %s", IMP_GET_NAME (import)); 330 | return -1; 331 | } 332 | 333 | return 0; 334 | } 335 | } 336 | 337 | return -1; 338 | } 339 | 340 | /********************************************//** 341 | * \brief Validates ELF header 342 | * 343 | * Makes sure the ELF is recognized by the 344 | * Vita's architecture. 345 | * \returns Zero if valid, otherwise invalid 346 | ***********************************************/ 347 | int 348 | uvl_elf_check_header (Elf32_Ehdr_t *hdr) ///< ELF header to check 349 | { 350 | IF_VERBOSE LOG ("Magic number: 0x%02X 0x%02X 0x%02X 0x%02X", hdr->e_ident[EI_MAG0], hdr->e_ident[EI_MAG1], hdr->e_ident[EI_MAG2], hdr->e_ident[EI_MAG3]); 351 | // magic number 352 | if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && hdr->e_ident[EI_MAG1] == ELFMAG1 && hdr->e_ident[EI_MAG2] == ELFMAG2 && hdr->e_ident[EI_MAG3] == ELFMAG3)) 353 | { 354 | LOG ("Invalid ELF magic number."); 355 | return -1; 356 | } 357 | // class 358 | if (!(hdr->e_ident[EI_CLASS] == ELFCLASS32)) 359 | { 360 | LOG ("Not a 32bit executable."); 361 | return -1; 362 | } 363 | // data 364 | if (!(hdr->e_ident[EI_DATA] == ELFDATA2LSB)) 365 | { 366 | LOG ("Not a valid ARM executable."); 367 | return -1; 368 | } 369 | // version 370 | if (!(hdr->e_ident[EI_VERSION] == EV_CURRENT)) 371 | { 372 | LOG ("Unsupported ELF version."); 373 | return -1; 374 | } 375 | // type 376 | if (!hdr->e_type == ET_SCE_RELEXEC) 377 | { 378 | LOG ("Only ET_SCE_RELEXEC files are supported."); 379 | return -1; 380 | } 381 | // machine 382 | if (!(hdr->e_machine == EM_ARM)) 383 | { 384 | LOG ("Not an ARM executable."); 385 | return -1; 386 | } 387 | // version 388 | if (!(hdr->e_version == EV_CURRENT)) 389 | { 390 | LOG ("Unsupported ELF version."); 391 | return -1; 392 | } 393 | return 0; 394 | } 395 | 396 | /********************************************//** 397 | * \brief Finds SCE module info 398 | * 399 | * This finds the module_info_t for this SCE 400 | * ELF. 401 | * \returns -1 on error, index of segment 402 | * containing module info on success. 403 | ***********************************************/ 404 | int 405 | uvl_elf_get_module_info (Elf32_Ehdr_t *elf_hdr, ///< ELF header 406 | Elf32_Phdr_t *elf_phdrs, ///< ELF program headers 407 | module_info_t **mod_info) ///< Where to read information to 408 | { 409 | u32_t offset; 410 | u32_t index; 411 | 412 | index = ((u32_t)elf_hdr->e_entry & 0xC0000000) >> 30; 413 | offset = (u32_t)elf_hdr->e_entry & 0x3FFFFFFF; 414 | 415 | if (elf_phdrs[index].p_vaddr == NULL) 416 | { 417 | LOG ("Invalid segment index %d\n", index); 418 | return -1; 419 | } 420 | 421 | *mod_info = (module_info_t *)((char *)elf_phdrs[index].p_vaddr + offset); 422 | 423 | return index; 424 | } 425 | 426 | // No longer needed for relocatable ELFs 427 | #if 0 428 | /********************************************//** 429 | * \brief Frees memory of where we want to load 430 | * 431 | * Finds the max and min addresses we want to 432 | * load to using program headers and frees 433 | * any module taking up those spaces. 434 | * \returns Zero on success, otherwise error 435 | ***********************************************/ 436 | int 437 | uvl_elf_free_memory (Elf32_Phdr_t *prog_hdrs, ///< Array of program headers 438 | int count) ///< Number of program headers 439 | { 440 | void *min_addr = (void*)0xFFFFFFFF; 441 | void *max_addr = (void*)0x00000000; 442 | loaded_module_info_t m_mod_info; 443 | PsvUID mod_list[MAX_LOADED_MODS]; 444 | u32_t num_loaded = MAX_LOADED_MODS; 445 | int i, j; 446 | u32_t length; 447 | int temp[2]; 448 | 449 | IF_VERBOSE LOG ("Reading %u program headers.", count); 450 | for (i = 0; i < count; i++) 451 | { 452 | if (prog_hdrs[i].p_vaddr < min_addr) 453 | { 454 | min_addr = prog_hdrs[i].p_vaddr; 455 | } 456 | if ((u32_t)prog_hdrs[i].p_vaddr + prog_hdrs[i].p_memsz > (u32_t)max_addr) 457 | { 458 | max_addr = (void*)((u32_t)prog_hdrs[i].p_vaddr + prog_hdrs[i].p_memsz); 459 | } 460 | } 461 | IF_DEBUG LOG ("Lowest load address: 0x%08X, highest: 0x%08X", (u32_t)min_addr, (u32_t)max_addr);\ 462 | 463 | IF_DEBUG LOG ("Getting list of loaded modules."); 464 | if (sceKernelGetModuleList (0xFF, mod_list, &num_loaded) < 0) 465 | { 466 | LOG ("Failed to get module list."); 467 | return -1; 468 | } 469 | IF_DEBUG LOG ("Found %u loaded modules.", num_loaded); 470 | for (i = 0; i < num_loaded; i++) 471 | { 472 | m_mod_info.size = sizeof (loaded_module_info_t); // should be 440 473 | IF_VERBOSE LOG ("Getting information for module #%u, UID: 0x%X.", i, mod_list[i]); 474 | if (sceKernelGetModuleInfo (mod_list[i], &m_mod_info) < 0) 475 | { 476 | LOG ("Error getting info for mod 0x%08X, continuing", mod_list[i]); 477 | continue; 478 | } 479 | for (j = 0; j < 3; j++) 480 | { 481 | //if (m_mod_info.segments[j].vaddr > min_addr || (u32_t)m_mod_info.segments[j].vaddr + m_mod_info.segments[j].memsz > (u32_t)min_addr) 482 | if (m_mod_info.segments[j].vaddr == (void*)0x81000000) 483 | { 484 | IF_DEBUG LOG ("Module %s segment %u (0x%08X, size %u) is in our address space. Attempting to unload.", m_mod_info.module_name, j, (u32_t)m_mod_info.segments[j].vaddr, m_mod_info.segments[j].memsz); 485 | if (sceKernelStopUnloadModule (mod_list[i], 0, 0, 0, &temp[0], &temp[1]) < 0) 486 | { 487 | LOG ("Error unloading %s.", m_mod_info.module_name); 488 | return -1; 489 | } 490 | break; 491 | } 492 | } 493 | } 494 | return 0; 495 | } 496 | #endif 497 | -------------------------------------------------------------------------------- /load.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file load.h 3 | /// \brief Functions to load executable 4 | /// \defgroup load Executable Loader 5 | /// \brief Parses and loads ELFs 6 | /// @{ 7 | /// 8 | #ifndef UVL_LOAD 9 | #define UVL_LOAD 10 | 11 | #include "types.h" 12 | 13 | /** \name ELF data types 14 | * @{ 15 | */ 16 | typedef void* Elf32_Addr; 17 | typedef u32_t Elf32_Off; 18 | typedef u32_t Elf32_Sword; 19 | typedef u32_t Elf32_Word; 20 | typedef u16_t Elf32_Half; 21 | /** @}*/ 22 | 23 | /** \name ELF identification 24 | * @{ 25 | */ 26 | #define EI_NIDENT 16 27 | #define EI_MAG0 0 28 | #define EI_MAG1 1 29 | #define EI_MAG2 2 30 | #define EI_MAG3 3 31 | #define EI_CLASS 4 32 | #define EI_DATA 5 33 | #define EI_VERSION 6 34 | #define EI_PAD 7 35 | #define ELFMAG0 0x7F 36 | #define ELFMAG1 'E' 37 | #define ELFMAG2 'L' 38 | #define ELFMAG3 'F' 39 | #define ELFCLASS32 1 40 | #define ELFDATA2LSB 1 41 | /** @}*/ 42 | /** \name ELF object types 43 | * @{ 44 | */ 45 | #define ET_EXEC 0x0002 46 | #define ET_SCE_EXEC 0xFE00 47 | #define ET_SCE_RELEXEC 0xFE04 48 | /** @}*/ 49 | /** \name ELF machine types 50 | * @{ 51 | */ 52 | #define EM_ARM 40 53 | /** @}*/ 54 | /** \name ELF version 55 | * @{ 56 | */ 57 | #define EV_CURRENT 1 58 | /** @}*/ 59 | /** \name ELF sh section type 60 | * @{ 61 | */ 62 | #define SHT_RELA 4 63 | #define SHT_REL 9 64 | /** @}*/ 65 | /** \name ELF ph section type 66 | * @{ 67 | */ 68 | #define PT_LOAD 1 69 | #define PT_SCE_RELA 0x60000000 70 | /** @}*/ 71 | /** \name ELF ph formats 72 | * @{ 73 | */ 74 | #define PF_X 1 75 | #define PF_W 2 76 | #define PF_R 4 77 | /** @}*/ 78 | /** \name SCE identification 79 | * @{ 80 | */ 81 | #define MAGIC_LEN 4 82 | #define SCEMAG0 'S' 83 | #define SCEMAG1 'C' 84 | #define SCEMAG2 'E' 85 | #define SCEMAG3 0 86 | /** @}*/ 87 | #define UVL_SEC_MODINFO ".sceModuleInfo.rodata" ///< Name of module information section 88 | #define UVL_SEC_MIN_ALIGN 0x100000 ///< Alignment of each section 89 | #define ATTR_MOD_INFO 0x8000 ///< module_exports_t attribute 90 | 91 | /** \name ELF structures 92 | * See the ELF specification for more information. 93 | * @{ 94 | */ 95 | typedef struct Elf32_Ehdr 96 | { 97 | u8_t e_ident[EI_NIDENT]; 98 | Elf32_Half e_type; 99 | Elf32_Half e_machine; 100 | Elf32_Word e_version; 101 | Elf32_Addr e_entry; 102 | Elf32_Off e_phoff; 103 | Elf32_Off e_shoff; 104 | Elf32_Word e_flags; 105 | Elf32_Half e_ehsize; 106 | Elf32_Half e_phentsize; 107 | Elf32_Half e_phnum; 108 | Elf32_Half e_shentsize; 109 | Elf32_Half e_shnum; 110 | Elf32_Half e_shstrndx; 111 | } Elf32_Ehdr_t; 112 | 113 | typedef struct Elf32_Shdr 114 | { 115 | Elf32_Word sh_name; 116 | Elf32_Word sh_type; 117 | Elf32_Word sh_flags; 118 | Elf32_Addr sh_addr; 119 | Elf32_Off sh_offset; 120 | Elf32_Word sh_size; 121 | Elf32_Word sh_link; 122 | Elf32_Word sh_info; 123 | Elf32_Word sh_addralign; 124 | Elf32_Word sh_entsize; 125 | } Elf32_Shdr_t; 126 | 127 | typedef struct Elf32_Phdr 128 | { 129 | Elf32_Word p_type; 130 | Elf32_Off p_offset; 131 | Elf32_Addr p_vaddr; 132 | Elf32_Addr p_paddr; 133 | Elf32_Word p_filesz; 134 | Elf32_Word p_memsz; 135 | Elf32_Word p_flags; 136 | Elf32_Word p_align; 137 | } Elf32_Phdr_t; 138 | /** @}*/ 139 | 140 | /** \cond predefined-types 141 | * @{ 142 | */ 143 | typedef struct module_info module_info_t; 144 | typedef struct uvl_loaded uvl_loaded_t; 145 | /** @}*/ 146 | 147 | /** \name Functions to load code 148 | * @{ 149 | */ 150 | int uvl_load_file (const char *filename, void **data, PsvSSize *size); 151 | int uvl_load_exe (const char *filename, void **entry, uvl_loaded_t *loaded); 152 | int uvl_load_elf (void *data, void **entry, uvl_loaded_t *loaded); 153 | /** @}*/ 154 | /** \name Helper functions 155 | * @{ 156 | */ 157 | int uvl_resolve_import_by_name(const char *name); 158 | int uvl_elf_check_header (Elf32_Ehdr_t *hdr); 159 | int uvl_elf_get_module_info (Elf32_Ehdr_t *elf_hdr, Elf32_Phdr_t *elf_phdrs, module_info_t **mod_info); 160 | //int uvl_elf_free_memory (Elf32_Phdr_t *prog_hdrs, int count); 161 | /** @}*/ 162 | 163 | #endif 164 | /// @} 165 | -------------------------------------------------------------------------------- /nidcache-169.h: -------------------------------------------------------------------------------- 1 | const nid_cache_db libkernel_nid_cache_header[] = { 2 | {0x37FE725A, 4}, // SceSysmem 3 | {0x859A24B1, 160}, // SceThreadmgr 4 | {0xEAED1616, 10}, // SceModulemgr 5 | {0x2DD91812, 7}, // SceProcessmgr 6 | {0xF2FF276E, 58}, // SceIofilemgr 7 | {0, 0} 8 | }; 9 | 10 | const u32_t libkernel_nid_cache[] = { 11 | // SceSysmem 12 | 0xA33B99D1, 13 | 0xA91E15EE, 14 | 0xB8EF5818, 15 | 0xB9D5EBDE, 16 | // SceThreadmgr 17 | 0x3CFCF00, 18 | 0x402C633, 19 | 0x40795C7, 20 | 0x558B7C1, 21 | 0x5C51CE1, 22 | 0x7D2584A, 23 | 0xC8A38E1, 24 | 0xD76458E, 25 | 0xF11545D, 26 | 0x106C216F, 27 | 0x118F646E, 28 | 0x12948A63, 29 | 0x13117B21, 30 | 0x151E0020, 31 | 0x16C93704, 32 | 0x16EC5B7C, 33 | 0x18C65756, 34 | 0x19A0C1B6, 35 | 0x1B74CB89, 36 | 0x1CAF805D, 37 | 0x1D17DECF, 38 | 0x200CC503, 39 | 0x20AF286A, 40 | 0x212E6C35, 41 | 0x215FD24D, 42 | 0x21716C81, 43 | 0x21C7913E, 44 | 0x22605E63, 45 | 0x2682E6ED, 46 | 0x27DD11EA, 47 | 0x27EE191B, 48 | 0x29483405, 49 | 0x2AAC8BFD, 50 | 0x2ABC41DF, 51 | 0x2B751F95, 52 | 0x370E147B, 53 | 0x377094D5, 54 | 0x38AA5E8E, 55 | 0x39364623, 56 | 0x394BCCF2, 57 | 0x3C00071F, 58 | 0x3DD9E4AB, 59 | 0x3E49D3F1, 60 | 0x3F42E175, 61 | 0x401E0C68, 62 | 0x438917E4, 63 | 0x452B0AB3, 64 | 0x45389B6B, 65 | 0x4B7F47DC, 66 | 0x4BB3154A, 67 | 0x4DBF648E, 68 | 0x4DF8B624, 69 | 0x4E0EA70D, 70 | 0x50407BF4, 71 | 0x52DD3322, 72 | 0x5B5650C7, 73 | 0x5B746A69, 74 | 0x5D06FF09, 75 | 0x5D86D763, 76 | 0x5E65E454, 77 | 0x5E7876F2, 78 | 0x5E93840E, 79 | 0x650CE348, 80 | 0x667A4649, 81 | 0x67FDA21B, 82 | 0x68D0FA79, 83 | 0x6B9711AC, 84 | 0x6C79F2F2, 85 | 0x6F1A4A2E, 86 | 0x6F2C41BA, 87 | 0x6F7C4DE6, 88 | 0x70358258, 89 | 0x7192B01C, 90 | 0x72DBB96B, 91 | 0x75FCF058, 92 | 0x79889DAC, 93 | 0x79BA0A6D, 94 | 0x7AE31060, 95 | 0x7D16FB3B, 96 | 0x7D483C33, 97 | 0x7EB9E8B5, 98 | 0x7FA945AD, 99 | 0x800BB137, 100 | 0x80191FAA, 101 | 0x80544E0C, 102 | 0x855F49D5, 103 | 0x8564E008, 104 | 0x865DA482, 105 | 0x86761234, 106 | 0x8CE3AFC7, 107 | 0x8E68E870, 108 | 0x8E9A0400, 109 | 0x91262C5F, 110 | 0x921A043D, 111 | 0x92667AE5, 112 | 0x940B9EBE, 113 | 0x9A92C33F, 114 | 0x9AA387DF, 115 | 0x9AC39954, 116 | 0x9B1922F2, 117 | 0x9C187FAD, 118 | 0x9C572180, 119 | 0x9C921F8D, 120 | 0x9D291788, 121 | 0x9DCB4B7A, 122 | 0xAA888831, 123 | 0xAC7FE4F3, 124 | 0xB1877F5E, 125 | 0xB373D8A1, 126 | 0xB3D600AB, 127 | 0xB5EC061A, 128 | 0xB6D50FCC, 129 | 0xB70EBAE9, 130 | 0xB8F165B4, 131 | 0xB96FED7D, 132 | 0xBACA6891, 133 | 0xBCFB867F, 134 | 0xC0FAF6A3, 135 | 0xC21FC992, 136 | 0xC239DBCC, 137 | 0xC30B1745, 138 | 0xC37F6983, 139 | 0xC3ED6E4A, 140 | 0xC6FFE335, 141 | 0xC7FB5497, 142 | 0xC96F4269, 143 | 0xCC14FA59, 144 | 0xCE769C83, 145 | 0xCEA3FC52, 146 | 0xD004EA15, 147 | 0xD3210C08, 148 | 0xD38231C9, 149 | 0xD4785C41, 150 | 0xD99F51D3, 151 | 0xD9E78D30, 152 | 0xDAB1B1C8, 153 | 0xDB9F5333, 154 | 0xDBD09B09, 155 | 0xDFCEE5AB, 156 | 0xE0A6D759, 157 | 0xE2C0BFEF, 158 | 0xE326EA7A, 159 | 0xE61C2B06, 160 | 0xE8C03447, 161 | 0xE8CC3DF0, 162 | 0xEA5C52F5, 163 | 0xEB9054B2, 164 | 0xF0526CE2, 165 | 0xF6A0FE84, 166 | 0xF6CFB4F1, 167 | 0xF6D515DC, 168 | 0xF7413EC7, 169 | 0xF76F3056, 170 | 0xF8E06784, 171 | 0xFA3D4491, 172 | 0xFA64FB37, 173 | 0xFB66565E, 174 | 0xFCE2F728, 175 | 0xFEC9E946, 176 | 0xFF738CD9, 177 | // SceModulemgr 178 | 0x1FD99C9F, 179 | 0x2EF2581F, 180 | 0x36585DAF, 181 | 0x5303C52F, 182 | 0x9C2A9A49, 183 | 0x9D2FE122, 184 | 0xA4E6DA4D, 185 | 0xBA49EA5C, 186 | 0xE439E26B, 187 | 0xF5798C7C, 188 | // SceProcessmgr 189 | 0x2BE3E066, 190 | 0x2F73D72F, 191 | 0x56C2E8FF, 192 | 0x89DA0967, 193 | 0xC053DC6B, 194 | 0xD37A8437, 195 | 0xF5D0D4C6, 196 | // SceIofilemgr 197 | 0xB13031, 198 | 0x9CD0FC8, 199 | 0x13DC3244, 200 | 0x1D2988F1, 201 | 0x2300858E, 202 | 0x34E6A06E, 203 | 0x36CAF911, 204 | 0x38FE853B, 205 | 0x3EE3F66E, 206 | 0x4912F748, 207 | 0x515AC017, 208 | 0x539FD5C4, 209 | 0x554292F0, 210 | 0x58010F40, 211 | 0x5DC29460, 212 | 0x5DD867F7, 213 | 0x5FFA47E2, 214 | 0x64B233B8, 215 | 0x654E27B1, 216 | 0x6F78FAFE, 217 | 0x70B7BB52, 218 | 0x78955C65, 219 | 0x81794921, 220 | 0x86DB0C0E, 221 | 0x8713D662, 222 | 0x8C319CF0, 223 | 0x8E7E11F2, 224 | 0x8F1ACC32, 225 | 0x9111D004, 226 | 0x92BDA6DA, 227 | 0x9654094B, 228 | 0x9E3F880D, 229 | 0xA604764A, 230 | 0xB0486482, 231 | 0xB14192F0, 232 | 0xB2B891E6, 233 | 0xB2D0B2F4, 234 | 0xB4B021D9, 235 | 0xBCF5684D, 236 | 0xC92AF88F, 237 | 0xCC67B6FD, 238 | 0xD2EE455F, 239 | 0xD302DCB9, 240 | 0xD414C89F, 241 | 0xE00DC256, 242 | 0xE0BE2A30, 243 | 0xE6C53567, 244 | 0xE6C923B3, 245 | 0xE6E614B5, 246 | 0xF3C9E783, 247 | 0xF437545D, 248 | 0xF4E13260, 249 | 0xF58286C3, 250 | 0xF5C58B21, 251 | 0xF5DEEA19, 252 | 0xF69FB394, 253 | 0xFAFF0002, 254 | 0xFFFB4D76 255 | }; 256 | -------------------------------------------------------------------------------- /nidcache-3xx.h: -------------------------------------------------------------------------------- 1 | const nid_cache_db libkernel_nid_cache_header[] = { 2 | {0x37FE725A, 4}, // SceSysmem 3 | {0x859A24B1, 98}, // SceThreadmgr 4 | {0xEAED1616, 12}, // SceModulemgr 5 | {0x2DD91812, 8}, // SceProcessmgr 6 | {0xF2FF276E, 34}, // SceIofilemgr 7 | {0, 0} 8 | }; 9 | 10 | const u32_t libkernel_nid_cache[] = { 11 | // SceSysmem 12 | 0xA33B99D1, 13 | 0xA91E15EE, 14 | 0xB8EF5818, 15 | 0xB9D5EBDE, 16 | // SceThreadmgr 17 | 0x3CFCF00, 18 | 0x402C633, 19 | 0x40795C7, 20 | 0x558B7C1, 21 | 0x5C51CE1, 22 | 0x7D2584A, 23 | 0xD76458E, 24 | 0x106C216F, 25 | 0x118F646E, 26 | 0x13117B21, 27 | 0x18C65756, 28 | 0x1B74CB89, 29 | 0x1BBDE3D9, 30 | 0x1CAF805D, 31 | 0x1D17DECF, 32 | 0x1FF5960D, 33 | 0x200CC503, 34 | 0x212E6C35, 35 | 0x215FD24D, 36 | 0x21C7913E, 37 | 0x2682E6ED, 38 | 0x29483405, 39 | 0x2AAC8BFD, 40 | 0x2ABC41DF, 41 | 0x377094D5, 42 | 0x38AA5E8E, 43 | 0x3DD9E4AB, 44 | 0x3E49D3F1, 45 | 0x401E0C68, 46 | 0x452B0AB3, 47 | 0x45389B6B, 48 | 0x4BB3154A, 49 | 0x4DBF648E, 50 | 0x4E0EA70D, 51 | 0x50407BF4, 52 | 0x5D86D763, 53 | 0x5DE0B7E9, 54 | 0x5E65E454, 55 | 0x5E7876F2, 56 | 0x6B9711AC, 57 | 0x6C79F2F2, 58 | 0x6F1A4A2E, 59 | 0x6F2C41BA, 60 | 0x6F7C4DE6, 61 | 0x70358258, 62 | 0x72DBB96B, 63 | 0x75FCF058, 64 | 0x79BA0A6D, 65 | 0x7AE31060, 66 | 0x7D483C33, 67 | 0x7EB55DAC, 68 | 0x7EB9E8B5, 69 | 0x7FA945AD, 70 | 0x80191FAA, 71 | 0x80544E0C, 72 | 0x865DA482, 73 | 0x86761234, 74 | 0x8CE3AFC7, 75 | 0x8E68E870, 76 | 0x91262C5F, 77 | 0x92667AE5, 78 | 0x940B9EBE, 79 | 0x9C187FAD, 80 | 0x9C572180, 81 | 0x9DCB4B7A, 82 | 0xAC7FE4F3, 83 | 0xB1877F5E, 84 | 0xB373D8A1, 85 | 0xB3D600AB, 86 | 0xB70EBAE9, 87 | 0xBACA6891, 88 | 0xBD06F27C, 89 | 0xC0FAF6A3, 90 | 0xC30B1745, 91 | 0xC37F6983, 92 | 0xC7FB5497, 93 | 0xCC14FA59, 94 | 0xCE6B49D8, 95 | 0xCE769C83, 96 | 0xCEA3FC52, 97 | 0xD004EA15, 98 | 0xD3210C08, 99 | 0xD4785C41, 100 | 0xD9E78D30, 101 | 0xDAB1B1C8, 102 | 0xDB9F5333, 103 | 0xDBD09B09, 104 | 0xE2C0BFEF, 105 | 0xE8CC3DF0, 106 | 0xEA5C52F5, 107 | 0xF5F81792, 108 | 0xF6D515DC, 109 | 0xF76F3056, 110 | 0xF8E06784, 111 | 0xFA3D4491, 112 | 0xFCE2F728, 113 | 0xFEC9E946, 114 | 0xFF738CD9, 115 | // SceModulemgr 116 | 0, 117 | 0x2EF2581F, 118 | 0x36585DAF, 119 | 0, 120 | 0, 121 | 0x5303C52F, 122 | 0, 123 | 0, 124 | 0x9C2A9A49, 125 | 0, 126 | 0xEAEB1312, 127 | 0xF5798C7C, 128 | // SceProcessmgr 129 | 0x2BE3E066, 130 | 0x2F73D72F, 131 | 0x56C2E8FF, 132 | 0x89DA0967, 133 | 0xC053DC6B, 134 | 0xD37A8437, 135 | 0xE5AA625C, 136 | 0xF5D0D4C6, 137 | // SceIofilemgr 138 | 0x9CD0FC8, 139 | 0x13DC3244, 140 | 0x1D2988F1, 141 | 0x2300858E, 142 | 0x34EFD876, 143 | 0x3EE3F66E, 144 | 0x4912F748, 145 | 0x515AC017, 146 | 0x539FD5C4, 147 | 0x5DD867F7, 148 | 0x5FFA47E2, 149 | 0x78955C65, 150 | 0x81794921, 151 | 0x86DB0C0E, 152 | 0x8713D662, 153 | 0x8E7E11F2, 154 | 0x8F1ACC32, 155 | 0x9111D004, 156 | 0x9654094B, 157 | 0xA604764A, 158 | 0xB2D0B2F4, 159 | 0xB4B021D9, 160 | 0xBCF5684D, 161 | 0xC70B8886, 162 | 0xCC67B6FD, 163 | 0xD2EE455F, 164 | 0xD414C89F, 165 | 0xE00DC256, 166 | 0xE0BE2A30, 167 | 0xE6C53567, 168 | 0xE6E614B5, 169 | 0xF5C58B21, 170 | 0xFDB32293, 171 | 0xFFFB4D76 172 | }; 173 | -------------------------------------------------------------------------------- /nidcache.h: -------------------------------------------------------------------------------- 1 | #ifndef UVL_NIDCACHE 2 | #define UVL_NIDCACHE 3 | 4 | #include "types.h" 5 | 6 | typedef struct { 7 | u32_t module_nid; 8 | u32_t entries; 9 | } nid_cache_db; 10 | 11 | #if defined(FW_3XX) 12 | #include "nidcache-3xx.h" 13 | #elif defined(FW_169) 14 | #include "nidcache-169.h" 15 | #else 16 | #warning "No FW version specified, NID caching disabled" 17 | const nid_cache_db libkernel_nid_cache_header[] = { {0, 0} }; 18 | const u32_t libkernel_nid_cache[0]; 19 | #endif 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /relocate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * relocate.c - Performs SCE ELF relocations 3 | * Copyright 2015 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "load.h" 18 | #include "relocate.h" 19 | #include "scefuncs.h" 20 | #include "utils.h" 21 | #include "uvloader.h" 22 | 23 | /********************************************//** 24 | * \brief Write to loaded segment at offset 25 | * 26 | * \returns Zero on success, otherwise error 27 | ***********************************************/ 28 | int 29 | uvl_segment_write (Elf32_Phdr_t *seg, ///< Where to write 30 | u32_t offset, ///< Offset to write to 31 | void *value, ///< What to write 32 | u32_t size) ///< How much 33 | { 34 | if (offset+size > seg->p_filesz) // don't overflow me plz 35 | { 36 | LOG ("Relocation overflows segment"); 37 | return -1; 38 | } 39 | if (seg->p_flags & PF_X) 40 | { 41 | uvl_unlock_mem (); 42 | } 43 | memcpy ((char *)seg->p_vaddr + offset, value, size); 44 | if (seg->p_flags & PF_X) 45 | { 46 | uvl_lock_mem (); 47 | } 48 | return 0; 49 | } 50 | 51 | /********************************************//** 52 | * \brief Perform SCE relocation 53 | * 54 | * \returns Zero on success, otherwise error 55 | ***********************************************/ 56 | int 57 | uvl_relocate (void *reloc, ///< Base address of relocation segment 58 | u32_t size, ///< Size of relocation segment 59 | Elf32_Phdr_t *segs) ///< All segments loaded 60 | { 61 | sce_reloc_t *entry; 62 | u32_t pos; 63 | u16_t r_code; 64 | u32_t r_offset; 65 | u32_t r_addend; 66 | u8_t r_symseg; 67 | u8_t r_datseg; 68 | s32_t offset; 69 | u32_t symval, addend, loc; 70 | u32_t upper, lower, sign, j1, j2; 71 | u32_t value; 72 | 73 | pos = 0; 74 | while (pos < size) 75 | { 76 | // get entry 77 | entry = (sce_reloc_t *)((char *)reloc + pos); 78 | if (SCE_RELOC_IS_SHORT (*entry)) 79 | { 80 | r_offset = SCE_RELOC_SHORT_OFFSET (entry->r_short); 81 | r_addend = SCE_RELOC_SHORT_ADDEND (entry->r_short); 82 | pos += 8; 83 | } 84 | else 85 | { 86 | r_offset = SCE_RELOC_LONG_OFFSET (entry->r_long); 87 | r_addend = SCE_RELOC_LONG_ADDEND (entry->r_long); 88 | if (SCE_RELOC_LONG_CODE2 (entry->r_long)) 89 | { 90 | IF_VERBOSE LOG ("Code2 ignored for relocation at %X.", pos); 91 | } 92 | pos += 12; 93 | } 94 | 95 | // get values 96 | r_symseg = SCE_RELOC_SYMSEG (*entry); 97 | r_datseg = SCE_RELOC_DATSEG (*entry); 98 | symval = r_symseg == 15 ? 0 : (u32_t)segs[r_symseg].p_vaddr; 99 | loc = (u32_t)segs[r_datseg].p_vaddr + r_offset; 100 | 101 | // perform relocation 102 | // taken from linux/arch/arm/kernel/module.c of Linux Kernel 4.0 103 | switch (SCE_RELOC_CODE (*entry)) 104 | { 105 | case R_ARM_V4BX: 106 | { 107 | /* Preserve Rm and the condition code. Alter 108 | * other bits to re-code instruction as 109 | * MOV PC,Rm. 110 | */ 111 | value = (*(u32_t *)loc & 0xf000000f) | 0x01a0f000; 112 | } 113 | break; 114 | case R_ARM_ABS32: 115 | case R_ARM_TARGET1: 116 | { 117 | value = r_addend + symval; 118 | } 119 | break; 120 | case R_ARM_REL32: 121 | case R_ARM_TARGET2: 122 | { 123 | value = r_addend + symval - loc; 124 | } 125 | break; 126 | case R_ARM_THM_CALL: 127 | { 128 | upper = *(u16_t *)loc; 129 | lower = *(u16_t *)(loc + 2); 130 | 131 | /* 132 | * 25 bit signed address range (Thumb-2 BL and B.W 133 | * instructions): 134 | * S:I1:I2:imm10:imm11:0 135 | * where: 136 | * S = upper[10] = offset[24] 137 | * I1 = ~(J1 ^ S) = offset[23] 138 | * I2 = ~(J2 ^ S) = offset[22] 139 | * imm10 = upper[9:0] = offset[21:12] 140 | * imm11 = lower[10:0] = offset[11:1] 141 | * J1 = lower[13] 142 | * J2 = lower[11] 143 | */ 144 | sign = (upper >> 10) & 1; 145 | j1 = (lower >> 13) & 1; 146 | j2 = (lower >> 11) & 1; 147 | offset = r_addend + symval - loc; 148 | 149 | if (offset <= (s32_t)0xff000000 || 150 | offset >= (s32_t)0x01000000) { 151 | LOG ("reloc %x out of range: 0x%08X", pos, symval); 152 | break; 153 | } 154 | 155 | sign = (offset >> 24) & 1; 156 | j1 = sign ^ (~(offset >> 23) & 1); 157 | j2 = sign ^ (~(offset >> 22) & 1); 158 | upper = (u16_t)((upper & 0xf800) | (sign << 10) | 159 | ((offset >> 12) & 0x03ff)); 160 | lower = (u16_t)((lower & 0xd000) | 161 | (j1 << 13) | (j2 << 11) | 162 | ((offset >> 1) & 0x07ff)); 163 | 164 | value = ((u32_t)lower << 16) | upper; 165 | } 166 | break; 167 | case R_ARM_CALL: 168 | case R_ARM_JUMP24: 169 | { 170 | offset = r_addend + symval - loc; 171 | if (offset <= (s32_t)0xfe000000 || 172 | offset >= (s32_t)0x02000000) { 173 | LOG ("reloc %x out of range: 0x%08X", pos, symval); 174 | break; 175 | } 176 | 177 | offset >>= 2; 178 | offset &= 0x00ffffff; 179 | 180 | value = (*(u32_t *)loc & 0xff000000) | offset; 181 | } 182 | break; 183 | case R_ARM_PREL31: 184 | { 185 | offset = r_addend + symval - loc; 186 | value = offset & 0x7fffffff; 187 | } 188 | break; 189 | case R_ARM_MOVW_ABS_NC: 190 | case R_ARM_MOVT_ABS: 191 | { 192 | offset = symval + r_addend; 193 | if (SCE_RELOC_CODE (*entry) == R_ARM_MOVT_ABS) 194 | offset >>= 16; 195 | 196 | value = *(u32_t *)loc; 197 | value &= 0xfff0f000; 198 | value |= ((offset & 0xf000) << 4) | 199 | (offset & 0x0fff); 200 | } 201 | break; 202 | case R_ARM_THM_MOVW_ABS_NC: 203 | case R_ARM_THM_MOVT_ABS: 204 | { 205 | upper = *(u16_t *)loc; 206 | lower = *(u16_t *)(loc + 2); 207 | 208 | /* 209 | * MOVT/MOVW instructions encoding in Thumb-2: 210 | * 211 | * i = upper[10] 212 | * imm4 = upper[3:0] 213 | * imm3 = lower[14:12] 214 | * imm8 = lower[7:0] 215 | * 216 | * imm16 = imm4:i:imm3:imm8 217 | */ 218 | offset = r_addend + symval; 219 | 220 | if (SCE_RELOC_CODE (*entry) == R_ARM_THM_MOVT_ABS) 221 | offset >>= 16; 222 | 223 | upper = (u16_t)((upper & 0xfbf0) | 224 | ((offset & 0xf000) >> 12) | 225 | ((offset & 0x0800) >> 1)); 226 | lower = (u16_t)((lower & 0x8f00) | 227 | ((offset & 0x0700) << 4) | 228 | (offset & 0x00ff)); 229 | 230 | value = ((u32_t)lower << 16) | upper; 231 | } 232 | break; 233 | default: 234 | { 235 | LOG ("Unknown relocation code %u at %x", r_code, pos); 236 | } 237 | case R_ARM_NONE: 238 | continue; 239 | } 240 | 241 | // write value 242 | uvl_segment_write (&segs[r_datseg], r_offset, &value, sizeof (value)); 243 | } 244 | 245 | return 0; 246 | } 247 | -------------------------------------------------------------------------------- /relocate.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file relocate.h 3 | /// \brief Performs SCE ELF relocations 4 | /// \defgroup load Executable Loader 5 | /// \brief Relocates ELFs 6 | /// @{ 7 | /// 8 | #ifndef UVL_RELOCATE 9 | #define UVL_RELOCATE 10 | 11 | #include "types.h" 12 | 13 | /** \name SCE Relocation 14 | * @{ 15 | */ 16 | typedef union sce_reloc 17 | { 18 | u32_t r_type; 19 | struct 20 | { 21 | u32_t r_opt1; 22 | u32_t r_opt2; 23 | } r_short; 24 | struct 25 | { 26 | u32_t r_type; 27 | u32_t r_addend; 28 | u32_t r_offset; 29 | } r_long; 30 | } sce_reloc_t; 31 | /** @}*/ 32 | 33 | /** \name Macros to get SCE reloc values 34 | * @{ 35 | */ 36 | #define SCE_RELOC_SHORT_OFFSET(x) (((x).r_opt1 >> 20) | ((x).r_opt2 & 0x3FF) << 12) 37 | #define SCE_RELOC_SHORT_ADDEND(x) ((x).r_opt2 >> 10) 38 | #define SCE_RELOC_LONG_OFFSET(x) ((x).r_offset) 39 | #define SCE_RELOC_LONG_ADDEND(x) ((x).r_addend) 40 | #define SCE_RELOC_LONG_CODE2(x) (((x).r_type >> 20) & 0xFF) 41 | #define SCE_RELOC_LONG_DIST2(x) (((x).r_type >> 28) & 0xF) 42 | #define SCE_RELOC_IS_SHORT(x) (((x).r_type) & 0xF) 43 | #define SCE_RELOC_CODE(x) (((x).r_type >> 8) & 0xFF) 44 | #define SCE_RELOC_SYMSEG(x) (((x).r_type >> 4) & 0xF) 45 | #define SCE_RELOC_DATSEG(x) (((x).r_type >> 16) & 0xF) 46 | /** @}*/ 47 | 48 | /** \name Vita supported relocations 49 | * @{ 50 | */ 51 | #define R_ARM_NONE 0 52 | #define R_ARM_ABS32 2 53 | #define R_ARM_REL32 3 54 | #define R_ARM_THM_CALL 10 55 | #define R_ARM_CALL 28 56 | #define R_ARM_JUMP24 29 57 | #define R_ARM_TARGET1 38 58 | #define R_ARM_V4BX 40 59 | #define R_ARM_TARGET2 41 60 | #define R_ARM_PREL31 42 61 | #define R_ARM_MOVW_ABS_NC 43 62 | #define R_ARM_MOVT_ABS 44 63 | #define R_ARM_THM_MOVW_ABS_NC 47 64 | #define R_ARM_THM_MOVT_ABS 48 65 | /** @}*/ 66 | 67 | /** \cond predefined-types 68 | * @{ 69 | */ 70 | typedef struct Elf32_Phdr Elf32_Phdr_t; 71 | /** @}*/ 72 | 73 | /** \name Relocation functions 74 | * @{ 75 | */ 76 | int uvl_segment_write (Elf32_Phdr_t *seg, u32_t offset, void *value, u32_t size); 77 | int uvl_relocate (void *reloc, u32_t size, Elf32_Phdr_t *segs); 78 | /** @}*/ 79 | 80 | #endif 81 | /// @} 82 | -------------------------------------------------------------------------------- /resolve.c: -------------------------------------------------------------------------------- 1 | /* 2 | * resolve.c - Resolves NIDs for dynamic linking 3 | * Copyright 2012 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "nidcache.h" 18 | #include "load.h" 19 | #include "resolve.h" 20 | #include "scefuncs.h" 21 | #include "utils.h" 22 | #include "uvloader.h" 23 | 24 | /** Checks if a bit is set in a given member */ 25 | #define BIT_SET(i, b) (i & (0x1 << b)) 26 | 27 | static u32_t sceSysmoduleLoadModule_stub[3]; 28 | static int (* sceSysmoduleLoadModule)(u16_t id); 29 | 30 | /** Remember SceLibKernel NID so we can resolve with caching */ 31 | int g_libkenel_nid = 0; 32 | 33 | /** Stores resolve entries */ 34 | struct resolve_table { 35 | PsvUID block_uid; ///< UID of the memory block for freeing 36 | u32_t length; ///< Number of entries 37 | resolve_entry_t table[]; ///< Table entries 38 | } *g_resolve_table = NULL; 39 | 40 | /********************************************//** 41 | * \brief Allocates memory for resolve table. 42 | * 43 | * \returns Zero on success, otherwise error 44 | ***********************************************/ 45 | int 46 | uvl_resolve_table_initialize () 47 | { 48 | u32_t size; 49 | PsvUID block; 50 | void *base; 51 | 52 | size = (MAX_RESOLVE_ENTRIES * sizeof (resolve_entry_t) + sizeof (u32_t) + sizeof (PsvUID) + 0xFFF) & ~0xFFF; // store block id, counter, table, and align to 0x1000 bytes 53 | IF_DEBUG LOG ("Creating resolve table of size %u.", size); 54 | block = sceKernelAllocMemBlock ("UVLTable", 0xC20D060, size, NULL); 55 | if (block < 0) 56 | { 57 | LOG ("Error allocating resolve table. 0x%08X", block); 58 | return -1; 59 | } 60 | if (sceKernelGetMemBlockBase (block, &base) < 0) 61 | { 62 | LOG ("Error getting block base."); 63 | return -1; 64 | } 65 | IF_DEBUG LOG ("Block UID 0x%08X allocated at 0x%08X", (u32_t)block, (u32_t)base); 66 | uvl_unlock_mem (); 67 | g_resolve_table = base; 68 | uvl_lock_mem (); 69 | g_resolve_table->block_uid = block; 70 | g_resolve_table->length = 0; 71 | return 0; 72 | } 73 | 74 | /********************************************//** 75 | * \brief Frees memory for resolve table. 76 | * 77 | * \returns Zero on success, otherwise error 78 | ***********************************************/ 79 | int 80 | uvl_resolve_table_destroy () 81 | { 82 | PsvUID block; 83 | 84 | if (g_resolve_table == NULL) 85 | { 86 | IF_DEBUG LOG ("Resolve table not initialized."); 87 | return 0; 88 | } 89 | if (sceKernelFreeMemBlock (g_resolve_table->block_uid) < 0) 90 | { 91 | LOG ("Error freeing resolve table."); 92 | return -1; 93 | } 94 | uvl_unlock_mem (); 95 | g_resolve_table = NULL; 96 | uvl_lock_mem (); 97 | return 0; 98 | } 99 | 100 | /********************************************//** 101 | * \brief Adds a resolve entry 102 | * 103 | * This function does not check for duplicates. 104 | * \returns Zero on success, otherwise error 105 | ***********************************************/ 106 | int 107 | uvl_resolve_table_add (resolve_entry_t *entry) ///< Entry to add 108 | { 109 | if (g_resolve_table->length >= MAX_RESOLVE_ENTRIES) 110 | { 111 | LOG ("Resolve table full. Please recompile with larger table."); 112 | return -1; 113 | } 114 | IF_VERBOSE LOG ("Adding entry #%u to resolve table.", g_resolve_table->length); 115 | IF_VERBOSE LOG ("NID: 0x%08X, type: %u, value 0x%08X", entry->nid, entry->type, entry->value.value); 116 | memcpy (&g_resolve_table->table[g_resolve_table->length], entry, sizeof (resolve_entry_t)); 117 | g_resolve_table->length++; 118 | return 0; 119 | } 120 | 121 | /********************************************//** 122 | * \brief Gets a resolve entry 123 | * 124 | * This function returns the last entry in the 125 | * table that has the given NID. 126 | * \returns Entry on success, NULL on error 127 | ***********************************************/ 128 | resolve_entry_t * 129 | uvl_resolve_table_get (u32_t nid) ///< NID to resolve 130 | { 131 | int i; 132 | for (i = g_resolve_table->length - 1; i >= 0; i--) 133 | { 134 | if (g_resolve_table->table[i].nid == nid) 135 | { 136 | return &g_resolve_table->table[i]; 137 | } 138 | } 139 | return NULL; 140 | } 141 | 142 | /********************************************//** 143 | * \brief Use import NID cache if available 144 | * 145 | * \returns Pointer to NID table 146 | ***********************************************/ 147 | static const u32_t * 148 | uvl_get_import_fnid_cache (module_info_t *mod_info, ///< Module containing import 149 | module_imports_t *imports) ///< Import table to read 150 | { 151 | int off; 152 | const nid_cache_db *header; 153 | const u32_t *func_nid_table; 154 | 155 | func_nid_table = NULL; 156 | if (mod_info->module_nid == g_libkenel_nid) // SceLibKernel 157 | { 158 | off = 0; 159 | for (header = &libkernel_nid_cache_header[0]; header->module_nid; header++) 160 | { 161 | if (header->module_nid == IMP_GET_NID (imports)) 162 | { 163 | if (header->entries != IMP_GET_FUNC_COUNT (imports)) 164 | { 165 | LOG ("Warning: Import for %s in %s has %u entries but only %u cached.", 166 | IMP_GET_NAME (imports), mod_info->modname, 167 | IMP_GET_FUNC_COUNT (imports), header->entries); 168 | } 169 | else 170 | { 171 | IF_VERBOSE LOG ("Using NID cache for %s -> %s", IMP_GET_NAME (imports), mod_info->modname); 172 | } 173 | func_nid_table = &libkernel_nid_cache[off]; 174 | break; 175 | } 176 | off += header->entries; 177 | } 178 | } 179 | if (!func_nid_table) 180 | { 181 | func_nid_table = IMP_GET_FUNC_TABLE (imports); 182 | } 183 | 184 | return func_nid_table; 185 | } 186 | 187 | /********************************************//** 188 | * \brief Creates resolve entry from stub 189 | * function imported by a module 190 | * 191 | * Given the stub function of a loaded module 192 | * that has already been resolved, extract 193 | * the resolved information and write it to 194 | * a @c resolve_entry_t. 195 | * \returns Zero on success, otherwise error 196 | ***********************************************/ 197 | int 198 | uvl_resolve_import_stub_to_entry (void *stub, ///< Stub function to read 199 | u32_t nid, ///< NID resolved by stub 200 | resolve_entry_t *entry) ///< Entry to write to 201 | { 202 | u32_t val = 0; 203 | u8_t inst_type = 0; 204 | int read = 0; 205 | entry->type = RESOLVE_TYPE_UNKNOWN; 206 | entry->value.value = 0; 207 | for (;;) 208 | { 209 | val = uvl_decode_arm_inst (*(u32_t*)stub, &inst_type); 210 | switch (inst_type) 211 | { 212 | case INSTRUCTION_MOVW: 213 | entry->value.value = val; 214 | break; 215 | case INSTRUCTION_MOVT: 216 | entry->value.value |= val << 16; // load upper 217 | break; 218 | case INSTRUCTION_SYSCALL: 219 | entry->type = RESOLVE_TYPE_SYSCALL; // value's meaning changed to syscall 220 | break; 221 | case INSTRUCTION_BRANCH: 222 | entry->type = RESOLVE_TYPE_FUNCTION; // value's meaning changed to function ptr 223 | break; 224 | case INSTRUCTION_ADR: 225 | entry->type = RESOLVE_TYPE_RELATIVE; 226 | entry->value.value = 0; 227 | break; // TODO: Support this kind of relocation 228 | case INSTRUCTION_MVN: 229 | entry->type = RESOLVE_TYPE_UNRESOLVED; 230 | entry->value.value = 0; 231 | break; 232 | case INSTRUCTION_UNKNOWN: // we should have already breaked! 233 | default: 234 | IF_DEBUG LOG ("Invalid instruction: 0x%08X found at 0x%08X for NID 0x%08X", *(u32_t*)stub, (u32_t)stub, nid); 235 | return -1; 236 | } 237 | if (entry->type != RESOLVE_TYPE_UNKNOWN) 238 | { 239 | break; 240 | } 241 | // next instruction 242 | stub = (char*)stub + sizeof (u32_t); 243 | } 244 | if (entry->value.value == 0) // false alarm 245 | { 246 | IF_VERBOSE LOG ("Stub 0x%08X has not been resolved yet. Skipping.", (u32_t)stub); 247 | return 0; 248 | } 249 | // put the finishing touches 250 | entry->nid = nid; 251 | IF_VERBOSE LOG ("Mapped resolved import NID: 0x%X to 0x%X of type %u.", entry->nid, entry->value.value, entry->type); 252 | return 0; 253 | } 254 | 255 | int 256 | sceSysmoduleLoadModulePatched(u16_t id) 257 | { 258 | PsvUID mod_list_old[MAX_LOADED_MODS]; 259 | u32_t num_loaded_old = MAX_LOADED_MODS; 260 | 261 | PsvUID mod_list_new[MAX_LOADED_MODS]; 262 | u32_t num_loaded_new = MAX_LOADED_MODS; 263 | 264 | sceKernelGetModuleList(0xFF, mod_list_old, &num_loaded_old); 265 | 266 | int res = sceSysmoduleLoadModule(id); 267 | if (res == 0) 268 | { 269 | if (sceKernelGetModuleList(0xFF, mod_list_new, &num_loaded_new) >= 0) 270 | { 271 | int i; 272 | for (i = 0; i < (num_loaded_new - num_loaded_old); i++) 273 | { 274 | uvl_resolve_add_module (mod_list_new[i], RESOLVE_MOD_EXPS); 275 | 276 | loaded_module_info_t m_mod_info; 277 | module_info_t *mod_info; 278 | module_exports_t *exports; 279 | 280 | m_mod_info.size = sizeof (loaded_module_info_t); // should be 440 281 | if (sceKernelGetModuleInfo (mod_list_new[i], &m_mod_info) < 0) 282 | { 283 | continue; 284 | } 285 | if ((mod_info = uvl_find_module_info (&m_mod_info)) == NULL) 286 | { 287 | continue; 288 | } 289 | for (exports = (module_exports_t*)((u32_t)m_mod_info.segments[0].vaddr + mod_info->ent_top); 290 | (u32_t)exports < ((u32_t)m_mod_info.segments[0].vaddr + mod_info->ent_end); exports++) 291 | { 292 | if (exports->lib_name != NULL) 293 | { 294 | uvl_resolve_import_by_name(exports->lib_name); 295 | } 296 | } 297 | } 298 | } 299 | } 300 | return res; 301 | } 302 | 303 | /********************************************//** 304 | * \brief Fills a stub with resolve entry 305 | * 306 | * \returns Zero on success, otherwise error 307 | ***********************************************/ 308 | int 309 | uvl_resolve_entry_to_import_stub (resolve_entry_t *entry, ///< Entry to read from 310 | void *stub) ///< Stub function to fill 311 | { 312 | u32_t *memloc = stub; 313 | switch (entry->type) 314 | { 315 | case RESOLVE_TYPE_FUNCTION: 316 | uvl_unlock_mem (); 317 | memloc[0] = uvl_encode_arm_inst (INSTRUCTION_MOVW, (u16_t)entry->value.value, 12); 318 | memloc[1] = uvl_encode_arm_inst (INSTRUCTION_MOVT, (u16_t)(entry->value.value >> 16), 12); 319 | memloc[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 12); 320 | uvl_lock_mem (); 321 | break; 322 | case RESOLVE_TYPE_SYSCALL: 323 | uvl_unlock_mem (); 324 | memloc[0] = uvl_encode_arm_inst (INSTRUCTION_MOVW, (u16_t)entry->value.value, 12); 325 | memloc[1] = uvl_encode_arm_inst (INSTRUCTION_SYSCALL, 0, 0); 326 | memloc[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 14); 327 | uvl_lock_mem (); 328 | 329 | if (entry->nid == 0x79a0160a) 330 | { 331 | u32_t value = (u32_t)sceSysmoduleLoadModulePatched; 332 | 333 | uvl_unlock_mem (); 334 | 335 | sceSysmoduleLoadModule_stub[0] = uvl_encode_arm_inst (INSTRUCTION_MOVW, (u16_t)entry->value.value, 12); 336 | sceSysmoduleLoadModule_stub[1] = uvl_encode_arm_inst (INSTRUCTION_SYSCALL, 0, 0); 337 | sceSysmoduleLoadModule_stub[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 14); 338 | sceSysmoduleLoadModule = (void *)sceSysmoduleLoadModule_stub; 339 | 340 | memloc[0] = uvl_encode_arm_inst (INSTRUCTION_MOVW, (u16_t)value, 12); 341 | memloc[1] = uvl_encode_arm_inst (INSTRUCTION_MOVT, (u16_t)(value >> 16), 12); 342 | memloc[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 12); 343 | 344 | uvl_lock_mem (); 345 | } 346 | 347 | break; 348 | case RESOLVE_TYPE_VARIABLE: 349 | uvl_unlock_mem (); 350 | memloc[0] = entry->value.value; 351 | uvl_lock_mem (); 352 | break; 353 | case RESOLVE_TYPE_UNKNOWN: 354 | default: 355 | LOG ("Invalid resolve entry 0x%08X", (u32_t)entry); 356 | return -1; 357 | } 358 | uvl_flush_icache (memloc, STUB_FUNC_SIZE); 359 | IF_VERBOSE LOG ("Resolved NID 0x%08X to 0x%08X of type %u", entry->nid, entry->value.value, entry->type); 360 | return 0; 361 | } 362 | 363 | /********************************************//** 364 | * \brief Get an instruction's type and 365 | * immediate value 366 | * 367 | * Currently only supports ARMv7 encoding of 368 | * MOV Rd, \#imm, MOVT Rd, \#imm, BX Rn, and 369 | * SVC \#imm. You should use the return value 370 | * of this function to check for error but 371 | * instead the value of @a type where 372 | * @c INSTRUCTION_UNKNOWN is a failure. 373 | * \returns Immediate value of instruction 374 | * on success, indeterminate on error 375 | ***********************************************/ 376 | u32_t 377 | uvl_decode_arm_inst (u32_t cur_inst, ///< ARMv7 instruction 378 | u8_t *type) ///< See defined "Supported ARM instruction types" 379 | { 380 | // if this doesn't change, error 381 | *type = INSTRUCTION_UNKNOWN; 382 | // Bits 31-28 should be 1110, Always Execute 383 | if (!(BIT_SET (cur_inst, 31) && BIT_SET (cur_inst, 30) && BIT_SET (cur_inst, 29) && !BIT_SET (cur_inst, 28))) 384 | { 385 | // Unsupported conditional instruction. 386 | return -1; 387 | } 388 | // Bits 27-25 should be 110 for supervisor calls 389 | if (BIT_SET (cur_inst, 27)) 390 | { 391 | // Bit 24 should be set for SWI calls 392 | if (BIT_SET (cur_inst, 26) && BIT_SET (cur_inst, 25) && BIT_SET (cur_inst, 24)) 393 | { 394 | *type = INSTRUCTION_SYSCALL; 395 | // TODO: Return syscall immediate value. 396 | return 1; 397 | } 398 | } 399 | // Bits 27-25 should be 001 for data instructions 400 | else if (!BIT_SET (cur_inst, 26) && BIT_SET (cur_inst, 25)) 401 | { 402 | // Bits 24-23 should be 10 403 | if (BIT_SET (cur_inst, 24) && !BIT_SET (cur_inst, 23)) 404 | { 405 | // MOV instruction 406 | // Bits 21-20 should be 00 407 | if (!(!BIT_SET (cur_inst, 21) && !BIT_SET (cur_inst, 20))) 408 | { 409 | // Invalid ARM MOV instruction. 410 | return -1; 411 | } 412 | // Bits 15-12 should be 1100 for R12 load 413 | if (!(BIT_SET (cur_inst, 15) && BIT_SET (cur_inst, 14) && !BIT_SET (cur_inst, 13) && !BIT_SET (cur_inst, 12))) 414 | { 415 | // Not R12, unsupported 416 | return -1; 417 | } 418 | // Bit 22 is 1 for top load 0 for bottom load 419 | if (BIT_SET (cur_inst, 22)) // top load 420 | { 421 | *type = INSTRUCTION_MOVT; 422 | } 423 | else 424 | { 425 | *type = INSTRUCTION_MOVW; 426 | } 427 | // Immediate value at 19-16 and 11-0 428 | // discard bytes 31-20 429 | // discard bytes 15-0 430 | return (((cur_inst << 12) >> 28) << 12) | ((cur_inst << 20) >> 20); 431 | } 432 | // Bits 24-23 should be 00 433 | else if (!BIT_SET (cur_inst, 24) && !BIT_SET (cur_inst, 23)) 434 | { 435 | // ADR instruction 436 | // Bits 22-16 should be 1001111 437 | if (!(BIT_SET (cur_inst, 22) && !BIT_SET (cur_inst, 21) && !BIT_SET (cur_inst, 20) && BIT_SET (cur_inst, 19) && BIT_SET (cur_inst, 18) && BIT_SET (cur_inst, 17) && BIT_SET (cur_inst, 16))) 438 | { 439 | // Invalid ARM ADR instruction 440 | return -1; 441 | } 442 | // Bits 15-12 should be 1100 for R12 load 443 | if (!(BIT_SET (cur_inst, 15) && BIT_SET (cur_inst, 14) && !BIT_SET (cur_inst, 13) && !BIT_SET (cur_inst, 12))) 444 | { 445 | // Not R12, unsupported 446 | return -1; 447 | } 448 | *type = INSTRUCTION_ADR; 449 | return cur_inst & 0xFFF; 450 | } 451 | // Bits 24-23 should be 11 452 | else if (BIT_SET (cur_inst, 24) && BIT_SET (cur_inst, 23)) 453 | { 454 | // ADR instruction 455 | // Bits 22-21 should be 11 456 | if (!(BIT_SET (cur_inst, 22) && BIT_SET (cur_inst, 21))) 457 | { 458 | // Invalid ARM MVN instruction 459 | return -1; 460 | } 461 | // MVN is always invalid 462 | *type = INSTRUCTION_MVN; 463 | return 0; 464 | } 465 | } 466 | // Bits 27-25 should be 000 for jump instructions 467 | else if (!BIT_SET (cur_inst, 26) && !BIT_SET (cur_inst, 25)) 468 | { 469 | // Bits 24-4 should be 100101111111111110001, 0x12FFF1 for BX 470 | if ((cur_inst << 7) >> 11 == 0x12FFF1) 471 | { 472 | *type = INSTRUCTION_BRANCH; 473 | return 1; 474 | } 475 | // Bits 24-4 should be 100101111111111110001, 0x12FFF3 for BLX 476 | else if ((cur_inst << 7) >> 11 == 0x12FFF3) 477 | { 478 | *type = INSTRUCTION_BRANCH; 479 | return 1; 480 | } 481 | else 482 | { 483 | // unknown jump 484 | return -1; 485 | } 486 | } 487 | else 488 | { 489 | // Unsupported instruction. 490 | return -1; 491 | } 492 | } 493 | 494 | /********************************************//** 495 | * \brief Creates an ARMv7 instruction 496 | * 497 | * Currently only supports ARMv7 encoding of 498 | * MOV Rd, \#imm, MOVT Rd, \#imm, BX Rn, and 499 | * SVC \#imm. Depending on the @a type, not 500 | * all parameters may be used. 501 | * \returns ARMv7 instruction on success 502 | * or 0 on failure. 503 | ***********************************************/ 504 | u32_t 505 | uvl_encode_arm_inst (u8_t type, ///< See defined "Supported ARM instruction types" 506 | u16_t immed, ///< Immediate value to encode 507 | u16_t reg) ///< Register used in instruction 508 | { 509 | switch(type) 510 | { 511 | case INSTRUCTION_MOVW: 512 | // 1110 0011 0000 XXXX YYYY XXXXXXXXXXXX 513 | // where X is the immediate and Y is the register 514 | // Upper bits == 0xE30 515 | return ((u32_t)0xE30 << 20) | ((u32_t)(immed & 0xF000) << 4) | (immed & 0xFFF) | (reg << 12); 516 | case INSTRUCTION_MOVT: 517 | // 1110 0011 0100 XXXX YYYY XXXXXXXXXXXX 518 | // where X is the immediate and Y is the register 519 | // Upper bits == 0xE34 520 | return ((u32_t)0xE34 << 20) | ((u32_t)(immed & 0xF000) << 4) | (immed & 0xFFF) | (reg << 12); 521 | case INSTRUCTION_SYSCALL: 522 | // Syscall does not have any immediate value, the number should 523 | // already be in R12 524 | return (u32_t)0xEF000000; 525 | case INSTRUCTION_BRANCH: 526 | // 1110 0001 0010 111111111111 0001 YYYY 527 | // BX Rn has 0xE12FFF1 as top bytes 528 | return ((u32_t)0xE12FFF1 << 4) | reg; 529 | case INSTRUCTION_UNKNOWN: 530 | default: 531 | return 0; 532 | } 533 | } 534 | 535 | /********************************************//** 536 | * \brief Add a module's import table's entries 537 | * to the resolve table 538 | * 539 | * A loaded module has it's stubs already 540 | * resolved by the kernel. This will copy 541 | * those resolved entries for our own use. 542 | * \returns Zero on success, otherwise error 543 | ***********************************************/ 544 | int 545 | uvl_resolve_add_imports (module_info_t *mod_info, ///< Module with import table 546 | module_imports_t *reload_imp_table, ///< If not null, reloaded version of module with NIDs intact 547 | module_imports_t *imp_table, ///< Module's import table to read from 548 | int syscalls_only) ///< If set, will only add resolved syscalls and nothing else 549 | { 550 | // this should be called BEFORE cleanup 551 | resolve_entry_t res_entry; 552 | u32_t *memory; 553 | u32_t nid; 554 | int i; 555 | const u32_t *func_nid_table; 556 | 557 | // get functions first 558 | IF_VERBOSE LOG ("Found %u resolved function imports to copy.", IMP_GET_FUNC_COUNT (imp_table)); 559 | if (reload_imp_table) // first attempt: try reloaded module 560 | { 561 | func_nid_table = IMP_GET_FUNC_TABLE (reload_imp_table); 562 | } 563 | else // second attempt: try cached NID database 564 | { 565 | func_nid_table = uvl_get_import_fnid_cache (mod_info, imp_table); 566 | } 567 | for(i = 0; i < IMP_GET_FUNC_COUNT (imp_table); i++) 568 | { 569 | nid = func_nid_table[i]; 570 | memory = IMP_GET_FUNC_ENTRIES (imp_table)[i]; 571 | if (uvl_resolve_import_stub_to_entry (memory, nid, &res_entry) < 0) 572 | { 573 | LOG ("Error generating entry from import stub. Continuing."); 574 | continue; 575 | } 576 | if (syscalls_only && res_entry.type != RESOLVE_TYPE_SYSCALL) 577 | { 578 | continue; 579 | } 580 | if (uvl_resolve_table_add (&res_entry) < 0) 581 | { 582 | LOG ("Error adding entry to table."); 583 | return -1; 584 | } 585 | } 586 | if (syscalls_only) 587 | { 588 | return 0; 589 | } 590 | // get variables 591 | res_entry.type = RESOLVE_TYPE_VARIABLE; 592 | IF_VERBOSE LOG ("Found %u resolved variable imports to copy.", IMP_GET_VARS_COUNT (imp_table)); 593 | for(i = 0; i < IMP_GET_VARS_COUNT (imp_table); i++) 594 | { 595 | res_entry.nid = IMP_GET_VARS_TABLE (imp_table)[i]; 596 | res_entry.value.value = *(u32_t*)IMP_GET_VARS_ENTRIES (imp_table)[i]; 597 | if (uvl_resolve_table_add (&res_entry) < 0) 598 | { 599 | LOG ("Error adding entry to table."); 600 | return -1; 601 | } 602 | } 603 | // get TLS 604 | /* 605 | // TODO: Find out how this works 606 | res_entry.type = RESOLVE_TYPE_VARIABLE; 607 | IF_VERBOSE LOG ("Found %u resolved tls imports to copy.", imp_table->num_tls_vars); 608 | for(i = 0; i < imp_table->num_tls_vars; i++) 609 | { 610 | res_entry.nid = imp_table->tls_nid_table[i]; 611 | res_entry.value.value = *(u32_t*)imp_table->tls_entry_table[i]; 612 | if (uvl_resolve_table_add (&res_entry) < 0) 613 | { 614 | LOG ("Error adding entry to table."); 615 | return -1; 616 | } 617 | } 618 | */ 619 | return 0; 620 | } 621 | 622 | /********************************************//** 623 | * \brief Add a module's export entries to 624 | * the resolve table 625 | * 626 | * \returns Zero on success, otherwise error 627 | ***********************************************/ 628 | int 629 | uvl_resolve_add_exports (module_exports_t *exp_table) ///< Module's export table 630 | { 631 | resolve_entry_t res_entry; 632 | int i; 633 | int offset = 0; 634 | 635 | // get functions first 636 | res_entry.type = RESOLVE_TYPE_FUNCTION; 637 | IF_VERBOSE LOG ("Found %u resolved function exports to copy.", exp_table->num_functions); 638 | for(i = 0; i < exp_table->num_functions; i++, offset++) 639 | { 640 | res_entry.nid = exp_table->nid_table[offset]; 641 | res_entry.value.func_ptr = exp_table->entry_table[offset]; 642 | if (uvl_resolve_table_add (&res_entry) < 0) 643 | { 644 | LOG ("Error adding entry to table."); 645 | return -1; 646 | } 647 | } 648 | // get variables 649 | res_entry.type = RESOLVE_TYPE_VARIABLE; 650 | IF_VERBOSE LOG ("Found %u resolved variable exports to copy.", exp_table->num_vars); 651 | for(i = 0; i < exp_table->num_vars; i++, offset++) 652 | { 653 | res_entry.nid = exp_table->nid_table[offset]; 654 | res_entry.value.value = *(u32_t*)exp_table->entry_table[offset]; 655 | if (uvl_resolve_table_add (&res_entry) < 0) 656 | { 657 | LOG ("Error adding entry to table."); 658 | return -1; 659 | } 660 | } 661 | return 0; 662 | } 663 | 664 | #if 0 665 | /********************************************//** 666 | * \brief Walks the resolve table, locates 667 | * unresolved entries and resolves them 668 | * 669 | * Called after building the resolve table from 670 | * resolved entries of loaded modules and 671 | * unresolved entries of the homebrew. 672 | * \returns Zero on success, otherwise error 673 | ***********************************************/ 674 | int 675 | uvl_resolve_all_unresolved () 676 | { 677 | resolve_entry_t *stub; 678 | resolve_entry_t *entry; 679 | u32_t *memloc; 680 | int i; 681 | IF_DEBUG LOG ("%u resolve entries to look through.", g_resolve_entries); 682 | for (i = 0; i < g_resolve_entries; i++) 683 | { 684 | if (g_resolve_table[i].resolved) 685 | { 686 | continue; 687 | } 688 | stub = &g_resolve_table[i]; 689 | // first attempt, look up in table 690 | IF_DEBUG LOG ("Trying to lookup NID 0x%X in resolve table.", stub->nid); 691 | if ((entry = uvl_resolve_table_get (stub->nid, 1)) != NULL) 692 | { 693 | stub->type = entry->type; 694 | switch (entry->type) 695 | { 696 | case RESOLVE_TYPE_FUNCTION: 697 | /* 698 | MOV R12, (u16_t)entry->value.func_ptr 699 | MOVT R12, (u16_t)(entry->value.func_ptr >> 16) 700 | BX R12 701 | */ 702 | memloc = stub->value.func_ptr; 703 | memloc[0] = uvl_encode_arm_inst (INSTRUCTION_MOV, (u16_t)entry->value.value, 12); 704 | memloc[1] = uvl_encode_arm_inst (INSTRUCTION_MOVT, (u16_t)(entry->value.value >> 16), 12); 705 | memloc[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 12); 706 | break; 707 | case RESOLVE_TYPE_SYSCALL: 708 | /* 709 | MOV R12, (u16_t)entry->value.value 710 | SVC 0 711 | BX LR 712 | */ 713 | memloc = stub->value.func_ptr; 714 | memloc[0] = uvl_encode_arm_inst (INSTRUCTION_MOV, (u16_t)entry->value.value, 12); 715 | memloc[1] = uvl_encode_arm_inst (INSTRUCTION_SYSCALL, 0, 0); 716 | memloc[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 14); 717 | break; 718 | case RESOLVE_TYPE_VARIABLE: 719 | *(u32_t*)stub->value.ptr = entry->value.value; 720 | break; 721 | } 722 | stub->resolved = 1; 723 | continue; 724 | } 725 | // second attempt, estimate syscall 726 | IF_DEBUG LOG ("Trying to estimate syscall for NID 0x%X.", stub->nid); 727 | if ((entry = uvl_estimate_syscall (stub->nid)) != NULL) 728 | { 729 | /* 730 | MOV R12, (u16_t)entry->value.value 731 | SVC 0 732 | BX LR 733 | */ 734 | memloc = stub->value.func_ptr; 735 | memloc[0] = uvl_encode_arm_inst (INSTRUCTION_MOV, (u16_t)entry->value.value, 12); 736 | memloc[1] = uvl_encode_arm_inst (INSTRUCTION_SYSCALL, 0, 0); 737 | memloc[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 14); 738 | stub->resolved = 1; 739 | continue; 740 | } 741 | // we failed :( 742 | LOG ("Failed to resolve function NID: 0x%08X, continuing", stub->nid); 743 | } 744 | } 745 | #endif 746 | 747 | /********************************************//** 748 | * \brief Adds entries from all loaded 749 | * modules to resolve table 750 | * 751 | * \returns Zero on success, otherwise error 752 | ***********************************************/ 753 | int 754 | uvl_resolve_add_all_modules (int type) ///< An OR combination of flags (see defined "Search flags for importing loaded modules") directing the search 755 | { 756 | PsvUID mod_list[MAX_LOADED_MODS]; 757 | u32_t num_loaded = MAX_LOADED_MODS; 758 | int i; 759 | 760 | IF_DEBUG LOG ("Getting list of loaded modules."); 761 | if (sceKernelGetModuleList (0xFF, mod_list, &num_loaded) < 0) 762 | { 763 | LOG ("Failed to get module list."); 764 | return -1; 765 | } 766 | IF_DEBUG LOG ("Found %u loaded modules.", num_loaded); 767 | for (i = 0; i < num_loaded; i++) 768 | { 769 | if (uvl_resolve_add_module (mod_list[i], type) < 0) 770 | { 771 | LOG ("Failed to add module %u: 0x%08X. Continuing.", i, mod_list[i]); 772 | continue; 773 | } 774 | } 775 | IF_DEBUG LOG ("Added %u NID entries to resolve database.", g_resolve_table->length); 776 | return 0; 777 | } 778 | 779 | /********************************************//** 780 | * \brief Take a loaded module info, and return 781 | * the module info in loaded memory. 782 | * 783 | * \returns module_info_t, NULL on error 784 | ***********************************************/ 785 | module_info_t * 786 | uvl_find_module_info (loaded_module_info_t *m_mod_info) ///< Loaded module information 787 | { 788 | module_info_t *mod_info; 789 | void *result; 790 | u32_t segment_size; 791 | 792 | mod_info = NULL; 793 | result = m_mod_info->segments[0].vaddr; 794 | segment_size = m_mod_info->segments[0].memsz; 795 | while (segment_size > 0) 796 | { 797 | IF_VERBOSE LOG ("Searching for module name in memory. Start 0x%X", result); 798 | result = memstr (result, segment_size, m_mod_info->module_name, strlen (m_mod_info->module_name)); 799 | if (result == NULL) 800 | { 801 | IF_DEBUG LOG ("Cannot find module name in memory."); 802 | break; // not found 803 | } 804 | // try making this the one 805 | mod_info = (module_info_t*)((u32_t)result - 4); 806 | IF_VERBOSE LOG("Possible module info struct at 0x%X", (u32_t) mod_info); 807 | if (mod_info->ent_top < segment_size && mod_info->ent_end < segment_size && 808 | mod_info->stub_top < segment_size && mod_info->stub_end < segment_size) 809 | { 810 | IF_VERBOSE LOG ("Module export start at 0x%X import start at 0x%X", (u32_t)mod_info->ent_top + (u32_t)m_mod_info->segments[0].vaddr, (u32_t)mod_info->stub_top + (u32_t)m_mod_info->segments[0].vaddr); 811 | break; // we found it 812 | } 813 | else // that string just happened to appear 814 | { 815 | IF_DEBUG LOG ("False alarm, found name is not in module info structure."); 816 | mod_info = NULL; 817 | segment_size -= ((u32_t)result - (u32_t)m_mod_info->segments[0].vaddr) + strlen (m_mod_info->module_name); // subtract length 818 | result = (void*)((u32_t)result + strlen (m_mod_info->module_name)); // start after name 819 | continue; 820 | } 821 | } 822 | 823 | return mod_info; 824 | } 825 | 826 | /********************************************//** 827 | * \brief Adds entries from a loaded module to 828 | * resolve table 829 | * 830 | * This functions takes a loaded module 831 | * and attempts to read its import and/or 832 | * export table and add entries to our 833 | * resolve table. 834 | * \returns Zero on success, otherwise error 835 | ***********************************************/ 836 | int 837 | uvl_resolve_add_module (PsvUID modid, ///< UID of the module 838 | int type) ///< An OR combination of flags (see defined "Search flags for importing loaded modules") directing the search 839 | { 840 | loaded_module_info_t m_mod_info; 841 | module_info_t *mod_info; 842 | module_exports_t *exports; 843 | module_imports_t *imports; 844 | PsvUID reload_mod; 845 | int opt; 846 | loaded_module_info_t m_reload_mod_info; 847 | module_info_t *reload_mod_info; 848 | module_imports_t *reload_imports; 849 | char reload_mod_path[64]; 850 | 851 | m_mod_info.size = sizeof (loaded_module_info_t); // should be 440 852 | IF_VERBOSE LOG ("Getting information for module UID: 0x%X.", modid); 853 | if (sceKernelGetModuleInfo (modid, &m_mod_info) < 0) 854 | { 855 | LOG ("Error getting info for mod 0x%08X", modid); 856 | return -1; 857 | } 858 | IF_DEBUG LOG ("Module: %s, at: 0x%08X", m_mod_info.module_name, m_mod_info.segments[0].vaddr); 859 | if ((mod_info = uvl_find_module_info (&m_mod_info)) == NULL) 860 | { 861 | LOG ("Can't get module information for %s.", m_mod_info.module_name); 862 | return -1; 863 | } 864 | if (type & RESOLVE_MOD_EXPS) 865 | { 866 | IF_VERBOSE LOG ("Adding exports to resolve table."); 867 | for (exports = (module_exports_t*)((u32_t)m_mod_info.segments[0].vaddr + mod_info->ent_top); 868 | (u32_t)exports < ((u32_t)m_mod_info.segments[0].vaddr + mod_info->ent_end); exports++) 869 | { 870 | if (exports->lib_name != NULL) 871 | { 872 | IF_VERBOSE LOG ("Adding exports for %s", exports->lib_name); 873 | } 874 | if (uvl_resolve_add_exports (exports) < 0) 875 | { 876 | LOG ("Unable to resolve exports at 0x%08X. Continuing.", (u32_t)exports); 877 | continue; 878 | } 879 | } 880 | } 881 | if (type & RESOLVE_MOD_IMPS) 882 | { 883 | reload_mod_info = NULL; 884 | reload_imports = NULL; 885 | if (type & RESOLVE_RELOAD_MOD) 886 | { 887 | opt = sizeof (opt); 888 | IF_VERBOSE LOG ("Attempting to reload: %s", m_mod_info.file_path); 889 | 890 | if (strncmp(m_mod_info.file_path, "ux0:/patch/", 11) == 0) 891 | { 892 | char* mod_filename = strchr(m_mod_info.file_path + 11, '/'); 893 | strcpy(reload_mod_path, "app0:"); 894 | strcpy(reload_mod_path + 5, mod_filename); 895 | 896 | IF_DEBUG LOG("Module path for reloading changed to: %s", reload_mod_path); 897 | 898 | reload_mod = sceKernelLoadModule(reload_mod_path, 0, &opt); 899 | } 900 | else if (strncmp(m_mod_info.file_path, "vs0:sys/external/", 17) == 0) 901 | { 902 | sceAppMgrGetVs0UserModuleDrive(reload_mod_path); 903 | strcpy(reload_mod_path + 15, m_mod_info.file_path + 17); 904 | 905 | IF_DEBUG LOG("Module path for reloading changed to: %s", reload_mod_path); 906 | 907 | reload_mod = sceKernelLoadModule(reload_mod_path, 0, &opt); 908 | } 909 | else 910 | { 911 | reload_mod = sceKernelLoadModule(m_mod_info.file_path, 0, &opt); 912 | } 913 | 914 | m_reload_mod_info.size = sizeof (loaded_module_info_t); 915 | if (sceKernelGetModuleInfo (reload_mod, &m_reload_mod_info) >= 0) 916 | { 917 | reload_mod_info = uvl_find_module_info (&m_reload_mod_info); 918 | } 919 | if (reload_mod_info) 920 | { 921 | LOG ("Reloaded %s", mod_info->modname); 922 | reload_imports = (module_imports_t*)((u32_t)m_reload_mod_info.segments[0].vaddr + reload_mod_info->stub_top); 923 | } 924 | } 925 | 926 | IF_VERBOSE LOG ("Adding resolved imports to resolve table."); 927 | for (imports = (module_imports_t*)((u32_t)m_mod_info.segments[0].vaddr + mod_info->stub_top); 928 | (u32_t)imports < ((u32_t)m_mod_info.segments[0].vaddr + mod_info->stub_end); imports = IMP_GET_NEXT (imports)) 929 | { 930 | IF_VERBOSE LOG ("Adding imports for %s", IMP_GET_NAME (imports)); 931 | if (uvl_resolve_add_imports (mod_info, reload_imports, imports, type & RESOLVE_IMPS_SVC_ONLY) < 0) 932 | { 933 | LOG ("Unable to resolve imports at 0x%08X. Continuing.", (u32_t)imports); 934 | continue; 935 | } 936 | if (reload_imports) 937 | { 938 | reload_imports = IMP_GET_NEXT (reload_imports); 939 | } 940 | } 941 | 942 | if (reload_mod_info) 943 | { 944 | IF_VERBOSE LOG ("Closing reloaded module."); 945 | sceKernelUnloadModule (reload_mod, 0, NULL); 946 | } 947 | } 948 | return 0; 949 | } 950 | 951 | /********************************************//** 952 | * \brief Resolves an import table 953 | * 954 | * \returns Zero on success, otherwise error 955 | ***********************************************/ 956 | int 957 | uvl_resolve_imports (module_imports_t *import) ///< Import table 958 | { 959 | u32_t i; 960 | resolve_entry_t *resolve; 961 | u32_t *stub; 962 | 963 | IF_DEBUG LOG ("Resolving import table at 0x%08X", (u32_t)import); 964 | for (i = 0; i < IMP_GET_FUNC_COUNT (import); i++) 965 | { 966 | IF_VERBOSE LOG ("Trying to resolve function NID: 0x%08X found in %s", IMP_GET_FUNC_TABLE (import)[i], IMP_GET_NAME (import)); 967 | resolve = uvl_resolve_table_get (IMP_GET_FUNC_TABLE (import)[i]); 968 | stub = IMP_GET_FUNC_ENTRIES (import)[i]; 969 | IF_VERBOSE LOG ("Stub located at: 0x%08X", (u32_t)stub); 970 | if (resolve == NULL) 971 | { 972 | LOG ("Cannot resolve NID: 0x%08X. Continuing.", IMP_GET_FUNC_TABLE (import)[i]); 973 | continue; 974 | } 975 | if (uvl_resolve_entry_to_import_stub (resolve, stub) < 0) 976 | { 977 | LOG ("Cannot write to stub 0x%08X", (u32_t)stub); 978 | return -1; 979 | } 980 | 981 | } 982 | for (i = 0; i < IMP_GET_VARS_COUNT (import); i++) 983 | { 984 | IF_VERBOSE LOG ("Trying to resolve variable NID: 0x%08X found in %s", IMP_GET_VARS_TABLE (import)[i], IMP_GET_NAME (import)); 985 | resolve = uvl_resolve_table_get (IMP_GET_VARS_TABLE (import)[i]); 986 | stub = IMP_GET_VARS_ENTRIES (import)[i]; 987 | IF_VERBOSE LOG ("Stub located at: 0x%08X", (u32_t)stub); 988 | if (resolve == NULL) 989 | { 990 | LOG ("Cannot resolve NID: 0x%08X. Continuing.", IMP_GET_VARS_TABLE (import)[i]); 991 | continue; 992 | } 993 | if (uvl_resolve_entry_to_import_stub (resolve, stub) < 0) 994 | { 995 | LOG ("Cannot write to stub 0x%08X", (u32_t)stub); 996 | return -1; 997 | } 998 | } 999 | /* 1000 | for (i = 0; i < import->num_tls_vars; i++) 1001 | { 1002 | IF_VERBOSE LOG ("Trying to resolve tls NID: 0x%08X found in %s", import->tls_nid_table[i], import->lib_name); 1003 | resolve = uvl_resolve_table_get (import->tls_nid_table[i]); 1004 | stub = import->tls_entry_table[i]; 1005 | IF_VERBOSE LOG ("Stub located at: 0x%08X", (u32_t)stub); 1006 | if (resolve == NULL) 1007 | { 1008 | LOG ("Cannot resolve NID: 0x%08X. Continuing.", import->tls_nid_table[i]); 1009 | continue; 1010 | } 1011 | if (uvl_resolve_entry_to_import_stub (resolve, stub) < 0) 1012 | { 1013 | LOG ("Cannot write to stub 0x%08X", (u32_t)stub); 1014 | return -1; 1015 | } 1016 | } 1017 | */ 1018 | return 0; 1019 | } 1020 | 1021 | /********************************************//** 1022 | * \brief Resolves UVLoader imported function 1023 | * 1024 | * UVLoader only depends on functions exported 1025 | * and imported by sceLibKernel. This function 1026 | * is a simplified version of the main resolver 1027 | * and does not use and external functions. 1028 | * \returns Zero on success, otherwise error 1029 | ***********************************************/ 1030 | int 1031 | uvl_resolve_loader (u32_t nid, void *libkernel, void *stub) 1032 | { 1033 | void *base; 1034 | void *result; 1035 | module_info_t *mod_info; 1036 | module_exports_t *exports; 1037 | module_imports_t *imports; 1038 | u32_t i; 1039 | const u32_t *func_nid_table; 1040 | 1041 | IF_VERBOSE LOG ("Resolving 0x%08X for 0x%08X", nid, (u32_t)stub); 1042 | 1043 | // Should always be first occurance of string 1044 | result = memstr (libkernel, UVL_LIBKERN_MAX_SIZE, "SceLibKernel", strlen ("SceLibKernel")); 1045 | mod_info = (module_info_t*)((u32_t)result - 4); 1046 | base = (char *)mod_info - mod_info->ent_top + sizeof (module_info_t); 1047 | 1048 | // remember libkernel nid if needed 1049 | if (!g_libkenel_nid) 1050 | { 1051 | uvl_unlock_mem (); 1052 | g_libkenel_nid = mod_info->module_nid; 1053 | uvl_lock_mem (); 1054 | IF_VERBOSE LOG ("SceLibKernel NID: 0x%08X", g_libkenel_nid); 1055 | } 1056 | 1057 | // look in exports 1058 | for (exports = (module_exports_t*)((u32_t)base + mod_info->ent_top); 1059 | (u32_t)exports < ((u32_t)base + mod_info->ent_end); exports++) 1060 | { 1061 | for (i = 0; i < exports->num_functions; i++) 1062 | { 1063 | if (exports->nid_table[i] == nid) 1064 | { 1065 | IF_VERBOSE LOG ("Resolved at export 0x%08X", (u32_t)exports->entry_table[i]); 1066 | uvl_unlock_mem (); 1067 | ((u32_t*)stub)[0] = uvl_encode_arm_inst (INSTRUCTION_MOVW, (u16_t)(u32_t)exports->entry_table[i], 12); 1068 | ((u32_t*)stub)[1] = uvl_encode_arm_inst (INSTRUCTION_MOVT, (u16_t)((u32_t)exports->entry_table[i] >> 16), 12); 1069 | ((u32_t*)stub)[2] = uvl_encode_arm_inst (INSTRUCTION_BRANCH, 0, 12); 1070 | uvl_lock_mem (); 1071 | uvl_flush_icache (stub, STUB_FUNC_SIZE); 1072 | return 0; 1073 | } 1074 | } 1075 | } 1076 | 1077 | // look in imports 1078 | for (imports = (module_imports_t*)((u32_t)base + mod_info->stub_top); 1079 | (u32_t)imports < ((u32_t)base + mod_info->stub_end); imports = IMP_GET_NEXT (imports)) 1080 | { 1081 | func_nid_table = uvl_get_import_fnid_cache (mod_info, imports); 1082 | for (i = 0; i < IMP_GET_FUNC_COUNT (imports); i++) 1083 | { 1084 | if (func_nid_table[i] == nid) 1085 | { 1086 | IF_VERBOSE LOG ("Resolved at import 0x%08X", (u32_t)IMP_GET_FUNC_ENTRIES (imports)[i]); 1087 | uvl_unlock_mem (); 1088 | memcpy (stub, IMP_GET_FUNC_ENTRIES (imports)[i], STUB_FUNC_SIZE); 1089 | uvl_lock_mem (); 1090 | uvl_flush_icache (stub, STUB_FUNC_SIZE); 1091 | return 0; 1092 | } 1093 | } 1094 | } 1095 | 1096 | LOG ("Cannot resolve 0x%08X for loader, UVL will not work properly.", nid); 1097 | 1098 | return -1; 1099 | } 1100 | -------------------------------------------------------------------------------- /resolve.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file resolve.h 3 | /// \brief Functions to resolve NIDs and syscalls 4 | /// \defgroup resolve Executable Resolver 5 | /// \brief Finds and resolves NIDs 6 | /// @{ 7 | /// 8 | #ifndef UVL_RESOLVE 9 | #define UVL_RESOLVE 10 | 11 | #include "types.h" 12 | 13 | /** \name Type of entry 14 | * @{ 15 | */ 16 | #define RESOLVE_TYPE_UNKNOWN 0 ///< Unknown type 17 | #define RESOLVE_TYPE_FUNCTION 1 ///< Function call 18 | #define RESOLVE_TYPE_SYSCALL 2 ///< Syscall 19 | #define RESOLVE_TYPE_VARIABLE 3 ///< Imported variable 20 | #define RESOLVE_TYPE_RELATIVE 4 ///< PC relative import 21 | #define RESOLVE_TYPE_UNRESOLVED 5 ///< No resolve 22 | /** @}*/ 23 | 24 | /** \name Supported ARM instruction types 25 | * @{ 26 | */ 27 | #define INSTRUCTION_UNKNOWN 0 ///< Unknown/unsupported instruction 28 | #define INSTRUCTION_MOVW 1 ///< MOVW Rd, \#imm instruction 29 | #define INSTRUCTION_MOVT 2 ///< MOVT Rd, \#imm instruction 30 | #define INSTRUCTION_SYSCALL 3 ///< SVC \#imm instruction 31 | #define INSTRUCTION_BRANCH 4 ///< BX Rn instruction 32 | #define INSTRUCTION_ADR 5 ///< Relative addressing 33 | #define INSTRUCTION_MVN 6 ///< MVN 0 (always invalid) 34 | /** @}*/ 35 | 36 | #define STUB_FUNC_MAX_LEN 16 ///< Max size for a stub function in bytes 37 | 38 | /** \name Search flags for importing loaded modules 39 | * \sa uvl_resolve_all_loaded_modules 40 | * @{ 41 | */ 42 | #define RESOLVE_MOD_IMPS 0x1 ///< Add entry from import function stubs 43 | #define RESOLVE_MOD_EXPS 0x2 ///< Add entry from exported information 44 | #define RESOLVE_IMPS_SVC_ONLY 0x4 ///< Used with @c RESOLVE_MOD_IMPS but only add syscalls for import entries 45 | #define RESOLVE_RELOAD_MOD 0x8 ///< Load module again to get unpoisoned import NID table 46 | /** @}*/ 47 | 48 | /** \name Module infomation check 49 | * @{ 50 | */ 51 | #define MOD_INFO_VALID_ATTR 0x0000 52 | #define MOD_INFO_VALID_VER 0x0101 53 | /** @}*/ 54 | 55 | #define MAX_LOADED_MODS 128 ///< Maximum number of loaded modules 56 | #define MAX_RESOLVE_ENTRIES 0x10000 ///< Maximum number of resolves 57 | #define STUB_FUNC_SIZE 0x10 ///< Size of stub functions 58 | #define UVL_LIBKERN_MAX_SIZE 0xE000 ///< Maximum size of sceLibKernel (for resolving loader) 59 | 60 | /** 61 | * \brief Resolve table entry 62 | * 63 | * This can represent either an unresolved entry 64 | * from a homebrew or a resolved entry copied 65 | * from a loaded module. 66 | */ 67 | typedef struct resolve_entry 68 | { 69 | u32_t nid; ///< NID of entry 70 | u16_t type; ///< See defined "Type of entry" 71 | u16_t reserved; ///< For future use 72 | /** 73 | * \brief Value of the entry 74 | */ 75 | union value 76 | { 77 | void* ptr; ///< A pointer value for unresolved pointing to where to write resolved value 78 | u32_t value; ///< Any double-word value for resolved 79 | void* func_ptr; ///< A pointer to stub function for unresolved or function to call for resolved 80 | u32_t syscall; ///< A syscall number 81 | } value; 82 | } resolve_entry_t; 83 | 84 | /** 85 | * \brief SCE module information section 86 | * 87 | * Can be found in an ELF file or loaded in 88 | * memory. 89 | */ 90 | typedef struct module_info // thanks roxfan 91 | { 92 | u16_t modattribute; // ?? 93 | u16_t modversion; // always 1,1? 94 | char modname[27]; ///< Name of the module 95 | u8_t type; // 6 = user-mode prx? 96 | void *gp_value; // always 0 on ARM 97 | u32_t ent_top; // beginning of the export list (sceModuleExports array) 98 | u32_t ent_end; // end of same 99 | u32_t stub_top; // beginning of the import list (sceModuleStubInfo array) 100 | u32_t stub_end; // end of same 101 | u32_t module_nid; // ID of the PRX? seems to be unused 102 | u32_t field_38; // unused in samples 103 | u32_t field_3C; // I suspect these may contain TLS info 104 | u32_t field_40; // 105 | u32_t mod_start; // module start function; can be 0 or -1; also present in exports 106 | u32_t mod_stop; // module stop function 107 | u32_t exidx_start; // ARM EABI style exception tables 108 | u32_t exidx_end; // 109 | u32_t extab_start; // 110 | u32_t extab_end; // 111 | } module_info_t; 112 | 113 | /** 114 | * \brief SCE module export table 115 | * 116 | * Can be found in an ELF file or loaded in 117 | * memory. 118 | */ 119 | typedef struct module_exports // thanks roxfan 120 | { 121 | u16_t size; // size of this structure; 0x20 for Vita 1.x 122 | u8_t lib_version[2]; // 123 | u16_t attribute; // ? 124 | u16_t num_functions; // number of exported functions 125 | u32_t num_vars; // number of exported variables 126 | u32_t num_tls_vars; // number of exported TLS variables? <-- pretty sure wrong // yifanlu 127 | u32_t module_nid; // NID of this specific export list; one PRX can export several names 128 | char *lib_name; // name of the export module 129 | u32_t *nid_table; // array of 32-bit NIDs for the exports, first functions then vars 130 | void **entry_table; // array of pointers to exported functions and then variables 131 | } module_exports_t; 132 | 133 | /** 134 | * \brief SCE module import table (< 3.0 format) 135 | * 136 | * Can be found in an ELF file or loaded in 137 | * memory. 138 | */ 139 | typedef struct module_imports_2x // thanks roxfan 140 | { 141 | u16_t size; // size of this structure; 0x34 for Vita 1.x 142 | u16_t lib_version; // 143 | u16_t attribute; // 144 | u16_t num_functions; // number of imported functions 145 | u16_t num_vars; // number of imported variables 146 | u16_t num_tls_vars; // number of imported TLS variables 147 | u32_t reserved1; // ? 148 | u32_t module_nid; // NID of the module to link to 149 | char *lib_name; // name of module 150 | u32_t reserved2; // ? 151 | u32_t *func_nid_table; // array of function NIDs (numFuncs) 152 | void **func_entry_table; // parallel array of pointers to stubs; they're patched by the loader to jump to the final code 153 | u32_t *var_nid_table; // NIDs of the imported variables (numVars) 154 | void **var_entry_table; // array of pointers to "ref tables" for each variable 155 | u32_t *tls_nid_table; // NIDs of the imported TLS variables (numTlsVars) 156 | void **tls_entry_table; // array of pointers to ??? 157 | } module_imports_2x_t; 158 | 159 | /** 160 | * \brief SCE module import table (>= 3.x format) 161 | * 162 | * Can be found in an ELF file or loaded in 163 | * memory. 164 | */ 165 | typedef struct module_imports_3x 166 | { 167 | u16_t size; // size of this structure; 0x24 for Vita 3.x 168 | u16_t lib_version; // 169 | u16_t attribute; // 170 | u16_t num_functions; // number of imported functions 171 | u16_t num_vars; // number of imported variables 172 | u16_t unknown1; 173 | u32_t module_nid; // NID of the module to link to 174 | char *lib_name; // name of module 175 | u32_t *func_nid_table; // array of function NIDs (numFuncs) 176 | void **func_entry_table; // parallel array of pointers to stubs; they're patched by the loader to jump to the final code 177 | u32_t *var_nid_table; // NIDs of the imported variables (numVars) 178 | void **var_entry_table; // array of pointers to "ref tables" for each variable 179 | } module_imports_3x_t; 180 | 181 | /** 182 | * \brief SCE module import table 183 | */ 184 | typedef union module_imports 185 | { 186 | u16_t size; 187 | module_imports_2x_t old_version; 188 | module_imports_3x_t new_version; 189 | } module_imports_t; 190 | 191 | #define IMP_GET_NEXT(imp) ((module_imports_t *)((char *)imp + imp->size)) 192 | #define IMP_GET_FUNC_COUNT(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.num_functions : imp->old_version.num_functions) 193 | #define IMP_GET_VARS_COUNT(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.num_vars : imp->old_version.num_vars) 194 | #define IMP_GET_NID(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.module_nid : imp->old_version.module_nid) 195 | #define IMP_GET_NAME(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.lib_name : imp->old_version.lib_name) 196 | #define IMP_GET_FUNC_TABLE(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.func_nid_table : imp->old_version.func_nid_table) 197 | #define IMP_GET_FUNC_ENTRIES(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.func_entry_table : imp->old_version.func_entry_table) 198 | #define IMP_GET_VARS_TABLE(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.var_nid_table : imp->old_version.var_nid_table) 199 | #define IMP_GET_VARS_ENTRIES(imp) (imp->size == sizeof (module_imports_3x_t) ? imp->new_version.var_entry_table : imp->old_version.var_entry_table) 200 | 201 | /** 202 | * \brief Either an SCE module import table or export table 203 | * 204 | * \sa module_imports 205 | * \sa module_exports 206 | */ 207 | typedef union module_ports 208 | { 209 | u16_t 210 | size; ///< Size of table 211 | module_imports_t imports; ///< Import kind 212 | module_exports_t exports; ///< Export kind 213 | } module_ports_t; 214 | 215 | /** 216 | * \brief A segment of the module in memory 217 | */ 218 | typedef struct segment_info 219 | { 220 | u32_t size; // this structure size (0x18) 221 | u32_t perms; // probably rwx in low bits 222 | void *vaddr; // address in memory 223 | u32_t memsz; // size in memory 224 | u32_t flags; // meanig unknown 225 | u32_t res; // unused? 226 | } segment_info_t; 227 | 228 | /** 229 | * \brief Loaded module information 230 | * 231 | * Returned by @c sceKernelGetModuleInfo 232 | */ 233 | typedef struct loaded_module_info 234 | { 235 | u32_t size; // 0x1B8 for Vita 1.x 236 | u32_t handle; // kernel module handle? 237 | u32_t flags; // some bits. could be priority or whatnot 238 | char module_name[28]; 239 | u32_t unkn_28; 240 | void *module_start; 241 | u32_t unkn_30; 242 | void *module_stop; 243 | void *exidx_start; 244 | void *exidx_end; 245 | u32_t unkn_40; 246 | u32_t unkn_44; 247 | void *tls_init_data; 248 | u32_t tls_init_size; 249 | u32_t tls_area_size; 250 | char file_path[256]; // 251 | segment_info_t segments[4]; 252 | u32_t type; // 6 = user-mode PRX? 253 | } loaded_module_info_t; 254 | 255 | /** \name Interacting with the resolve table 256 | * @{ 257 | */ 258 | int uvl_resolve_table_initialize (); 259 | int uvl_resolve_table_destroy (); 260 | int uvl_resolve_table_add (resolve_entry_t *entry); 261 | resolve_entry_t *uvl_resolve_table_get (u32_t nid); 262 | /** @}*/ 263 | /** \name Estimating syscalls 264 | * @{ 265 | */ 266 | resolve_entry_t *uvl_estimate_syscall (u32_t nid); 267 | /** @}*/ 268 | /** \name Capturing and resolving stubs 269 | * @{ 270 | */ 271 | int uvl_resolve_import_stub_to_entry (void *stub, u32_t nid, resolve_entry_t *entry); 272 | int uvl_resolve_entry_to_import_stub (resolve_entry_t *entry, void *stub); 273 | /** @}*/ 274 | /** \name ARM instruction functions 275 | * @{ 276 | */ 277 | u32_t uvl_decode_arm_inst (u32_t cur_inst, u8_t *type); 278 | u32_t uvl_encode_arm_inst (u8_t type, u16_t immed, u16_t reg); 279 | /** @}*/ 280 | /** \name Bulk add to resolve table 281 | * @{ 282 | */ 283 | int uvl_resolve_add_imports (module_info_t *mod_info, module_imports_t *reload_imp_table, module_imports_t *imp_table, int syscalls_only); 284 | int uvl_resolve_add_exports (module_exports_t *exp_table); 285 | /** @}*/ 286 | /** \name Resolving entries 287 | * @{ 288 | */ 289 | int uvl_resolve_add_all_modules (int type); 290 | int uvl_resolve_add_module (PsvUID modid, int type); 291 | int uvl_resolve_imports (module_imports_t *import); 292 | int uvl_resolve_loader (u32_t nid, void *libkernel_base, void *stub); 293 | /** @}*/ 294 | 295 | module_info_t *uvl_find_module_info (loaded_module_info_t *m_mod_info); 296 | 297 | // live resolving too slow 298 | #if 0 299 | /** \name Resolving entries 300 | * @{ 301 | */ 302 | u32_t uvl_encode_arm_inst (u8_t type, u16_t immed, u16_t reg); 303 | int uvl_resolve_stub (u32_t nid, void *stub, char *lib_name); 304 | int uvl_resolve_stub_from_module (u32_t nid, void *stub, char *lib_name, void *mod_start, module_info_t *mod_info); 305 | /** @}*/ 306 | #endif 307 | 308 | #endif 309 | /// @} 310 | -------------------------------------------------------------------------------- /scefuncs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * scefuncs.c - Hooks for API functions 3 | * Copyright 2012 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #define GENERATE_STUBS 18 | #include "config.h" 19 | #include "resolve.h" 20 | #include "scefuncs.h" 21 | #include "utils.h" 22 | #include "uvloader.h" 23 | 24 | /********************************************//** 25 | * \brief Wrapper to allocate code memory block 26 | * 27 | * Wrapper function to allocate code memory and 28 | * return a block id. 29 | * \returns Block id for code memory 30 | ***********************************************/ 31 | int sceKernelAllocCodeMemBlock(const char *name, ///< Block name 32 | unsigned int length) ///< Allocate size 33 | { 34 | return sceKernelFindMemBlockByAddr(uvl_alloc_code_mem(&length), 0); 35 | } 36 | 37 | /********************************************//** 38 | * \brief Resolves UVLoader 39 | * 40 | * This function will try its best to resolve 41 | * imported function given their NIDs. UVL 42 | * only uses sceLibKernel API calls which 43 | * should be imported by every game. 44 | ***********************************************/ 45 | void 46 | uvl_scefuncs_resolve_loader (void *anchor) ///< Import table entry pointing to SceLibKernel 47 | { 48 | // we must first find the relocated sceLibKernel base 49 | // by resolving the first 50 | resolve_entry_t kernel_base; 51 | // unfortunally, we can't do error checks yet so let's pray 52 | // it doesn't crash 53 | uvl_resolve_import_stub_to_entry (anchor, 0, &kernel_base); 54 | kernel_base.value.value &= ~1u; // unset first bit (entry is thumb code) 55 | #define RESOLVE_STUB(_stub, _nid) uvl_resolve_loader (_nid, kernel_base.value.ptr, _stub); 56 | 57 | RESOLVE_STUB(sceKernelStopUnloadModule, 0x2415F8A4); 58 | RESOLVE_STUB(sceKernelFindMemBlockByAddr, 0xA33B99D1); 59 | RESOLVE_STUB(sceKernelFreeMemBlock, 0xA91E15EE); 60 | RESOLVE_STUB(sceKernelGetMemBlockBase, 0xB8EF5818); 61 | RESOLVE_STUB(sceKernelAllocMemBlock, 0xB9D5EBDE); 62 | RESOLVE_STUB(sceKernelExitDeleteThread, 0x1D17DECF); 63 | RESOLVE_STUB(sceKernelGetModuleList, 0x2EF2581F); 64 | RESOLVE_STUB(sceKernelGetModuleInfo, 0x36585DAF); 65 | RESOLVE_STUB(sceIoWrite, 0x11FED231); 66 | RESOLVE_STUB(sceIoClose, 0xF5C6F098); 67 | RESOLVE_STUB(sceIoRead, 0x713523E1); 68 | RESOLVE_STUB(sceIoOpen, 0x6C60AC61); 69 | RESOLVE_STUB(sceIoLseek, 0x99BA173E); 70 | RESOLVE_STUB(sceKernelStartThread, 0xF08DE149); 71 | RESOLVE_STUB(sceKernelCreateThread, 0xC5C11EE7); 72 | RESOLVE_STUB(sceKernelLoadModule, 0xBBE82155); 73 | RESOLVE_STUB(sceKernelUnloadModule, 0x1987920E); 74 | RESOLVE_STUB(sceClibVsnprintf, 0xFA6BE467); 75 | RESOLVE_STUB(sceKernelWaitThreadEnd, 0xDDB395A9); 76 | 77 | #undef RESOLVE_STUB 78 | } 79 | 80 | int 81 | uvl_scefuncs_resolve_appmgruser(void) 82 | { 83 | PsvUID mod_list[MAX_LOADED_MODS]; 84 | u32_t num_loaded = MAX_LOADED_MODS; 85 | int i; 86 | 87 | if (sceKernelGetModuleList (0xFF, mod_list, &num_loaded) < 0) 88 | { 89 | return -1; 90 | } 91 | for (i = 0; i < num_loaded; i++) 92 | { 93 | loaded_module_info_t m_mod_info; 94 | module_info_t *mod_info; 95 | module_exports_t *exports; 96 | 97 | m_mod_info.size = sizeof (loaded_module_info_t); // should be 440 98 | if (sceKernelGetModuleInfo (mod_list[i], &m_mod_info) < 0) 99 | { 100 | continue; 101 | } 102 | if (strcmp(m_mod_info.module_name, "SceDriverUser") != 0) 103 | { 104 | continue; 105 | } 106 | if ((mod_info = uvl_find_module_info (&m_mod_info)) == NULL) 107 | { 108 | continue; 109 | } 110 | for (exports = (module_exports_t*)((u32_t)m_mod_info.segments[0].vaddr + mod_info->ent_top); 111 | (u32_t)exports < ((u32_t)m_mod_info.segments[0].vaddr + mod_info->ent_end); exports++) 112 | { 113 | int j; 114 | int offset = 0; 115 | 116 | for(j = 0; j < exports->num_functions; j++, offset++) 117 | { 118 | if (exports->nid_table[offset] == 0x906154de) { 119 | resolve_entry_t res_entry; 120 | res_entry.type = RESOLVE_TYPE_FUNCTION; 121 | res_entry.nid = exports->nid_table[offset]; 122 | res_entry.value.func_ptr = exports->entry_table[offset]; 123 | uvl_resolve_entry_to_import_stub(&res_entry, &sceAppMgrGetVs0UserModuleDrive); 124 | return 0; 125 | } 126 | } 127 | } 128 | } 129 | return -1; 130 | } 131 | 132 | int 133 | uvl_resolve_stub_by_nid(void* stub, 134 | u32_t nid) 135 | { 136 | resolve_entry_t* entry = uvl_resolve_table_get(nid); 137 | 138 | if (uvl_resolve_entry_to_import_stub(entry, stub) < 0) 139 | { 140 | return -1; 141 | } 142 | } 143 | 144 | void 145 | uvl_scefuncs_resolve_debugnet(void) 146 | { 147 | uvl_resolve_stub_by_nid(&sceNetSendto, 0x52db31d5); 148 | uvl_resolve_stub_by_nid(&sceNetShowNetstat, 0x338edc2e); 149 | uvl_resolve_stub_by_nid(&sceNetInit, 0xeb03e265); 150 | uvl_resolve_stub_by_nid(&sceNetCtlInit, 0x495ca1db); 151 | uvl_resolve_stub_by_nid(&sceNetCtlInetGetInfo, 0xb26d07f3); 152 | uvl_resolve_stub_by_nid(&sceNetInetPton, 0xd5eeb048); 153 | uvl_resolve_stub_by_nid(&sceNetSocket, 0xf084fce3); 154 | uvl_resolve_stub_by_nid(&sceNetSetsockopt, 0x065505ca); 155 | uvl_resolve_stub_by_nid(&sceNetHtons, 0x9fa3207b); 156 | uvl_resolve_stub_by_nid(&sceNetCtlTerm, 0xcd188648); 157 | uvl_resolve_stub_by_nid(&sceNetTerm, 0xea3cc286); 158 | } 159 | -------------------------------------------------------------------------------- /scefuncs.h: -------------------------------------------------------------------------------- 1 | #ifndef UVL_SCEFUNCS 2 | #define UVL_SCEFUNCS 3 | 4 | #include "types.h" 5 | 6 | /** \name IO Constants 7 | * \todo Use toolchain 8 | * @{ 9 | */ 10 | #define PSP2_SEEK_SET 0 11 | #define PSP2_SEEK_CUR 1 12 | #define PSP2_SEEK_END 2 13 | #define PSP2_O_RDONLY 0x0001 14 | #define PSP2_O_WRONLY 0x0002 15 | #define PSP2_O_RDWR (PSP2_O_RDONLY | PSP2_O_WRONLY) 16 | #define PSP2_O_NBLOCK 0x0004 17 | #define PSP2_O_DIROPEN 0x0008 18 | #define PSP2_O_APPEND 0x0100 19 | #define PSP2_O_CREAT 0x0200 20 | #define PSP2_O_TRUNC 0x0400 21 | #define PSP2_O_EXCL 0x0800 22 | #define PSP2_O_NOWAIT 0x8000 23 | #define PSP2_STM_RWXU 00700 24 | #define PSP2_STM_RUSR 00400 25 | #define PSP2_STM_WUSR 00200 26 | #define PSP2_STM_XUSR 00100 27 | #define PSP2_STM_RWU (PSP2_STM_RUSR | PSP2_STM_WUSR) 28 | #define PSP2_STM_RU (PSP2_STM_RUSR) 29 | /** @}*/ 30 | 31 | #ifdef GENERATE_STUBS 32 | #define STUB_FUNCTION_FILLED(type, name, high, low) \ 33 | type __attribute__((naked, section(".sceStub.text.filled"))) name () \ 34 | { \ 35 | __asm__ ("movw r12, #" #low" \n" \ 36 | "movt r12, #" #high" \n" \ 37 | "bx r12\n" \ 38 | "nop"); \ 39 | } 40 | #else 41 | #define STUB_FUNCTION_FILLED(type, name, high, low) type __attribute__((naked)) name () 42 | #endif 43 | 44 | #ifdef GENERATE_STUBS 45 | #define STUB_FUNCTION(type, name) \ 46 | type __attribute__((naked, section(".sceStub.text.uvl"))) name () \ 47 | { \ 48 | __asm__ ("movw r0, #0xffff\n" \ 49 | "movt r0, #0xffff\n" \ 50 | "bx lr\n" \ 51 | "nop"); \ 52 | } 53 | #else 54 | #define STUB_FUNCTION(type, name) type __attribute__((naked)) name () 55 | #endif 56 | 57 | // functions for writing executable code 58 | int sceKernelAllocCodeMemBlock(const char *name, unsigned int length); 59 | 60 | // some names from https://github.com/pspdev/pspsdk 61 | STUB_FUNCTION(int, sceKernelStopUnloadModule); 62 | STUB_FUNCTION(int, sceKernelFindMemBlockByAddr); 63 | STUB_FUNCTION(int, sceKernelFreeMemBlock); 64 | STUB_FUNCTION(int, sceKernelGetMemBlockBase); 65 | STUB_FUNCTION(int, sceKernelAllocMemBlock); 66 | STUB_FUNCTION(int, sceKernelExitDeleteThread); 67 | STUB_FUNCTION(int, sceKernelGetModuleList); 68 | STUB_FUNCTION(int, sceKernelGetModuleInfo); 69 | STUB_FUNCTION(PsvSSize, sceIoWrite); 70 | STUB_FUNCTION(int, sceIoClose); 71 | STUB_FUNCTION(PsvSSize, sceIoRead); 72 | STUB_FUNCTION(PsvUID, sceIoOpen); 73 | STUB_FUNCTION(PsvOff, sceIoLseek); 74 | STUB_FUNCTION(int, sceKernelStartThread); 75 | STUB_FUNCTION(PsvUID, sceKernelCreateThread); 76 | STUB_FUNCTION(PsvUID, sceKernelLoadModule); 77 | STUB_FUNCTION(int, sceKernelUnloadModule); 78 | STUB_FUNCTION(int, sceClibVsnprintf); 79 | STUB_FUNCTION(int, sceKernelWaitThreadEnd); 80 | 81 | STUB_FUNCTION(int, sceAppMgrGetVs0UserModuleDrive); 82 | 83 | STUB_FUNCTION(int, sceNetSendto); 84 | STUB_FUNCTION(int, sceNetShowNetstat); 85 | STUB_FUNCTION(int, sceNetInit); 86 | STUB_FUNCTION(int, sceNetCtlInit); 87 | STUB_FUNCTION(int, sceNetCtlInetGetInfo); 88 | STUB_FUNCTION(int, sceNetInetPton); 89 | STUB_FUNCTION(int, sceNetSocket); 90 | STUB_FUNCTION(int, sceNetSetsockopt); 91 | STUB_FUNCTION(u16_t, sceNetHtons); 92 | STUB_FUNCTION(void, sceNetCtlTerm); 93 | STUB_FUNCTION(int, sceNetTerm); 94 | 95 | void uvl_scefuncs_resolve_loader(void *anchor); 96 | int uvl_scefuncs_resolve_appmgruser(void); 97 | void uvl_scefuncs_resolve_debugnet(void); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file types.h 3 | /// \brief Types used in UVLoader 4 | /// 5 | #ifndef UVL_TYPES 6 | #define UVL_TYPES 7 | 8 | /** \name Fixed width integers 9 | * @{ 10 | */ 11 | typedef unsigned char u8_t; ///< Unsigned 8-bit type 12 | typedef unsigned short int u16_t; ///< Unsigned 16-bit type 13 | typedef unsigned int u32_t; ///< Unsigned 32-bit type 14 | typedef unsigned long long int u64_t; ///< Unsigned 64-bit type 15 | typedef char s8_t; ///< Signed 8-bit type 16 | typedef short int s16_t; ///< Signed 16-bit type 17 | typedef int s32_t; ///< Signed 32-bit type 18 | typedef long long int s64_t; ///< Signed 64-bit type 19 | /** @}*/ 20 | 21 | /** \name SCE standard types 22 | * @{ 23 | */ 24 | typedef int PsvUID; ///< PsvUID type 25 | typedef long long int PsvOff; ///< PsvOff type 26 | typedef int PsvSSize; ///< PsvSSize type 27 | /** @}*/ 28 | 29 | // TODO: Make sure void* is 4 bytes 30 | 31 | #define NULL 0 ///< For NULL pointers 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.c - Common library functions 3 | * Copyright 2012 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "config.h" 18 | #include "scefuncs.h" 19 | #include "utils.h" 20 | #include "uvloader.h" 21 | 22 | // Below is stolen from Android's Bionic 23 | 24 | /*- 25 | * Copyright (c) 1990 The Regents of the University of California. 26 | * All rights reserved. 27 | * 28 | * This code is derived from software contributed to Berkeley by 29 | * Chris Torek. 30 | * 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions 33 | * are met: 34 | * 1. Redistributions of source code must retain the above copyright 35 | * notice, this list of conditions and the following disclaimer. 36 | * 2. Redistributions in binary form must reproduce the above copyright 37 | * notice, this list of conditions and the following disclaimer in the 38 | * documentation and/or other materials provided with the distribution. 39 | * 3. Neither the name of the University nor the names of its contributors 40 | * may be used to endorse or promote products derived from this software 41 | * without specific prior written permission. 42 | * 43 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 | * SUCH DAMAGE. 54 | */ 55 | 56 | /* 57 | * sizeof(word) MUST BE A POWER OF TWO 58 | * SO THAT wmask BELOW IS ALL ONES 59 | */ 60 | typedef long word; /* "word" used for optimal copy speed */ 61 | 62 | #define wsize sizeof(word) 63 | #define wmask (wsize - 1) 64 | 65 | /* 66 | * Copy a block of memory, handling overlap. 67 | * This is the routine that actually implements 68 | * (the portable versions of) bcopy, memcpy, and memmove. 69 | */ 70 | void * 71 | memcpy(void *dst0, const void *src0, u32_t length) 72 | { 73 | char *dst = dst0; 74 | const char *src = src0; 75 | u32_t t; 76 | 77 | if (length == 0 || dst == src) /* nothing to do */ 78 | goto done; 79 | 80 | /* 81 | * Macros: loop-t-times; and loop-t-times, t>0 82 | */ 83 | #define TLOOP(s) if (t) TLOOP1(s) 84 | #define TLOOP1(s) do { s; } while (--t) 85 | 86 | if ((unsigned long)dst < (unsigned long)src) { 87 | /* 88 | * Copy forward. 89 | */ 90 | t = (long)src; /* only need low bits */ 91 | if ((t | (long)dst) & wmask) { 92 | /* 93 | * Try to align operands. This cannot be done 94 | * unless the low bits match. 95 | */ 96 | if ((t ^ (long)dst) & wmask || length < wsize) 97 | t = length; 98 | else 99 | t = wsize - (t & wmask); 100 | length -= t; 101 | TLOOP1(*dst++ = *src++); 102 | } 103 | /* 104 | * Copy whole words, then mop up any trailing bytes. 105 | */ 106 | t = length / wsize; 107 | TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); 108 | t = length & wmask; 109 | TLOOP(*dst++ = *src++); 110 | } else { 111 | /* 112 | * Copy backwards. Otherwise essentially the same. 113 | * Alignment works as before, except that it takes 114 | * (t&wmask) bytes to align, not wsize-(t&wmask). 115 | */ 116 | src += length; 117 | dst += length; 118 | t = (long)src; 119 | if ((t | (long)dst) & wmask) { 120 | if ((t ^ (long)dst) & wmask || length <= wsize) 121 | t = length; 122 | else 123 | t &= wmask; 124 | length -= t; 125 | TLOOP1(*--dst = *--src); 126 | } 127 | t = length / wsize; 128 | TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); 129 | t = length & wmask; 130 | TLOOP(*--dst = *--src); 131 | } 132 | done: 133 | return (dst0); 134 | } 135 | 136 | char * 137 | strcpy(char *to, const char *from) 138 | { 139 | char *save = to; 140 | 141 | for (; (*to = *from) != '\0'; ++from, ++to); 142 | return(save); 143 | } 144 | 145 | int memcmp(const void *s1, const void *s2, u32_t n) 146 | { 147 | const unsigned char* p1 = s1; 148 | const unsigned char* end1 = p1 + n; 149 | const unsigned char* p2 = s2; 150 | int d = 0; 151 | 152 | for (;;) { 153 | if (d || p1 >= end1) break; 154 | d = (int)*p1++ - (int)*p2++; 155 | 156 | if (d || p1 >= end1) break; 157 | d = (int)*p1++ - (int)*p2++; 158 | 159 | if (d || p1 >= end1) break; 160 | d = (int)*p1++ - (int)*p2++; 161 | 162 | if (d || p1 >= end1) break; 163 | d = (int)*p1++ - (int)*p2++; 164 | } 165 | return d; 166 | } 167 | 168 | /* 169 | * Compare strings. 170 | */ 171 | int 172 | strcmp(const char *s1, const char *s2) 173 | { 174 | while (*s1 == *s2++) 175 | if (*s1++ == 0) 176 | return (0); 177 | return (*(unsigned char *)s1 - *(unsigned char *)--s2); 178 | } 179 | 180 | int 181 | strncmp(const char *s1, const char *s2, u32_t n) 182 | { 183 | if (n == 0) 184 | return (0); 185 | do { 186 | if (*s1 != *s2++) 187 | return (*(unsigned char *)s1 - *(unsigned char *)--s2); 188 | if (*s1++ == 0) 189 | break; 190 | } while (--n != 0); 191 | return (0); 192 | } 193 | 194 | void* memset(void* dst, int c, u32_t n) 195 | { 196 | char* q = dst; 197 | char* end = q + n; 198 | 199 | for (;;) { 200 | if (q >= end) break; *q++ = (char) c; 201 | if (q >= end) break; *q++ = (char) c; 202 | if (q >= end) break; *q++ = (char) c; 203 | if (q >= end) break; *q++ = (char) c; 204 | } 205 | 206 | return dst; 207 | } 208 | 209 | u32_t 210 | strlen(const char *str) 211 | { 212 | const char *s; 213 | 214 | for (s = str; *s; ++s) 215 | ; 216 | return (s - str); 217 | } 218 | 219 | char * 220 | strchr(const char *str, int c) 221 | { 222 | const char ch = c; 223 | 224 | for (; *str != ch; str++) 225 | if (*str == '\0') 226 | return 0; 227 | return (char *) str; 228 | } 229 | 230 | // Below is stolen from http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm 231 | 232 | #define ALPHABET_LEN 256 233 | #define NOT_FOUND patlen 234 | #define max(a, b) ((a < b) ? b : a) 235 | 236 | void make_delta1(int *delta1, char *pat, int patlen); 237 | int is_prefix(char *word, int wordlen, int pos); 238 | int suffix_length(char *word, int wordlen, int pos); 239 | void make_delta2(int *delta2, char *pat, int patlen); 240 | char* boyer_moore (char *string, u32_t stringlen, char *pat, u32_t patlen); 241 | 242 | // delta1 table: delta1[c] contains the distance between the last 243 | // character of pat and the rightmost occurence of c in pat. 244 | // If c does not occur in pat, then delta1[c] = patlen. 245 | // If c is at string[i] and c != pat[patlen-1], we can 246 | // safely shift i over by delta1[c], which is the minimum distance 247 | // needed to shift pat forward to get string[i] lined up 248 | // with some character in pat. 249 | // this algorithm runs in alphabet_len+patlen time. 250 | void make_delta1(int *delta1, char *pat, int patlen) { 251 | int i; 252 | for (i=0; i < ALPHABET_LEN; i++) { 253 | delta1[i] = NOT_FOUND; 254 | } 255 | for (i=0; i < patlen-1; i++) { 256 | delta1[pat[i]] = patlen-1 - i; 257 | } 258 | } 259 | 260 | // true if the suffix of word starting from word[pos] is a prefix 261 | // of word 262 | int is_prefix(char *word, int wordlen, int pos) { 263 | int i; 264 | int suffixlen = wordlen - pos; 265 | // could also use the strncmp() library function here 266 | for (i = 0; i < suffixlen; i++) { 267 | if (word[i] != word[pos+i]) { 268 | return 0; 269 | } 270 | } 271 | return 1; 272 | } 273 | 274 | // length of the longest suffix of word ending on word[pos]. 275 | // suffix_length("dddbcabc", 8, 4) = 2 276 | int suffix_length(char *word, int wordlen, int pos) { 277 | int i; 278 | // increment suffix length i to the first mismatch or beginning 279 | // of the word 280 | for (i = 0; (word[pos-i] == word[wordlen-1-i]) && (i < pos); i++); 281 | return i; 282 | } 283 | 284 | // delta2 table: given a mismatch at pat[pos], we want to align 285 | // with the next possible full match could be based on what we 286 | // know about pat[pos+1] to pat[patlen-1]. 287 | // 288 | // In case 1: 289 | // pat[pos+1] to pat[patlen-1] does not occur elsewhere in pat, 290 | // the next plausible match starts at or after the mismatch. 291 | // If, within the substring pat[pos+1 .. patlen-1], lies a prefix 292 | // of pat, the next plausible match is here (if there are multiple 293 | // prefixes in the substring, pick the longest). Otherwise, the 294 | // next plausible match starts past the character aligned with 295 | // pat[patlen-1]. 296 | // 297 | // In case 2: 298 | // pat[pos+1] to pat[patlen-1] does occur elsewhere in pat. The 299 | // mismatch tells us that we are not looking at the end of a match. 300 | // We may, however, be looking at the middle of a match. 301 | // 302 | // The first loop, which takes care of case 1, is analogous to 303 | // the KMP table, adapted for a 'backwards' scan order with the 304 | // additional restriction that the substrings it considers as 305 | // potential prefixes are all suffixes. In the worst case scenario 306 | // pat consists of the same letter repeated, so every suffix is 307 | // a prefix. This loop alone is not sufficient, however: 308 | // Suppose that pat is "ABYXCDEYX", and text is ".....ABYXCDEYX". 309 | // We will match X, Y, and find B != E. There is no prefix of pat 310 | // in the suffix "YX", so the first loop tells us to skip forward 311 | // by 9 characters. 312 | // Although superficially similar to the KMP table, the KMP table 313 | // relies on information about the beginning of the partial match 314 | // that the BM algorithm does not have. 315 | // 316 | // The second loop addresses case 2. Since suffix_length may not be 317 | // unique, we want to take the minimum value, which will tell us 318 | // how far away the closest potential match is. 319 | void make_delta2(int *delta2, char *pat, int patlen) { 320 | int p; 321 | int last_prefix_index = patlen-1; 322 | 323 | // first loop 324 | for (p=patlen-1; p>=0; p--) { 325 | if (is_prefix(pat, patlen, p+1)) { 326 | last_prefix_index = p+1; 327 | } 328 | delta2[p] = last_prefix_index + (patlen-1 - p); 329 | } 330 | 331 | // second loop 332 | for (p=0; p < patlen-1; p++) { 333 | int slen = suffix_length(pat, patlen, p); 334 | if (pat[p - slen] != pat[patlen-1 - slen]) { 335 | delta2[patlen-1 - slen] = patlen-1 - p + slen; 336 | } 337 | } 338 | } 339 | 340 | char* boyer_moore (char *string, u32_t stringlen, char *pat, u32_t patlen) { 341 | int i; 342 | int delta1[ALPHABET_LEN]; 343 | int delta2[patlen * sizeof(int)]; 344 | make_delta1(delta1, pat, patlen); 345 | make_delta2(delta2, pat, patlen); 346 | 347 | i = patlen-1; 348 | while (i < stringlen) { 349 | int j = patlen-1; 350 | while (j >= 0 && (string[i] == pat[j])) { 351 | --i; 352 | --j; 353 | } 354 | if (j < 0) { 355 | return (string + i+1); 356 | } 357 | 358 | i += max(delta1[string[i]], delta2[j]); 359 | } 360 | return NULL; 361 | } 362 | 363 | /********************************************//** 364 | * \brief Search for a string in memory 365 | * 366 | * Uses the Boyer-Moore algorithm to search. 367 | * \returns First occurrence of @a needle in 368 | * @a haystack 369 | ***********************************************/ 370 | char* 371 | memstr (char *haystack, ///< Where to search 372 | int h_length, ///< Length of @a haystack 373 | char *needle, ///< String to find 374 | int n_length) ///< Length of @a needle 375 | { 376 | return boyer_moore (haystack, h_length, needle, n_length); 377 | } 378 | 379 | /********************************************//** 380 | * \brief Unsigned integer division 381 | * 382 | * ARM does not have native division support 383 | * \returns Result of operation or zero if 384 | * dividing by zero. 385 | ***********************************************/ 386 | uidiv_result_t 387 | uidiv (u32_t num, ///< Numerator 388 | u32_t dem) ///< Denominator 389 | { 390 | u32_t tmp = dem; 391 | uidiv_result_t ans = {0}; 392 | 393 | if (dem == 0) 394 | { 395 | // TODO: Somehow make error 396 | return ans; 397 | } 398 | 399 | while (tmp <= num >> 1) 400 | { 401 | tmp <<= 1; 402 | } 403 | 404 | do 405 | { 406 | if (num >= tmp) 407 | { 408 | num -= tmp; 409 | ans.quo++; 410 | } 411 | ans.quo <<= 1; 412 | tmp >>= 1; 413 | } while (tmp >= dem); 414 | ans.quo >>= 1; 415 | ans.rem = num; 416 | 417 | return ans; 418 | } 419 | 420 | // thanks naehrwert for the tiny printf 421 | static void _putn(char **p_str, u32_t x, u32_t base, char fill, int fcnt, int upper) 422 | { 423 | char buf[65]; 424 | char *digits; 425 | char *p; 426 | int c = fcnt; 427 | uidiv_result_t div_res; 428 | 429 | if (upper) 430 | digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 431 | else 432 | digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 433 | 434 | if(base > 36) 435 | return; 436 | 437 | p = buf + 64; 438 | *p = 0; 439 | do 440 | { 441 | c--; 442 | div_res = uidiv (x, base); 443 | *--p = digits[div_res.rem]; 444 | x = div_res.quo; 445 | }while(x); 446 | 447 | if(fill != 0) 448 | { 449 | while(c > 0) 450 | { 451 | *--p = fill; 452 | c--; 453 | } 454 | } 455 | 456 | for(; *p != '\0'; *((*p_str)++) = *(p++)); 457 | } 458 | 459 | /********************************************//** 460 | * \brief Simple @c vsprintf 461 | * 462 | * Only supports %c, %s, %u, %x, %X with 463 | * optional zero padding. 464 | * Always returns zero. 465 | ***********************************************/ 466 | int vsprintf (char *str, const char *fmt, va_list ap) 467 | { 468 | char *s; 469 | char c, fill; 470 | int fcnt; 471 | u32_t n; 472 | 473 | while(*fmt) 474 | { 475 | if(*fmt == '%') 476 | { 477 | fmt++; 478 | fill = 0; 479 | fcnt = 0; 480 | if((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') 481 | if(*(fmt+1) >= '0' && *(fmt+1) <= '9') 482 | { 483 | fill = *fmt; 484 | fcnt = *(fmt+1) - '0'; 485 | fmt++; 486 | fmt++; 487 | } 488 | switch(*fmt) 489 | { 490 | case 'c': 491 | c = va_arg(ap, u32_t); 492 | *(str++) = c; 493 | break; 494 | case 's': 495 | s = va_arg(ap, char *); 496 | for(; *s != '\0'; *(str++) = *(s++)); 497 | break; 498 | case 'u': 499 | n = va_arg(ap, u32_t); 500 | _putn(&str, n, 10, fill, fcnt, 0); 501 | break; 502 | case 'x': 503 | n = va_arg(ap, u32_t); 504 | _putn(&str, n, 16, fill, fcnt, 0); 505 | break; 506 | case 'X': 507 | n = va_arg(ap, u32_t); 508 | _putn(&str, n, 16, fill, fcnt, 1); 509 | break; 510 | case '%': 511 | *(str++) = '%'; 512 | break; 513 | case '\0': 514 | goto out; 515 | default: 516 | *(str++) = '%'; 517 | *(str++) = *fmt; 518 | break; 519 | } 520 | } 521 | else 522 | *(str++) = *fmt; 523 | fmt++; 524 | } 525 | 526 | out: 527 | *str = '\0'; 528 | return 0; 529 | } 530 | 531 | /********************************************//** 532 | * \brief Simple @c sprintf 533 | * 534 | * Only supports %c, %s, %u, %x, %X with 535 | * optional zero padding. 536 | * Always returns zero. 537 | ***********************************************/ 538 | int sprintf (char *str, const char *format, ...) 539 | { 540 | va_list arg; 541 | 542 | va_start (arg, format); 543 | vsprintf (str, format, arg); 544 | va_end (arg); 545 | return 0; 546 | } 547 | 548 | static int g_fd_log = 0; 549 | 550 | /********************************************//** 551 | * \brief Sets the logging function 552 | ***********************************************/ 553 | void 554 | vita_init_log () 555 | { 556 | int fd = sceIoOpen (UVL_LOG_PATH, PSP2_O_WRONLY | PSP2_O_CREAT | PSP2_O_TRUNC, PSP2_STM_RWU); 557 | uvl_unlock_mem (); 558 | g_fd_log = fd; 559 | uvl_lock_mem (); 560 | } 561 | 562 | /********************************************//** 563 | * \brief Writes a log entry 564 | * 565 | * Writes log to all places set in options 566 | * including log file, on screen, and console. 567 | ***********************************************/ 568 | void 569 | vita_logf (char *file, ///< Source file of code writing to log 570 | int line, ///< Line number of code writing to log 571 | ...) ///< Format and value(s) to write 572 | { 573 | char processed_line[MAX_LOG_LENGTH]; 574 | char log_line[MAX_LOG_LENGTH]; 575 | va_list arg; 576 | 577 | va_start (arg, line); 578 | // generate log entry content 579 | vsprintf (processed_line, va_arg (arg, const char*), arg); 580 | va_end (arg); 581 | // generate complete log entry 582 | sprintf (log_line, "%s:%u %s\n", file, line, processed_line); 583 | if (g_fd_log > 0) 584 | { 585 | sceIoWrite (g_fd_log, log_line, strlen (log_line)); 586 | } 587 | uvl_debug_log (log_line); 588 | } 589 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file utils.h 3 | /// \brief Common functions 4 | /// \defgroup library Library Functions 5 | /// \brief String and memory functions 6 | /// @{ 7 | /// 8 | #ifndef UVL_UTILS 9 | #define UVL_UTILS 10 | 11 | #include "types.h" 12 | 13 | #ifdef DEBUG 14 | #define DEBUG_LOGGING 1 ///< Enable debug logging 15 | #else 16 | #define DEBUG_LOGGING 0 ///< Disable debug logging 17 | #endif 18 | 19 | #ifndef VERBOSE_LOGGING 20 | #define VERBOSE_LOGGING 0 ///< Disable verbose logging 21 | #else 22 | #undef VERBOSE_LOGGING 23 | #ifndef DEBUG_LOGGING 24 | #define DEBUG_LOGGING 1 ///< Enabled automatically when verbose logging 25 | #endif 26 | #define VERBOSE_LOGGING 1 ///< Enable verbose logging 27 | #endif 28 | 29 | #define MAX_LOG_LENGTH 0x100 ///< Any log entry larger than this will cause a buffer overflow! 30 | #define IF_DEBUG if (DEBUG_LOGGING) ///< Place before calling @c LOG to only show when debugging 31 | #define IF_VERBOSE if (VERBOSE_LOGGING) ///< Place before calling @c LOG to only show when verbose output is enabled 32 | #define LOG(args...) \ 33 | vita_logf (__FILE__, __LINE__, args) ///< Write a log entry 34 | 35 | /** \name stdarg.h functions 36 | * See @c stdarg.h documentation for details. 37 | * @{ 38 | */ 39 | typedef __builtin_va_list va_list; 40 | #define va_start(ap, v) __builtin_va_start(ap, v) 41 | #define va_arg(ap, type) __builtin_va_arg(ap, type) 42 | #define va_end(ap) __builtin_va_end(ap) 43 | /** @}*/ 44 | 45 | /** \brief Division result 46 | * \sa uidiv 47 | */ 48 | typedef struct uidiv_result { 49 | u32_t quo; ///< Quotient 50 | u32_t rem; ///< Remainder 51 | } uidiv_result_t; 52 | 53 | // string.h from libc 54 | /* 55 | * Copyright (C) 2008 The Android Open Source Project 56 | * All rights reserved. 57 | * 58 | * Redistribution and use in source and binary forms, with or without 59 | * modification, are permitted provided that the following conditions 60 | * are met: 61 | * * Redistributions of source code must retain the above copyright 62 | * notice, this list of conditions and the following disclaimer. 63 | * * Redistributions in binary form must reproduce the above copyright 64 | * notice, this list of conditions and the following disclaimer in 65 | * the documentation and/or other materials provided with the 66 | * distribution. 67 | * 68 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 69 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 70 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 71 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 72 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 73 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 74 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 75 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 76 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 77 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 78 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 79 | * SUCH DAMAGE. 80 | */ 81 | 82 | /** \name string.h functions 83 | * See @c string.h documention for details. 84 | * @{ 85 | */ 86 | void* memcpy (void *destination, const void *source, u32_t num); 87 | char* strcpy (char *destination, const char *source); 88 | int memcmp (const void *ptr1, const void *ptr2, u32_t num); 89 | int strcmp (const char *str1, const char *str2); 90 | int strncmp (const char *str1, const char *str2, u32_t num); 91 | void* memset (void *ptr, int value, u32_t num); 92 | u32_t strlen (const char *str); 93 | char* strchr(const char *str, int c); 94 | 95 | /** @}*/ 96 | 97 | /** \name stdio.h functions 98 | * See @c stdio.h documention for details. 99 | * @{ 100 | */ 101 | int vsprintf (char *str, const char *fmt, va_list ap); 102 | int sprintf (char *str, const char *format, ...); 103 | /** @}*/ 104 | 105 | /** \name Additional functions 106 | * @{ 107 | */ 108 | char* memstr (char *haystack, int h_length, char *needle, int n_length); 109 | uidiv_result_t uidiv (u32_t num, u32_t dem); 110 | void vita_init_log (); 111 | void vita_logf (char *file, int line, ...); 112 | /** @}*/ 113 | 114 | #endif 115 | /// @} 116 | -------------------------------------------------------------------------------- /uvloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uvloader.c - Userland Vita Loader entry point 3 | * Copyright 2012 Yifan Lu 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "cleanup.h" 18 | #include "config.h" 19 | #include "load.h" 20 | #include "resolve.h" 21 | #include "scefuncs.h" 22 | #include "utils.h" 23 | #include "uvloader.h" 24 | 25 | #include "debugnet.h" 26 | 27 | // make sure code is PIE 28 | #ifndef __PIE__ 29 | #error "Must compile with -fPIE" 30 | #endif 31 | 32 | static uvl_context_t *g_context; 33 | static debug_log_func g_debug_log; 34 | 35 | static void uvl_init_from_context (uvl_context_t *ctx); 36 | 37 | /********************************************//** 38 | * \brief Starting point from exploit 39 | * 40 | * Call this from your exploit to run UVLoader. 41 | * It will first cache all loaded modules and 42 | * attempt to resolve its own NIDs which 43 | * should only depend on sceLibKernel. 44 | * \returns Zero on success, otherwise error 45 | ***********************************************/ 46 | int START_SECTION 47 | uvl_start (uvl_context_t *ctx) ///< Pass in context information 48 | { 49 | uvl_init_from_context (ctx); 50 | uvl_scefuncs_resolve_loader (ctx->libkernel_anchor); 51 | uvl_scefuncs_resolve_appmgruser(); 52 | vita_init_log (); 53 | LOG ("UVLoader %u.%u.%u started.", UVL_VER_MAJOR, UVL_VER_MINOR, UVL_VER_REV); 54 | return uvl_start_load (); 55 | } 56 | 57 | /********************************************//** 58 | * \brief Sets up hooks from context buffer 59 | ***********************************************/ 60 | static void 61 | uvl_init_from_context (uvl_context_t *ctx) ///< Context buffer 62 | { 63 | ctx->psvUnlockMem (); 64 | g_context = ctx; 65 | g_debug_log = &uvl_debug_log_psm; 66 | ctx->psvLockMem (); 67 | } 68 | 69 | /********************************************//** 70 | * \brief From context buffer 71 | ***********************************************/ 72 | void * 73 | uvl_alloc_code_mem (unsigned int *p_len) 74 | { 75 | return g_context->psvCodeAllocMem (p_len); 76 | } 77 | 78 | /********************************************//** 79 | * \brief From context buffer 80 | ***********************************************/ 81 | void 82 | uvl_unlock_mem (void) 83 | { 84 | g_context->psvUnlockMem (); 85 | } 86 | 87 | /********************************************//** 88 | * \brief From context buffer 89 | ***********************************************/ 90 | void 91 | uvl_lock_mem (void) 92 | { 93 | g_context->psvLockMem (); 94 | } 95 | 96 | /********************************************//** 97 | * \brief From context buffer 98 | ***********************************************/ 99 | void 100 | uvl_flush_icache (void *addr, unsigned int len) 101 | { 102 | g_context->psvFlushIcache (addr, len); 103 | } 104 | 105 | /********************************************//** 106 | * \brief From context buffer 107 | ***********************************************/ 108 | int 109 | uvl_debug_log_psm (const char *line) 110 | { 111 | if (g_context->logline) 112 | return g_context->logline (line); 113 | else 114 | return -1; 115 | } 116 | 117 | void 118 | uvl_set_debug_log_func(debug_log_func func) 119 | { 120 | uvl_unlock_mem(); 121 | g_debug_log = func; 122 | uvl_lock_mem(); 123 | } 124 | 125 | int 126 | uvl_debug_log (const char *line) 127 | { 128 | return g_debug_log(line); 129 | } 130 | 131 | /********************************************//** 132 | * \brief printf proxy 133 | * 134 | * Used for exporting debug logging 135 | ***********************************************/ 136 | static int 137 | printf (const char *format, ...) 138 | { 139 | char buffer[MAX_LOG_LENGTH]; 140 | va_list arg; 141 | 142 | va_start (arg, format); 143 | sceClibVsnprintf (buffer, MAX_LOG_LENGTH, format, arg); 144 | va_end (arg); 145 | 146 | g_debug_log(buffer); 147 | return 0; 148 | } 149 | 150 | /********************************************//** 151 | * \brief Add custom NID entries for UVL 152 | ***********************************************/ 153 | void 154 | uvl_add_uvl_exports (void) 155 | { 156 | resolve_entry_t entry; 157 | entry.nid = UVL_EXIT_NID; 158 | entry.type = RESOLVE_TYPE_FUNCTION; 159 | entry.value.func_ptr = uvl_exit; 160 | uvl_resolve_table_add (&entry); 161 | entry.nid = UVL_CODE_ALLOC_NID; 162 | entry.type = RESOLVE_TYPE_FUNCTION; 163 | entry.value.func_ptr = uvl_alloc_code_mem; 164 | uvl_resolve_table_add (&entry); 165 | entry.nid = UVL_CODE_UNLOCK_NID; 166 | entry.type = RESOLVE_TYPE_FUNCTION; 167 | entry.value.func_ptr = uvl_unlock_mem; 168 | uvl_resolve_table_add (&entry); 169 | entry.nid = UVL_CODE_LOCK_NID; 170 | entry.type = RESOLVE_TYPE_FUNCTION; 171 | entry.value.func_ptr = uvl_lock_mem; 172 | uvl_resolve_table_add (&entry); 173 | entry.nid = UVL_CODE_FLUSH_NID; 174 | entry.type = RESOLVE_TYPE_FUNCTION; 175 | entry.value.func_ptr = uvl_flush_icache; 176 | uvl_resolve_table_add (&entry); 177 | entry.nid = UVL_DEBUG_LOG_NID; 178 | entry.type = RESOLVE_TYPE_FUNCTION; 179 | entry.value.func_ptr = uvl_debug_log; 180 | uvl_resolve_table_add (&entry); 181 | entry.nid = UVL_PRINTF_NID; 182 | entry.type = RESOLVE_TYPE_FUNCTION; 183 | entry.value.func_ptr = printf; 184 | uvl_resolve_table_add (&entry); 185 | entry.nid = UVL_LOAD_NID; 186 | entry.type = RESOLVE_TYPE_FUNCTION; 187 | entry.value.func_ptr = uvl_load; 188 | uvl_resolve_table_add (&entry); 189 | 190 | entry.nid = UVL_LOG_WRITE_NID; 191 | entry.type = RESOLVE_TYPE_FUNCTION; 192 | entry.value.func_ptr = uvl_log_write; 193 | uvl_resolve_table_add(&entry); 194 | } 195 | 196 | /********************************************//** 197 | * \brief Main function. Builds resolves and load. 198 | * 199 | * \returns Zero on success, otherwise error 200 | ***********************************************/ 201 | int 202 | uvl_start_load () 203 | { 204 | IF_DEBUG LOG ("Initializing resolve table."); 205 | if (uvl_resolve_table_initialize () < 0) 206 | { 207 | LOG ("Failed to initialize resolve table."); 208 | return -1; 209 | } 210 | IF_DEBUG LOG ("Filling resolve table."); 211 | if (uvl_resolve_add_all_modules (RESOLVE_MOD_IMPS | RESOLVE_MOD_EXPS | RESOLVE_IMPS_SVC_ONLY | RESOLVE_RELOAD_MOD) < 0) 212 | { 213 | LOG ("Cannot cache all loaded entries."); 214 | return -1; 215 | } 216 | IF_DEBUG LOG ("Adding UVL imports."); 217 | uvl_add_uvl_exports (); 218 | 219 | if (g_context->use_debugnet) 220 | { 221 | IF_DEBUG LOG("Initializing DebugNet logging..."); 222 | if (debugNetSetup() < 0) 223 | { 224 | LOG("Failed to set up DebugNet."); 225 | } 226 | } 227 | 228 | uvl_pre_clean(); 229 | 230 | IF_DEBUG LOG ("Loading homebrew."); 231 | if (uvl_load (UVL_HOMEBREW_PATH) < 0) 232 | { 233 | return -1; 234 | } 235 | IF_DEBUG LOG ("Cleaning up."); 236 | uvl_resolve_table_destroy (); 237 | return 0; 238 | } 239 | 240 | /********************************************//** 241 | * \brief Loads a executable at path 242 | * 243 | * Starts a new thread with the homebrew 244 | * loaded. Waits until the homebrew exits and 245 | * returns. 246 | * \returns Thread ID on success, otherwise error 247 | ***********************************************/ 248 | int 249 | uvl_load (const char *path) 250 | { 251 | char data_blob[LOADED_INFO_SIZE]; 252 | uvl_loaded_t *loaded; 253 | int (*start)(int, void *); 254 | int ret_value; 255 | PsvUID tid; 256 | int i; 257 | 258 | loaded = (uvl_loaded_t *)data_blob; 259 | IF_DEBUG LOG ("Loading homebrew"); 260 | if (uvl_load_exe (path, (void**)&start, loaded) < 0) 261 | { 262 | LOG ("Cannot load homebrew."); 263 | return -1; 264 | } 265 | IF_DEBUG LOG ("Starting homebrew: entry at 0x%08X", start); 266 | tid = sceKernelCreateThread ("homebrew", start, 0, 0x00040000, 0, 0x00070000, NULL); 267 | if (tid < 0) 268 | { 269 | LOG ("Cannot create thread."); 270 | return -1; 271 | } 272 | loaded->tid = tid; 273 | IF_DEBUG LOG ("Starting new thread."); 274 | if (sceKernelStartThread (tid, 0, NULL) < 0) 275 | { 276 | LOG ("Cannot start thread."); 277 | return -1; 278 | } 279 | IF_DEBUG LOG ("Homebrew running..."); 280 | if (sceKernelWaitThreadEnd (tid, &ret_value, NULL) < 0) 281 | { 282 | LOG ("Failed to wait for thread to exit."); 283 | } 284 | IF_DEBUG LOG ("Homebrew exited with value 0x%08X", ret_value); 285 | 286 | // free segments 287 | for (i = 0; i < loaded->numsegs; i++) 288 | { 289 | sceKernelFreeMemBlock (loaded->segs[i]); 290 | } 291 | 292 | return 0; 293 | } 294 | 295 | /********************************************//** 296 | * \brief Exiting point for loaded application 297 | * 298 | * This is hooked by the loaded application to 299 | * terminate the process early. The call is 300 | * not needed in normal operations. 301 | * For this reason, you should not add any 302 | * cleanup code here. 303 | * \returns Zero on success, otherwise error 304 | ***********************************************/ 305 | void 306 | uvl_exit (int status) 307 | { 308 | sceKernelExitDeleteThread (0); 309 | } 310 | 311 | /********************************************//** 312 | * \brief Write to UVL log 313 | * 314 | * \returns Zero on success, otherwise error 315 | ***********************************************/ 316 | int 317 | uvl_log_write(const void* buffer, unsigned int size) 318 | { 319 | return debugNetSend(buffer, size); 320 | } 321 | -------------------------------------------------------------------------------- /uvloader.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file uvloader.h 3 | /// \brief Userland Vita Loader startup 4 | /// \defgroup uvloader UVLoader 5 | /// \brief Startup and hooks 6 | /// @{ 7 | /// 8 | #ifndef UVL_MAIN 9 | #define UVL_MAIN 10 | 11 | #ifdef UVLOADER 12 | #include "types.h" 13 | 14 | #define START_SECTION __attribute__ ((section (".text.start"))) 15 | #define UVL_EXIT_NID 0x826BBBAF ///< NID of C exit() call 16 | #define UVL_PRINTF_NID 0x9A004680 ///< NID of C printf() call 17 | #define UVL_CODE_ALLOC_NID 0xBCEAB831 ///< uvl_alloc_code_mem 18 | #define UVL_CODE_UNLOCK_NID 0x98D1C91D ///< uvl_unlock_mem 19 | #define UVL_CODE_LOCK_NID 0xEEC99826 ///< uvl_lock_mem 20 | #define UVL_CODE_FLUSH_NID 0xC85B400C ///< uvl_flush_icache 21 | #define UVL_DEBUG_LOG_NID 0xD4F59028 ///< uvl_debug_log 22 | #define UVL_LOAD_NID 0xE8E92954 ///< uvl_load 23 | 24 | #define UVL_LOG_WRITE_NID 0xC1EE36CE ///< uvl_log_write 25 | 26 | #define LOADED_INFO_SIZE 0x1000 ///< Must be page aligned 27 | 28 | /** \name UVLoader version information 29 | * @{ 30 | */ 31 | #define UVL_VER_MAJOR 1 ///< Major version 32 | #define UVL_VER_MINOR 2 ///< Minor version 33 | #define UVL_VER_REV 0 ///< Revision 34 | /** @}*/ 35 | 36 | /** 37 | * \brief UVLoader bootstrap information 38 | * 39 | * External data passed to start of UVLoader 40 | * to aid in locating functions and bypassing 41 | * ASLR. 42 | */ 43 | typedef struct uvl_context 44 | { 45 | void *(*psvCodeAllocMem)(unsigned int *p_len); ///< Allocate code block 46 | void (*psvUnlockMem)(void); ///< Unlock code block 47 | void (*psvLockMem)(void); ///< Relock code block 48 | void (*psvFlushIcache)(void *, unsigned int); ///< Flush Icache 49 | int (*logline)(const char *); ///< Debug logging (optional) 50 | void *libkernel_anchor; ///< Any imported SceLibKernel function 51 | int use_debugnet; ///< Use debugnet logging 52 | } uvl_context_t; 53 | 54 | /** 55 | * \brief Callback exit function 56 | */ 57 | typedef void (*uvl_exit_cb_t)(int status); 58 | 59 | /** 60 | * \brief Loaded application information 61 | * 62 | * Information on the loaded application. 63 | */ 64 | typedef struct uvl_loaded 65 | { 66 | PsvUID tid; ///< UID of running thread 67 | int stack_size; ///< Stack size of loaded application 68 | int thread_priority; ///< Priority of loaded application 69 | int numsegs; ///< Number of elements in array below 70 | PsvUID segs[0]; ///< Array of memory segments allocated 71 | } uvl_loaded_t; 72 | 73 | int START_SECTION uvl_start (uvl_context_t *ctx); 74 | int uvl_start_load (); 75 | 76 | #endif 77 | 78 | /** \name UVLoader API Exports 79 | * @{ 80 | */ 81 | void *uvl_alloc_code_mem (unsigned int *p_len); 82 | void uvl_unlock_mem (); 83 | void uvl_lock_mem (); 84 | void uvl_flush_icache (void *addr, unsigned int len); 85 | int uvl_debug_log_psm (const char *line); 86 | int uvl_debug_log (const char *line); 87 | int uvl_load (const char *path); 88 | void uvl_exit (int status); 89 | 90 | int uvl_log_write(const void* buffer, unsigned int size); 91 | 92 | typedef int(*debug_log_func)(const char* line); 93 | void uvl_set_debug_log_func(debug_log_func func); 94 | /** @}*/ 95 | 96 | #endif 97 | /// @} 98 | -------------------------------------------------------------------------------- /uvloader.json: -------------------------------------------------------------------------------- 1 | { 2 | "UVLoader": { 3 | "nid": 29503324, 4 | "modules": { 5 | "UVLoader": { 6 | "nid": 222466649, 7 | "kernel": false, 8 | "functions": { 9 | "uvl_alloc_code_mem": 3169499185, 10 | "uvl_debug_log": 3572863016, 11 | "uvl_exit": 2188098479, 12 | "uvl_flush_icache": 3361423372, 13 | "uvl_load": 3907594580, 14 | "uvl_lock_mem": 4006189094, 15 | "uvl_log_write": 3253614286, 16 | "uvl_unlock_mem": 2563885341 17 | }, 18 | "variables": { 19 | } 20 | } 21 | } 22 | } 23 | } 24 | --------------------------------------------------------------------------------