Making Isolated SPU Modules and Loaders

From PS3 Developer wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Introduction

  • E.g. to dump your ATA, ENCDEC or EID2 keys you have to make signed isolated SPU modules or loaders.
  • This is a tutorial how to do it on Linux (it doesn't matter on PC or PS3).

Tools

SPU GCC Compiler

  • You need SPU GCC compiler to compile your code and create binary version of it.
  • On PS3 Debian, just install spu toolchain with aptitude.
  • You can also cross-compile SPU GCC toolchain for your Linux PC.
  • See http://gitorious.ps3dev.net/ps3linux/powerpc64-cross-compiler if you want to build SPU GCC cross-compiler. Just change in HOWTO target option from powerpc64-linux to spu-elf.

ps3tools

  • You need these tools to decrypt PS3 isolated SPU modules and loaders.
  • You also need it to sign and encrypt your own SPU modules and loaders.
  • self_rebuilder doesn't work properly with isolated SPU modules or loaders. Therefore, i made a new tool which works with isolated SPU modules and loaders. It's called iso_rebuilder and is a modified version of self_rebuilder.
  • See my GIT repop: http://gitorious.ps3dev.net/ps3otheros/ps3tools

How To Test Isolated SPU Modules and Loaders

  • I test my isolated SPU modules and loaders with PS3 Linux and spuisofs/spuldrfs Virtual File Systems.

spuisofs

  • You can test with spuisofs isolated SPU modules which are decrypted by isoldr.
  • You cannot test loaders with spuisofs.
  • But spuisofs has the advantage that it's alot easier to execute isolated SPUs with it than with spuldrfs.

See http://www.ps3devwiki.com/wiki/Spuisofs

spuldrfs

  • You can test with spuldrfs isolated SPU modules which are decrypted by isoldr and loaders which are decrypted by metldr.
  • Use spuisofs if you want to execute isoldr SPUs, it's easier to do than with spuldrfs.

See http://www.ps3devwiki.com/wiki/Spuldrfs

Example: Making dump_ata_keys.self

  • First you need sb_iso_spu_module.self from your NOR/NAND flash or from PS3 update file.
Type This
# compile your SPU code

spu-elf-gcc -c dump_ata_keys.S

ls -l dump_ata_keys.o

# convert your code to binary

spu-elf-objcopy -O binary dump_ata_keys.o dump_ata_keys.bin

ls -l dump_ata_keys.bin

# decrypt sb_iso_spu_module.self

unself sb_iso_spu_module.self sb_iso_spu_module.elf

ls -l sb_iso_spu_module.elf
mv sb_iso_spu_module.elf dump_ata_keys.elf

# print program header of decrypted SPU module

readelf -l dump_ata_keys.elf

Elf file type is EXEC (Executable file)
Entry point 0x880
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000100 0x00000880 0x00000880 0x05040 0x05040 R E 0x80
  LOAD           0x005180 0x00005900 0x00005900 0x00030 0x001c0 RW  0x80
  NOTE           0x0051b0 0x00000000 0x00000000 0x00034 0x00000 R   0x10

 Section to Segment mapping:
  Segment Sections...
   00     .unknown .unknown 
   01     .unknown .unknown .unknown .unknown 
   02     .unknown 

# entry point is 0x880 which is in first program segment at file offset 0x100

# now we kill all old code and data with 0s before we put our code there.
# seek parameter is the offset of the first program segment.
# count parameter is the sum of the offset of the last program segment plus its size and
# minus the offset of the first program segmnet.

# killing old code and data with 0s is a good idea because 0x00000000 means stop opcode.

dd if=/dev/zero of=dump_ata_keys.elf bs=1 seek=$((0x100)) count=$((0x51b0 + 0x34 - 0x100)) conv=notrunc

# after you filled out the SPU module with 0s, check it with spu-objdump

spu-elf-objdump -d dump_ata_keys.elf 

dump_ata_keys.elf:     file format elf32-spu


Disassembly of section :

00000880 <>:
	...

# now we copy our code to SPU module
# seek parameter is the entry point offset in file

dd if=dump_ata_keys.bin of=dump_ata_keys.elf bs=1 seek=$((0x100)) conv=notrunc

# now build isolated SPU module

iso_rebuilder dump_ata_keys.elf dump_ata_keys.self sb_iso_spu_module.self

# we are done :)
# time to test it with spuisofs !!!

# mount spuisofs (we do it of course on PS3 Linux and not on PC)
# you could use my Debian LiveCD e.g. which has all tools you need

sudo mount -t spuisofs none /mnt

ls -l /mnt
total 0
-rw-rw-rw- 1 root root 1048576 Sep  7 12:12 app
-rw-rw-rw- 1 root root 1048576 Sep  7 12:12 arg1
-rw-rw-rw- 1 root root 1048576 Sep  7 12:12 arg2
--w--w--w- 1 root root       0 Sep  7 12:12 cont
-r--r--r-- 1 root root       0 Sep  7 12:12 info
-rw-rw-rw- 1 root root  262144 Sep  7 12:12 ls
-rw-rw-rw- 1 root root  131072 Sep  7 12:12 priv2
-rw-rw-rw- 1 root root  131072 Sep  7 12:12 problem
--w--w--w- 1 root root      24 Sep  7 12:12 run
-r--r--r-- 1 root root    4096 Sep  7 12:12 shadow

# compile dump_ata_keys application

tar xvzf dump_ata_keys.tar.gz
cd dump_ata_keys
make
ls -l dump_ata_keys

./dump_ata_keys
usage: ./dump_ata_keys <self path> <eid4 path>

# NOTE: you don't really need eid4 to run the application or to dump your ATA keys

./dump_ata_keys ./dump_ata_keys.self ./eid4
spuisofs found at /mnt
arg1 kernel virtual address d000000003375000
shadow: spe_execution_status 7
priv2: puint_mb_R 2
shadow: spe_execution_status b
problem: spu_status_R 6660082

# here is important to check the stop code which is 0x666 :)
# my dump_ata_keys.S code stops with stop code 0x666 when it's done
# this way you can be really sure that your dump_ata_keys.self was correctly signed,
# encrypted and accepted by isoldr

# dump your ATA keys

hexdump -C /mnt/arg1

Example: Making dump_encdec_keys.self

  • First you need lv1ldr from your NOR/NAND flash or from PS3 update file.
Type This
# compile your SPU code

spu-elf-gcc -c dump_encdec_keys.S

ls -l dump_encdec_keys.o

# convert your code to binary

spu-elf-objcopy -O binary dump_encdec_keys.o dump_encdec_keys.bin

ls -l dump_encdec_keys.bin

# decrypt lv1ldr

unself lv1ldr lv1ldr.elf

ls -l lv1ldr.elf
mv lv1ldr.elf dump_encdec_keys.elf

# print program header of decrypted loader

readelf -l dump_encdec_keys.elf

Elf file type is EXEC (Executable file)
Entry point 0x12c00
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000080 0x00000800 0x00000800 0x00000 0x0cd20 RW  0x80
  LOAD           0x000100 0x00012c00 0x00012c00 0x1ca00 0x1ca00 R E 0x80
  LOAD           0x01cb00 0x0002f600 0x0002f600 0x004f0 0x004f0 RW  0x80

 Section to Segment mapping:
  Segment Sections...
   00     .unknown
   01     .unknown .unknown
   02     .unknown .unknown .unknown 

# entry point is 0x12c00 which is in second program segment at file offset 0x100

# now we kill all old code and data with 0s before we put our code there.
# seek parameter is the offset of the second program segment.
# count parameter is the sum of the offset of the last program segment plus its size and
# minus the offset of the second program segment.

# killing old code and data with 0s is a good idea because 0x00000000 means stop opcode.

dd if=/dev/zero of=dump_encdec_keys.elf bs=1 seek=$((0x100)) count=$((0x1cb00 + 0x4f0 - 0x100)) conv=notrunc

# after you filled out the SPU module with 0s, check it with spu-objdump

spu-elf-objdump -d dump_encdec_keys.elf 

dump_encdec_keys.elf:     file format elf32-spu


Disassembly of section :

00012c00 <>:
        ...

# now we copy our code to loader
# seek parameter is the entry point offset in file

dd if=dump_encdec_keys.bin of=dump_encdec_keys.elf bs=1 seek=$((0x100)) conv=notrunc

# now build loader

iso_rebuilder dump_encdec_keys.elf dump_encdec_keys.self lv1ldr

# we are done :)
# time to test it with spuldrfs !!!

# mount spuldrfs (we do it of course on PS3 Linux and not on PC)
# you could use my Debian LiveCD e.g. which has all tools you need

sudo mount -t spuldrfs none /mnt

ls -l /mnt
total 0
-rw-rw-rw- 1 root root 1048576 Sep  7 13:20 buf1
-rw-rw-rw- 1 root root 1048576 Sep  7 13:20 buf2
-rw-rw-rw- 1 root root 1048576 Sep  7 13:20 buf3
-r--r--r-- 1 root root       0 Sep  7 13:20 info
-rw-rw-rw- 1 root root 1048576 Sep  7 13:20 ldr
-rw-rw-rw- 1 root root  262144 Sep  7 13:20 ls
-rw-rw-rw- 1 root root 1048576 Sep  7 13:20 metldr
-rw-rw-rw- 1 root root  131072 Sep  7 13:20 priv2
-rw-rw-rw- 1 root root  131072 Sep  7 13:20 problem
--w--w--w- 1 root root       0 Sep  7 13:20 run
-r--r--r-- 1 root root    4096 Sep  7 13:20 shadow

# compile dump_encdec_keys application

tar xvzf dump_encdec_keys.tar.gz
cd dump_encdec_keys
make
ls -l dump_encdec_keys

./dump_encdec_keys
usage: ./dump_encdec_keys <metldr path> <ldr path>

# NOTE: you will need your metldr

./dump_encdec_keys ./metldr ./dump_encdec_keys.self
spuldrfs found at /mnt
buf1 kernel virtual address d000000003c48000
buf2 kernel virtual address d000000003d49000
priv2: puint_mb_R 1
problem: pu_mb_R 1
priv2: puint_mb_R 666
problem: spu_status_R 6660082

# here is important to check the stop code which is 0x666 :)
# my dump_encdec_keys.S code stops with stop code 0x666 when it's done
# this way you can be really sure that your dump_encdec_keys.self was correctly signed,
# encrypted and accepted by metldr

# dump your ENCDEC keys (not really, you have to calculate your ENCDEC keys)

hexdump -C /mnt/buf2