diff --git a/PAYLOADS/1.00-2.13/Mainrules.mk b/PAYLOADS/1.00-2.13/Mainrules.mk index 3d4c1a0..605b2d4 100644 --- a/PAYLOADS/1.00-2.13/Mainrules.mk +++ b/PAYLOADS/1.00-2.13/Mainrules.mk @@ -9,7 +9,9 @@ IOP_AS = iop-as IOP_OBJCOPY = iop-objcopy IOP_OBJDUMP = iop-objdump -IOP_SYMBOLS = -DREAD_SECTORS=$(IOP_READ_SECTORS) -DORIGINAL_RETURN_ADDRESS=$(IOP_ORIGINAL_RETURN_ADDRESS) -DRETURN_ADDRESS_LOCATION=$(IOP_RETURN_ADDRESS_LOCATION) +IOP_SYMBOLS = -DREAD_SECTORS_210=$(IOP_READ_SECTORS_210) -DORIGINAL_RETURN_ADDRESS_210=$(IOP_ORIGINAL_RETURN_ADDRESS_210) -DRETURN_ADDRESS_LOCATION_210=$(IOP_RETURN_ADDRESS_LOCATION_210) \ + -DREAD_SECTORS_212=$(IOP_READ_SECTORS_212) -DORIGINAL_RETURN_ADDRESS_212=$(IOP_ORIGINAL_RETURN_ADDRESS_212) -DRETURN_ADDRESS_LOCATION_212=$(IOP_RETURN_ADDRESS_LOCATION_212) + IOP_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -g $(IOP_SYMBOLS) EE_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 diff --git a/PAYLOADS/1.00-2.13/2.10_repacked.mk b/PAYLOADS/1.00-2.13/emulator.mk similarity index 68% rename from PAYLOADS/1.00-2.13/2.10_repacked.mk rename to PAYLOADS/1.00-2.13/emulator.mk index 4dd9ccd..61b5fae 100644 --- a/PAYLOADS/1.00-2.13/2.10_repacked.mk +++ b/PAYLOADS/1.00-2.13/emulator.mk @@ -1,9 +1,12 @@ STAGE1_LOAD_ADDRESS = 0xa00b7548 STAGE1_LOAD_ADDRESS_STRING = '\x48\x75\x0b\xa0' -IOP_READ_SECTORS = 0xb260c -IOP_ORIGINAL_RETURN_ADDRESS = 0xb3630 -IOP_RETURN_ADDRESS_LOCATION = 0x1f62ac +IOP_READ_SECTORS_210 = 0xb260c +IOP_READ_SECTORS_212 = 0xb25f8 +IOP_ORIGINAL_RETURN_ADDRESS_210 = 0xb3630 +IOP_ORIGINAL_RETURN_ADDRESS_212 = 0xB35D8 +IOP_RETURN_ADDRESS_LOCATION_210 = 0x1f62ac +IOP_RETURN_ADDRESS_LOCATION_212 = 0x1f62b4 #IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"` diff --git a/PAYLOADS/1.00-2.13/2.10.mk b/PAYLOADS/1.00-2.13/hardware.mk similarity index 63% rename from PAYLOADS/1.00-2.13/2.10.mk rename to PAYLOADS/1.00-2.13/hardware.mk index e269ad9..c93b011 100644 --- a/PAYLOADS/1.00-2.13/2.10.mk +++ b/PAYLOADS/1.00-2.13/hardware.mk @@ -5,6 +5,13 @@ IOP_READ_SECTORS = 0x5DD0C # 0xb260c + 0x5c700 - 0xb1000 IOP_ORIGINAL_RETURN_ADDRESS = 0x5ED30 # 0xb3630 + 0x5c700 - 0xb1000 IOP_RETURN_ADDRESS_LOCATION = 0x1F30AC # 0x1f62ac + 0x1F3058 - 0x1f6258 +IOP_READ_SECTORS_210 = 0x5DD0C # 0xb260c + 0x5c700 - 0xb1000 +IOP_READ_SECTORS_212 = 0x5DCF8 # 0xb25f8 + 0x5c700 - 0xb1000 +IOP_ORIGINAL_RETURN_ADDRESS_210 = 0x5ED30 # 0xb3630 + 0x5c700 - 0xb1000 +IOP_ORIGINAL_RETURN_ADDRESS_212 = 0x5ECD8 # 0xB35D8 + 0x5c700 - 0xb1000 +IOP_RETURN_ADDRESS_LOCATION_210 = 0x1F30AC # 0x1f62ac + 0x1F3058 - 0x1f6258 +IOP_RETURN_ADDRESS_LOCATION_212 = 0x1F30B4 # 0x1f62b4 + 0x1F3058 - 0x1f6258 + #IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"` IOP_PAYLOAD_ENTRY = 0xa00fd178 # Set this manually for now. diff --git a/PAYLOADS/1.00-2.13/ioppayload.iop.c b/PAYLOADS/1.00-2.13/ioppayload.iop.c index 418a89a..f456a26 100644 --- a/PAYLOADS/1.00-2.13/ioppayload.iop.c +++ b/PAYLOADS/1.00-2.13/ioppayload.iop.c @@ -53,25 +53,25 @@ typedef struct { #define min(a, b) (((a) < (b)) ? (a) : (b)) -/* All of these could be reimplemented here, but I'm lazy so we will use whatever - * the IOP has already loaded. The addresses are hardcoded but should be easy - * enough to extract from IOP memory by looking for their module names and magic - * number 0x41C00000. - */ +int (*readSectors)(int count, int sector, void *destination); -int (*readSectors)(int count, int sector, void *destination) = (void *)READ_SECTORS; +//int (*sceSifSetDma)(struct SifDmaTransfer *, int num) = (void *)0x16fc8; +//int (*sceSifDmaStat)(int trid) = (void *)0x17170; +//void (*flushIcache)(void) = (void*)0x2f40; +//void (*flushDcache)(void) = (void*)0x3044; +//void (*printf)(char *, ...) = (void *)0x1ab84; // 2.10 +//void (*printf)(char *, ...) = (void *)0x155f8; // 2.12 -int (*sceSifSetDma)(struct SifDmaTransfer *, int num) = (void *)0x16fc8; -int (*sceSifDmaStat)(int trid) = (void *)0x17170; -void (*flushIcache)(void) = (void*)0x2f40; -void (*flushDcache)(void) = (void*)0x3044; -void (*printf)(char *, ...) = (void *)0x1ab84; +int (*sceSifSetDma)(struct SifDmaTransfer *, int num); +int (*sceSifDmaStat)(int trid); static void transfer_to_ee(void *dest, void *src, unsigned int size); static void *memcpy(void *dest, void *src, unsigned int n); static void *memset(void *s, int c, unsigned int n); static void memset_ee(void *s, int c, unsigned int n); +//#include "iopresolve.h" + static void readData(void *dest, unsigned int offset, size_t n) { //unsigned char buffer[SECTOR_SIZE]; //unsigned char *buffer = (void *)0xfd000; @@ -110,18 +110,30 @@ static void readDataUnsafe(void *dest, unsigned int offset, size_t n) { void _start(void) { extern unsigned char ee_crt0[]; extern unsigned int ee_crt0_size; - void *return_address = EE_CRT0_ADDRESS; - int one = 1; + void *return_address[4] __attribute__ ((aligned (16))) = { EE_CRT0_ADDRESS, 0, 0, 0 }; + int one __attribute__ ((aligned (16))) = 1; int i; + //sceSifSetDma = resolve("sifman", 7); + //sceSifDmaStat = resolve("sifman", 8); + + sceSifSetDma = (void *)0x16fc8; + sceSifDmaStat = (void *)0x17170; + + if(*(unsigned int *)READ_SECTORS_210 == 0x27bdffc8) // addiu $sp, $sp, -0x38 + readSectors = (void *)READ_SECTORS_210; + else readSectors = (void *)READ_SECTORS_212; + transfer_to_ee(EE_CRT0_ADDRESS, ee_crt0, ee_crt0_size); - /* Corrupt all known return addresses in the stack. - */ - transfer_to_ee((void *)0x14A5FF0, &return_address, sizeof(return_address)); /* 2.10E/A */ - transfer_to_ee((void *)0x10007F0, &return_address, sizeof(return_address)); /* 2.10J */ - transfer_to_ee((void *)0x12D1C70, &return_address, sizeof(return_address)); /* 2.10U */ + // Corrupt all known return addresses in the stack, there might be a more universal way for IOP to redirect EE... + transfer_to_ee((void *)0x14A5FF0, &return_address, sizeof(return_address)); // 2.10E/A + transfer_to_ee((void *)0x10007F0, &return_address, sizeof(return_address)); // 2.10J + transfer_to_ee((void *)0x12D1C70, &return_address, sizeof(return_address)); // 2.10U + transfer_to_ee((void *)0x12B8CF0, &return_address, sizeof(return_address)); // 2.12U + + // Clear bit 0 of 0x208bb710 to make EE exit loop waiting for IOP, and return to our above payload //unsigned int loopValue = 0x010004; @@ -185,17 +197,11 @@ void _start(void) { copied += k; remaining -= k; } - - //unsigned char x[] = { 0x08, 0x00, 0xE0, 0x03, 0x01, 0x00, 0x42, 0x30, 0x01 }; - //memcpy(buffer, &x, sizeof(x)); - //memset(buffer + sizeof(x), 0, sizeofbuffer - sizeof(x)); - //transfer_to_ee(eph[i].vaddr + (eph[i].filesz & ~(0x10 - 1)), buffer, (remaining + 0xf) & ~(0x10 - 1)); } transfer_to_ee(EE_ENTRYPOINT_ADDRESS, &eh.entry, sizeof(one)); - /* Signal EE that the ELF is loaded and ready to execute. - */ + // Signal EE that the ELF is loaded and ready to execute. transfer_to_ee(EE_WAIT_ADDRESS, &one, sizeof(one)); //int loopValueJ = 0; diff --git a/PAYLOADS/1.00-2.13/iopresolve.h b/PAYLOADS/1.00-2.13/iopresolve.h new file mode 100644 index 0000000..6162f3c --- /dev/null +++ b/PAYLOADS/1.00-2.13/iopresolve.h @@ -0,0 +1,220 @@ +//typedef unsigned char u8; +//typedef unsigned short u16; +//typedef unsigned int u32; + +typedef void *pointer; + +#define NULL 0 + +typedef struct _smod_mod_info { + //struct _smod_mod_info *next; + pointer next; + /** A pointer to the name in IOP RAM, this must be smem_read(). */ + //char *name; + pointer name; + u16 version; + /** For MODLOAD shipped with games. The old MODLOAD module from boot ROMs do not use a flags field. */ + u16 newflags; + u16 id; + u16 unused; + /** _start */ + u32 entry; + u32 gp; + u32 text_start; + u32 text_size; + u32 data_size; + u32 bss_size; + u32 unused1; + u32 unused2; +} smod_mod_info_t; + +typedef struct _slib_imp_list { + u8 magic; + //struct _slib_imp_list *next; + pointer next; + u16 version; + u16 flags; + u8 name[8]; + //void *imports[0]; + pointer imports[0]; +} slib_imp_list_t; + +typedef struct _slib_exp_lib { + //struct _slib_exp_lib *prev; + pointer prev; + //struct _slib_imp_list *caller; + pointer caller; + u16 version; + u16 flags; + u8 name[8]; + //void *exports[0]; + pointer exports[0]; +} slib_exp_lib_t; + +typedef struct _slib_exp_lib_list { + //struct _slib_exp_lib *tail; + pointer tail; + //struct _slib_exp_lib *head; + pointer head; +} slib_exp_lib_list_t; + +#define SMEM_BUF_SIZE 0x300 //Must be large enough to accommodate all operations. + +struct smem_buf { + union { + u8 bytes[SMEM_BUF_SIZE / sizeof(u8)]; + u32 words[SMEM_BUF_SIZE / sizeof(u32)]; + smod_mod_info_t mod_info; + slib_exp_lib_t exp_lib; + }; +}; + + + +size_t strlen(const char *str) { + const char *s; + for (s = str; *s; ++s); + return (s - str); +} + +int memcmp(const char *cs_in, const char *ct_in, size_t n) { + size_t i; + const unsigned char * cs = (const unsigned char*) cs_in; + const unsigned char * ct = (const unsigned char*) ct_in; + + for (i = 0; i < n; i++, cs++, ct++) + { + if (*cs < *ct) + { + return -1; + } + else if (*cs > *ct) + { + return 1; + } + } + return 0; +} + + + +slib_exp_lib_list_t _slib_cur_exp_lib_list; + +struct smem_buf smem_buf; + +typedef unsigned int SifRpcReceiveData_t; + +size_t SifRpcGetOtherData(void *a, pointer x, void *dest, size_t s, int z) { + memcpy(dest, x, s); + return s; +} + +slib_exp_lib_list_t *slib_exp_lib_list(void) { + SifRpcReceiveData_t RData; + slib_exp_lib_t *core_exps; + slib_exp_lib_list_t *exp_lib_list = NULL; + u32 i, addr, core_end, NextMod, *exp_func; + void *pGetLoadcoreInternalData; + smod_mod_info_t *ModInfo; + + /* Read the start of the global module table - this is where we will search. */ + if(SifRpcGetOtherData(&RData, (void*)0x800, &smem_buf, sizeof(smod_mod_info_t), 0)>=0){ + /* The first entry points to LOADCORE's module info. We then use the + module info to determine the end of LOADCORE's .text segment (just + past the export library we're trying to find. */ + NextMod = *smem_buf.words; + if(SifRpcGetOtherData(&RData, (void*)NextMod, &smem_buf, sizeof(smod_mod_info_t), 0)>=0){ + ModInfo = &smem_buf.mod_info; + core_end = ModInfo->text_start+ModInfo->text_size; + + /* Back up so we position ourselves infront of where the export + library will be. */ + if(SifRpcGetOtherData(&RData, (void*)(core_end - 512), &smem_buf, 512, 0)>=0){ + /* Search for LOADCORE's export library. */ + for (i = 0; i < 512; i += 4) { + /* SYSMEM's export library sits at 0x830, so it should appear in + LOADCORE's prev pointer. */ + if (smem_buf.words[i / sizeof(u32)] == 0x830) { + if (!memcmp(smem_buf.bytes + i + 12, "loadcore", 8)) + //if(*(unsigned int *)(smem_buf.bytes + i + 12) == 0x64616f6c) // 6c 6f 61 64 == load + break; + } + } + if (i >= 512) + return NULL; + + /* Get to the start of the export table, and find the address of the + routine that will get us the export library list info. */ + core_exps = (slib_exp_lib_t *)(smem_buf.bytes + i); + pGetLoadcoreInternalData = core_exps->exports[3]; + + if(SifRpcGetOtherData(&RData, pGetLoadcoreInternalData, &smem_buf, 8, 0)>=0){ + exp_func = smem_buf.words; + + /* Parse the two instructions that hold the address of the table. */ + if ((exp_func[0] & 0xffff0000) != 0x3c020000) /* lui v0, XXXX */ + return NULL; + if ((exp_func[1] & 0xffff0000) != 0x24420000) /* addiu v0, v0, XXXX */ + return NULL; + + addr = ((exp_func[0] & 0xffff) << 16) | (exp_func[1] & 0xffff); + + if(SifRpcGetOtherData(&RData, (void*)addr, &smem_buf, 8, 0)>=0){ + _slib_cur_exp_lib_list.tail = (slib_exp_lib_t *)(smem_buf.words[0]); + _slib_cur_exp_lib_list.head = (slib_exp_lib_t *)(smem_buf.words[1]); + exp_lib_list = &_slib_cur_exp_lib_list; + } + } + } + } + } + + return exp_lib_list; +} + +#define EXP_LIB_MAX SMEM_BUF_SIZE /* We can even handle CDVDMAN's bloat! */ + +int slib_get_exp_lib(const char *name, slib_exp_lib_t *library) +{ + SifRpcReceiveData_t RData; + slib_exp_lib_list_t *exp_lib_list = &_slib_cur_exp_lib_list; + slib_exp_lib_t *exp_lib = &smem_buf.exp_lib; + void *cur_lib; + int len = strlen(name), count = 0; + + if (!exp_lib_list->head && !(exp_lib_list = slib_exp_lib_list())) + return 0; + + /* Read the tail export library to initiate the search. */ + cur_lib = exp_lib_list->tail; + + while (cur_lib) { + if(SifRpcGetOtherData(&RData, cur_lib, exp_lib, EXP_LIB_MAX, 0)>=0){ + if (!memcmp(exp_lib->name, name, len)) { + while (exp_lib->exports[count] != 0) + count++; + + if (library) + memcpy(library, exp_lib, sizeof(slib_exp_lib_t) + count * 4); + + return count; + } + + cur_lib = exp_lib->prev; + } + } + + return 0; +} + +void *resolve(char *name, int export) { + slib_exp_lib_t *modload_lib = (void *)0x100; + + memset(&_slib_cur_exp_lib_list, 0, sizeof(slib_exp_lib_list_t)); + + if (!slib_get_exp_lib(name, modload_lib)) { + return NULL; + } + + return modload_lib->exports[export]; +} diff --git a/PAYLOADS/1.00-2.13/stage1.iop.S b/PAYLOADS/1.00-2.13/stage1.iop.S index b859aa5..b0c2c99 100644 --- a/PAYLOADS/1.00-2.13/stage1.iop.S +++ b/PAYLOADS/1.00-2.13/stage1.iop.S @@ -1,14 +1,10 @@ # ElReino & CTurt 2020 -readSectors = READ_SECTORS - flushIcache = 0x00002f40 flushDcache = 0x0003044 #flushDcacheWrapper = 0x0057f1c -#iop_payload_address = 0x460000 -#iop_payload_address = 0xa0460000 iop_payload_address = 0xa00fd000 .section .text @@ -16,11 +12,21 @@ iop_payload_address = 0xa00fd000 .global _start _start: move $fp, $sp # We need to reset $fp as it gets trashed by memcpy - + +check_210: + la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38 + la $v0, READ_SECTORS_210 + lw $t0, 0($v0) + beq $t0, $v1, read_iop_payload + +check_212: + la $v0, READ_SECTORS_212 + +read_iop_payload: la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count la $a1, 0x700000 / 0x800 # sector la $a2, iop_payload_address # destination - jal readSectors + jal $v0 #jal flushIcache #jal flushDcache @@ -28,13 +34,21 @@ _start: #jal ENTRY la $v0, ENTRY jalr $v0 - + +check_210_again: + la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38 + la $v0, READ_SECTORS_210 + lw $v0, 0($v0) + la $a0, RETURN_ADDRESS_LOCATION_210 + la $ra, ORIGINAL_RETURN_ADDRESS_210 + beq $v0, $v1, return + +check_212_again: + la $a0, RETURN_ADDRESS_LOCATION_212 + la $ra, ORIGINAL_RETURN_ADDRESS_212 + +return: # Return gracefully back to original return address - la $a0, RETURN_ADDRESS_LOCATION - la $ra, ORIGINAL_RETURN_ADDRESS # hardware - sw $ra, 0($a0) - la $v0, 0 - jr $ra diff --git a/PREBUILT ISOs/2.10.iso b/PREBUILT ISOs/some 2.10 models and 2.12U.iso similarity index 99% rename from PREBUILT ISOs/2.10.iso rename to PREBUILT ISOs/some 2.10 models and 2.12U.iso index 90aad41..a3e0371 100644 Binary files a/PREBUILT ISOs/2.10.iso and b/PREBUILT ISOs/some 2.10 models and 2.12U.iso differ diff --git a/README.md b/README.md index 8c968e2..4918735 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ Boot your PlayStation 2 without any disc inserted, and press Triangle to identif **Currently only support:** -- 2.10 (all regions and languages), +- 2.10 (certain models only?), + +- 2.12 (region U, others to be added soon), - 3.04 (tested only region M in emulator so far, but guess most other regions EUMACDG, except for J will work - with English language set in settings), @@ -140,13 +142,13 @@ If you wish to update the loader payload, run `build.sh` inside `PAYLOAD` direct ## DEVELOPMENT: Replacing the loader payload - Phat Run the following to build a new `dvd.iso`: -`make -f 2.10.mk` +`make -f hardware.mk` -If you want to test on PCSX2 using KrHacken's repacked DVD players, it loads `udfio` at a different base address, use the repacked makefile to build an image for testing on the emulator: +If you want to test on PCSX2 using KrHacken's repacked DVD players, it loads `udfio` at a different base address, use the repacked Makefile to build an image for testing on the emulator: -`make -f 2.10_repacked.mk` +`make -f emulator.mk` -`clean` before switching between these, or use `-B` flag. +`clean` before switching between these different Makefiles, or use `-B` flag. ## PORTING: Please read my technical writeup, to understand how the exploit works. I've also provided some [notes about porting](https://cturt.github.io/FreeDVDBoot/portingnotes.html) in the [`gh-pages`](https://github.com/CTurt/FreeDVDBoot/tree/gh-pages) branch.