diff --git a/Makefile b/Makefile index 48f581a..69fd673 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ OBJS += $(FEXCSRCS:.c=.o) $(FEXCPPSRCS:.cpp=.o) RESOURCES_PNG = resources/battery.png resources/battery_bar_green.png resources/battery_bar_red.png RESOURCES_TXT = resources/english_us_translation.txt -OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) +PAYLOAD_BIN = payload/payload.bin +OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) $(PAYLOAD_BIN:.bin=.o) #stubs.o include this crashes fex!!! @@ -52,6 +53,8 @@ $(TARGET).elf: $(OBJS) $(PREFIX)-ld -r -b binary -o $@ $^ %.o: %.txt $(PREFIX)-ld -r -b binary -o $@ $^ +%.o: %.bin + $(PREFIX)-ld -r -b binary -o $@ $^ clean: @rm -rf $(TARGET).velf $(TARGET).elf $(OBJS) diff --git a/homebrew.c b/homebrew.c index 56260eb..99c67d8 100644 --- a/homebrew.c +++ b/homebrew.c @@ -37,7 +37,8 @@ int sceKernelCreateLwMutex(void *work, const char *name, SceUInt attr, int initCount, void *option); int sceKernelDeleteLwMutex(void *work); -static int launch_counter = 0; +static void *code_memory = NULL; +static SceUID code_blockid = INVALID_UID; static void *uvl_backup = NULL; static uint32_t uvl_addr = 0; @@ -93,6 +94,12 @@ SceModuleInfo *getElfModuleInfo(void *buf) { return (SceModuleInfo *)((uint32_t)buf + program[index].p_offset + offset); } +void initCodeMemory() { + unsigned int length = MAX_CODE_SIZE; + code_memory = uvl_alloc_code_mem(&length); + code_blockid = sceKernelFindMemBlockByAddr(code_memory, 0); +} + void initHomebrewPatch() { force_exit = 0; exited = 0; @@ -129,8 +136,6 @@ void initHomebrewPatch() { } void loadHomebrew(char *file) { - debugPrintf("%d. launch\n", launch_counter++); - // Finish netdbg netdbg_fini(); @@ -147,6 +152,9 @@ void loadHomebrew(char *file) { // Init initVita2dLib(); initSceAppUtil(); + + // Init netdbg + netdbg_init(); } void finishGxm() { @@ -744,8 +752,22 @@ int sceKernelGetMemBlockBasePatchedUVL(SceUID uid, void **basep) { return res; } +SceUID sceKernelFindMemBlockByAddrPatchedUVL(const void *addr, SceSize size) { + debugPrintf("%s 0x%08X\n", __FUNCTION__, code_blockid); + return code_blockid; +} + +int sceKernelFreeMemBlockPatchedUVL(SceUID uid) { + debugPrintf("%s 0x%08X\n", __FUNCTION__, uid); + + if (uid == code_blockid) + return 0; + + return sceKernelFreeMemBlock(uid); +} + SceUID sceIoOpenPatchedUVL(const char *file, int flags, SceMode mode) { - debugPrintf("%s\n", __FUNCTION__); + debugPrintf("%s %s\n", __FUNCTION__, file); return sceIoOpen(file, flags, mode); } @@ -772,13 +794,15 @@ int sceIoClosePatchedUVL(SceUID fd) { PatchValue patches_uvl[] = { { -1, (uint32_t)&sceKernelAllocMemBlock, sceKernelAllocMemBlockPatchedUVL }, { -1, (uint32_t)&sceKernelGetMemBlockBase, sceKernelGetMemBlockBasePatchedUVL }, + { -1, (uint32_t)&sceKernelFindMemBlockByAddr, sceKernelFindMemBlockByAddrPatchedUVL }, + { -1, (uint32_t)&sceKernelFreeMemBlock, sceKernelFreeMemBlockPatchedUVL }, { -1, (uint32_t)&sceKernelCreateThread, sceKernelCreateThreadPatchedUVL }, { -1, (uint32_t)&sceKernelWaitThreadEnd, sceKernelWaitThreadEndPatchedUVL }, { -1, (uint32_t)&sceIoOpen, sceIoOpenPatchedUVL }, { -1, (uint32_t)&sceIoLseek, sceIoLseekPatchedUVL }, - { -1, (uint32_t)&sceIoRead, sceIoReadPatchedUVL }, + { -1, (uint32_t)&sceIoRead, sceIoReadPatchedUVL }, // COULD NOT BE PATCHED, DIFFERENT NID { -1, (uint32_t)&sceIoWrite, sceIoWritePatchedUVL }, - { -1, (uint32_t)&sceIoClose, sceIoClosePatchedUVL }, + { -1, (uint32_t)&sceIoClose, sceIoClosePatchedUVL }, // COULD NOT BE PATCHED, DIFFERENT NID }; #define N_UVL_PATCHES (sizeof(patches_uvl) / sizeof(PatchValue)) @@ -799,7 +823,7 @@ void PatchUVL() { int count = 0; uint32_t i = 0; - while (i < UVL_SIZE && count < N_UVL_PATCHES) { + while (i < MAX_UVL_SIZE && count < N_UVL_PATCHES) { uint32_t addr = uvl_addr + i; uint32_t value = extractStub(addr); @@ -814,6 +838,9 @@ void PatchUVL() { i += ((j == N_UVL_PATCHES) ? 0x4 : 0x10); } + + // Make uvl_alloc_code_mem return 0 + makeThumbDummyFunction0(extractFunctionStub((uint32_t)&uvl_alloc_code_mem) & ~0x1); } void getUVLTextAddr() { @@ -824,8 +851,8 @@ void getUVLTextAddr() { void backupUVL() { if (!uvl_backup) { - uvl_backup = malloc(UVL_SIZE); - memcpy(uvl_backup, (void *)uvl_addr, UVL_SIZE); + uvl_backup = malloc(MAX_UVL_SIZE); + memcpy(uvl_backup, (void *)uvl_addr, MAX_UVL_SIZE); } } @@ -833,10 +860,10 @@ void restoreUVL() { if (uvl_backup) { uvl_unlock_mem(); - memcpy((void *)uvl_addr, uvl_backup, UVL_SIZE); + memcpy((void *)uvl_addr, uvl_backup, MAX_UVL_SIZE); uvl_lock_mem(); - uvl_flush_icache((void *)uvl_addr, UVL_SIZE); + uvl_flush_icache((void *)uvl_addr, MAX_UVL_SIZE); free(uvl_backup); uvl_backup = NULL; diff --git a/homebrew.h b/homebrew.h index 136cc6d..573e8ea 100644 --- a/homebrew.h +++ b/homebrew.h @@ -41,7 +41,8 @@ } \ } -#define UVL_SIZE 0x100000 +#define MAX_CODE_SIZE 12 * 1024 * 1024 +#define MAX_UVL_SIZE 1 * 1024 * 1024 #define INVALID_UID -1 @@ -63,6 +64,8 @@ typedef struct { void *function; } PatchValue; +void initCodeMemory(); + int isValidElf(char *file); void loadHomebrew(char *file); diff --git a/init.c b/init.c index 6ab4ef9..557bda2 100644 --- a/init.c +++ b/init.c @@ -19,6 +19,7 @@ #include "main.h" #include "init.h" #include "file.h" +#include "utils.h" #include "module.h" extern unsigned char _binary_resources_battery_png_start; @@ -266,9 +267,6 @@ int findScePafFunctions() { uint32_t scePowerSetGpuClockFrequencyAddr = findModuleImportByInfo(mod_info, text_addr, "ScePower", 0x717DB06C) - text_addr; - uint32_t sceKernelOpenMemBlockAddr = findModuleImportByInfo(mod_info, text_addr, "SceSysmem", 0x8EB8DFBB) - text_addr; - uint32_t sceKernelCloseMemBlockAddr = findModuleImportByInfo(mod_info, text_addr, "SceSysmem", 0xB680E3A0) - text_addr; - uint32_t sceKernelGetSystemSwVersionAddr = findModuleImportByInfo(mod_info, text_addr, "SceModulemgr", 0x5182E212) - text_addr; uint32_t sceKernelGetModelForCDialogAddr = findModuleImportByInfo(mod_info, text_addr, "SceSysmem", 0xA2CB322F) - text_addr; @@ -288,9 +286,6 @@ int findScePafFunctions() { if (findModuleByName(modname, &text_addr, &text_size) == 0) return -2; - copyStub((uint32_t)&sceKernelOpenMemBlock, (void *)text_addr + sceKernelOpenMemBlockAddr); - copyStub((uint32_t)&sceKernelCloseMemBlock, (void *)text_addr + sceKernelCloseMemBlockAddr); - copyStub((uint32_t)&sceKernelGetSystemSwVersion, (void *)text_addr + sceKernelGetSystemSwVersionAddr); copyStub((uint32_t)&sceKernelGetModelForCDialog, (void *)text_addr + sceKernelGetModelForCDialogAddr); diff --git a/main.c b/main.c index 40291b3..1627803 100644 --- a/main.c +++ b/main.c @@ -18,9 +18,9 @@ /* TODO: + - Fix VitaShell reloading. - Nethost. Patch UVL to be able to launch from host0 - Terminate thread / free stack of previous VitaShell when reloading - - Fix gxm bug in homebrew.c - Page skip for hex and text viewer - Improve homebrew exiting. Compatibility list at http://wololo.net/talk/viewtopic.php?f=113&p=402975#p402975 - Add UTF8/UTF16 to vita2dlib's pgf @@ -819,7 +819,7 @@ int dialogSteps() { args.archive_path = archive_path; args.copy_mode = copy_mode; - SceUID thid = sceKernelCreateThread("copy_thread", (SceKernelThreadEntry)copy_thread, 0x10000100, 0x10000, 0, 0x70000, NULL); + SceUID thid = sceKernelCreateThread("copy_thread", (SceKernelThreadEntry)copy_thread, 0x40, 0x10000, 0, 0x70000, NULL); if (thid >= 0) sceKernelStartThread(thid, sizeof(CopyArguments), &args); @@ -846,7 +846,7 @@ int dialogSteps() { args.cur_path = cur_path; args.index = base_pos + rel_pos; - SceUID thid = sceKernelCreateThread("delete_thread", (SceKernelThreadEntry)delete_thread, 0x10000100, 0x10000, 0, 0x70000, NULL); + SceUID thid = sceKernelCreateThread("delete_thread", (SceKernelThreadEntry)delete_thread, 0x40, 0x10000, 0, 0x70000, NULL); if (thid >= 0) sceKernelStartThread(thid, sizeof(DeleteArguments), &args); @@ -1485,9 +1485,37 @@ void freePreviousVitaShell() { sceKernelFreeMemBlock(sceKernelFindMemBlockByAddr((void *)extractFunctionStub((uint32_t)&sceKernelBacktraceSelf), 0)); } +extern unsigned char _binary_payload_payload_bin_start; +extern unsigned char _binary_payload_payload_bin_end; +extern unsigned char _binary_payload_payload_bin_size; // crashes + +typedef struct { + char *path; + int (* uvl_load)(const char *path); + int (* sceKernelExitDeleteThread)(int status); +} PayloadArgs; + +void payload() { + unsigned int length = 1 * 1024 * 1024; + void *addr = uvl_alloc_code_mem(&length); + + int size = &_binary_payload_payload_bin_end - &_binary_payload_payload_bin_start; + + uvl_unlock_mem(); + memcpy(addr, &_binary_payload_payload_bin_start, size); + uvl_lock_mem(); + uvl_flush_icache(addr, size); + + PayloadArgs args = { (void *)uvl_load, (void *)sceKernelExitDeleteThread }; + int (* executePayload)(PayloadArgs *args) = (void *)((uint32_t)addr | 0x1); + executePayload(&args); + + while (1); // Should not reach this +} + int vitashell_thread(SceSize args, void *argp) { #ifndef RELEASE - // sceIoRemove("cache0:vitashell_log.txt"); + sceIoRemove("cache0:vitashell_log.txt"); #endif // Free .text and .data segment of previous VitaShell @@ -1496,6 +1524,9 @@ int vitashell_thread(SceSize args, void *argp) { // Init VitaShell VitaShellInit(); + // Init code memory + initCodeMemory(); + // Set up nid table // setupNidTable(); @@ -1527,10 +1558,10 @@ int vitashell_thread(SceSize args, void *argp) { int main(int argc, const char *argv[]) { // Start app with bigger stack - SceUID thid = sceKernelCreateThread("VitaShell_main_thread", (SceKernelThreadEntry)vitashell_thread, 0x10000100, 1 * 1024 * 1024, 0, 0x70000, NULL); + SceUID thid = sceKernelCreateThread("vitashell_thread", (SceKernelThreadEntry)vitashell_thread, 0x10000100, 1 * 1024 * 1024, 0, 0x70000, NULL); if (thid >= 0) { sceKernelStartThread(thid, argc, argv); - sceKernelWaitThreadEnd(thid, NULL, NULL); + sceKernelWaitThreadEnd(thid, NULL, NULL); // TODO: Only first boot } return 0; diff --git a/module.c b/module.c index 06b6a62..8977a17 100644 --- a/module.c +++ b/module.c @@ -165,12 +165,25 @@ void copyStub(uint32_t address, void *function) { uvl_unlock_mem(); - uint32_t *f = (uint32_t *)address; - memcpy((void *)f, function, 0x10); + memcpy((void *)address, function, 0x10); uvl_lock_mem(); - uvl_flush_icache(f, 0x10); + uvl_flush_icache((void *)address, 0x10); +} + +void makeThumbDummyFunction0(uint32_t address) { + if (!address) + return; + + uvl_unlock_mem(); + + *(uint16_t *)(address + 0x0) = 0x2000; // movs a1, #0 + *(uint16_t *)(address + 0x2) = 0x4770; // bx lr + + uvl_lock_mem(); + + uvl_flush_icache((void *)address, 0x4); } uint32_t extractFunctionStub(uint32_t address) { diff --git a/module.h b/module.h index dddfe0b..c284674 100644 --- a/module.h +++ b/module.h @@ -102,6 +102,7 @@ uint32_t encode_arm_inst(uint8_t type, uint16_t immed, uint16_t reg); void makeSyscallStub(uint32_t address, uint16_t syscall); void makeFunctionStub(uint32_t address, void *function); void copyStub(uint32_t address, void *function); +void makeThumbDummyFunction0(uint32_t address); uint32_t extractFunctionStub(uint32_t address); uint32_t extractSyscallStub(uint32_t address); diff --git a/payload/Makefile b/payload/Makefile new file mode 100644 index 0000000..06fdf25 --- /dev/null +++ b/payload/Makefile @@ -0,0 +1,21 @@ +TARGET = payload +OBJS = main.o + +PREFIX = arm-vita-eabi +CC = $(PREFIX)-gcc +LD = $(PREFIX)-gcc +OBJCOPY = $(PREFIX)-objcopy +CFLAGS = -fPIE -fno-zero-initialized-in-bss -std=gnu99 -mcpu=cortex-a9 -mthumb-interwork -mthumb +LDFLAGS = -T linker.x -nodefaultlibs -nostdlib -pie + +all: $(TARGET) + +%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) $(CFLAGS_THUMB) + +$(TARGET): $(OBJS) + $(LD) -o $@ $^ $(LDFLAGS) + $(OBJCOPY) -O binary $@ $@.bin + +clean: + rm -rf *~ *.elf *.bin *.s $(TARGET) $(OBJS) diff --git a/payload/linker.x b/payload/linker.x new file mode 100644 index 0000000..e5fec2c --- /dev/null +++ b/payload/linker.x @@ -0,0 +1,12 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) + +SECTIONS +{ + .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .data : { *(.data .data.* .gnu.linkonce.d.*) } + .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } +} diff --git a/payload/main.c b/payload/main.c new file mode 100644 index 0000000..f3f7927 --- /dev/null +++ b/payload/main.c @@ -0,0 +1,28 @@ +/* + VitaShell + Copyright (C) 2015-2016, TheFloW + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +typedef struct { + char *path; + int (* uvl_load)(const char *path); + int (* sceKernelExitDeleteThread)(int status); +} PayloadArgs; + +int __attribute__ ((section (".text.start"))) _start(PayloadArgs *args) { + args->uvl_load(args->path); + return args->sceKernelExitDeleteThread(0); +} \ No newline at end of file diff --git a/payload/main.o b/payload/main.o new file mode 100644 index 0000000..125f2e8 Binary files /dev/null and b/payload/main.o differ diff --git a/payload/payload b/payload/payload new file mode 100644 index 0000000..e0dfd6d Binary files /dev/null and b/payload/payload differ diff --git a/payload/payload.bin b/payload/payload.bin new file mode 100644 index 0000000..e8f3845 Binary files /dev/null and b/payload/payload.bin differ diff --git a/utils.c b/utils.c index 818b884..e98f26f 100644 --- a/utils.c +++ b/utils.c @@ -206,8 +206,8 @@ void getTimeString(char *string, int time_format, SceRtcTime *time) { int netdbg_init() { + int ret = 0; #ifdef NETDBG_ENABLE - int ret; SceNetSockaddrIn server; SceNetInitParam initparam; SceUShort16 port = NETDBG_DEFAULT_PORT; @@ -262,8 +262,8 @@ error_netinit: net_memory = NULL; } error_netstat: - return ret; #endif + return ret; } void netdbg_fini()