Skip to the content
2 layers14 × 14 mmTry2, the printed circuit board in 3D

Tools and guides for achieving code execution in Playstation Vita/TV BootROM's "SD boot mode"

Size
14 × 14 mm
Copper layers
2
Thickness
1.6 mm
Parts
10
Nets
8
Pads
20
Tracks, vias
22, 0
Routed
Yes
KiCad
KiCad 7 (file 20221018)
Created
9 Dec 2023
Updated
26 Dec 2024

Overview

Try2 is an open-source printed circuit board by SKGleba, from the SKGleba/psp2sdboot repository on GitHub, published under the MIT licence. It is a 2-layer board of 14 × 14 mm with 10 parts on 8 nets, routed with 22 tracks and 0 vias.

It is built around the MMBF170. Its parts include 8 connectors and 2 transistors.

Main components

1

README

README.md

psp2sdboot

This repo contains guides, payloads, schematics and scripts for use with PSP2's "SD boot mode".

About

JIG

On all Playstation Vita/TV units the System Controller ("syscon", "ernie") has an RPC server activated by a specific hardware circuit. When activated, syscon listens over UART for commands that can range from simple diag checks, fuse reads, calibrations, to special features such as NVS R/W that require authorization using handshakes with secret keys. More information as well as circuit schematics and RPC clients can be found in the bert repository.

GC/SD boot

An authorized JIG interface client can trigger a special, alternative boot mode inside the BootROM. In this mode, which we dubbed "sdboot", a signed second_loader.enp is loaded from an unauthenticated MMC/SD storage inside the GameCard slot and decrypted using an alternative set of per-console keys.

Vulnerability

In sdboot, after copying itself from 0x40000 to 0x5c000, BootROM first reads a single block (0x200 bytes) from the external storage to 0x40000, verifies if second_loader offset and size fields are valid, then reads second_loader to 0x40000.
The issue is that the exception vectors are hardcoded to 0x40000, so any exceptions in BootROM during (or after) second_loader is read will cause a "jump" to the read data - resulting in arbitrary code execution.

Code execution

A simple way to trigger an exception is to perform a Fault Injection attack. Because all faults/exceptions result in code execution, the FI setup does not need to be precise, and can be approached in a spray-and-pray manner.
This project makes use of Voltage Fault Injection, specifically the "crowbar" method, performed by a low cost setup with the Teensy 4 mcu system at heart.
The result is a consistent BootROM code execution of a arbitrary code blob loaded from an unauthenticated MMC/SD storage inside the GameCard slot.

BootROM RPC

With psp2sdboot, the default code blob is bob, it starts an RPC server that can be used for research or executing additional specialized payloads with functionality such as key retrieval, data dumping, unbricking and more.

Supported units
  • DEM-3000 : only IRT-002
    • Due to an unknown JIG interface-enable procedure on IRT-001 / "slideys"
  • CEM-3000 : supported
  • PCH-1000 : supported
  • VTE-1000 : supported
  • PCH-2000 : not yet supported
    • Due to lack of success triggering exceptions with Voltage Fault Injection

Setup

Requirements

  • a working syscon JIG setup
  • logic analyzer with at least two channels, a simple USB 8ch saleae/clone should work
  • GC-SD adapter such as "sd2vita", with a micro/sd up to 2TiB
  • consistent, configurable pulse generator that can set 1v+ for 100ns or less.
    • for this project, the Teensy 4.0 / Teensy 4.1 mcu board was chosen for its high speed, tight-coupled memory and gpio controllers
    • a chipwhisperer (lite) was also successfully used in this project's early iterations
  • fast switching, logic level n-mosfet
    • depending on your soldering skills/setup, a breakout board might be a good idea
    • for this project, IRLML2502 and IRLML6246 were used
  • 3.3v usb<->uart adapter for communicating with the Teensy 4 mcu board

Teensy

  • Connect the Teensy 4 to a PC, enter bootloader mode
  • Flash the latest build of teensy4vfi using Teensy Loader
  • Connect the usb<->uart adapter
    • PC TX -> Teensy pad 0 (RX)
    • PC RX -> Teensy pad 1 (TX)
    • GND

Solder points

There are at least two (magnet) wire solder points - Core_VDD (orange) and GC_dat0 (yellow).

  • PCH-1000/PDEL-1000/CEM-3000/DEM-3000: front
  • VTE-1000: front | back
  • It is recommended to add a separate GND wire for the MOSFET.

Wiring

The MOSFET wires should be insulated and kept as short as possible, you can even solder its legs directly to the Core_VDD capacitor.

wiring

Software

The original setup was Windows + WSL1, but the instructions should work fine on Windows, Linux and MacOS.

Prerequisites
Environment

The "root", working directory should be a local copy of this repository.

  • compile tools/mkfake.c with GCC
  • create symlinks for bob/bob_rpc.py, teensy4vfi/teensy_rpc.py, and bert/bert.py
  • create a bob directory in payloads/, and copy there the bob build and header files
    • bob/build/* to payloads/bob/
    • bob/source/include to payloads/bob/
  • "set" the environment by running the provided env.bat
    • this simply sets a bunch of aliases

microSD card

A raw SD card image can be created using the previously compiled mkfake utility, the syntax is mkfake <code_blob> -o <output> where:

  • code_blob is bob's glitch build - payloads/bob/bob_glitch.bin
  • output will be the SD card image The prepared SD card must then be inserted in the target's GC slot.

SD Boot

The provided sdboot.py is a python script that loops reboot->glitch->check until bob is successfully loaded and executed.
Its accepted arguments/parameters and their descriptions can be listed with sdboot help.

Calibration

The first step is determining optimal timing parameters range for the main sdboot script, which will then find the more precise/consistent glitch timings.

The "threshold" width

The width of a glitch that always causes an unrecoverable crash is called the "threshold", this should be the upper width boundary - sdboot's width_max argument.
It can be determined by the following procedure:

  1. sdboot width=100 width_max=100000 width_step=100
    • note the width at which dat0 cut off
    • if there is no dat0 cut off until 100000, the setup is wrong/faulty
  2. sdboot width=<cutoff_width-100> width_max=<cutoff_width+100> width_step=20
    • repeat at least 5 times
    • note the width at which dat0 always cuts off, this is the "threshold"
  3. If the "threshold" is below 200, it might indicate a faulty circuit, slow mosfet, or a very isolated/clean setup.

    LA view
The "up_to_read" offset

up_to_read is a special 0-width glitch queued to find an empty sector read op, which compensates for a high SD init/read jitter.
The idea is that as long as it lands in the middle of an empty sector being read (dat0 pulled down), the actual fault injection glitch can be precisely triggered and timed from dat0 going up.
It can be determined by altering the following command: sdboot up_to_read_mark=100 up_to_read=298400000. Change up_to_read until the mosfet line spike happens around the middle of an empty sector read.

LA view

Glitching

The second step is running the sdboot python script, and letting it find a correct combination of offset and width parameters
Script arguments are based on the values found during the Calibration step, with an added broad offset range:
sdboot up_to_read=<up_to_read> width=<threshold-(2*width_step)> width_max=<threshold+width_step> width_step=20 offset=100 offset_max=10000 offset_mult=10 offset_step=40

  • offset* parameters should initially be broad, with further loops being more precise (eg offset_mult=1)
  • if the threshold is below 500, width_step=10 might be a better choice
  • if the starting width (threshold - (2 x width_step)) is observed to cut off dat0, the starting width should be decreased by width_step-sized decrements
  • ultimately it depends on luck, it might take hours or even days to find a working offset and width pair
  • in case of success, a got sd boot: off=<offset>[<offset_mult>] width=<width> message will be displayed and the script will stop

Post-Exploitation

After bob presence is confirmed with bob ping, you can use the bob_rpc script to conduct further research or copy and run MeP payloads. Available RPC commands can be listed by calling the script without any arguments - bob. Memory Layout

RPC payloads

You should put your custom payloads inside the payloads/ directory.
They can statically link to bob and bootrom for basic funtionality, see the linker example. Headers can be found in payloads/bob/include/.
Payloads can be executed anywhere in the physical memory, keep in mind that some is uninitialized - eg DRAM.

  • copy: file_send <offset> <payload_file>
  • exec: exec <offset> <arg0> <arg1> <arg2_data>, where arg2_data is a buffer passed as arg2
  • extended exec: exece <offset> <arg0> <arg1> <arg2> <arg..>, up to 8 args total

Key extraction

Provided is a basic keydumper - payloads/keydumper - it can be used to get the SLSK enc/dec key partials, SNVS enc/dec keys, and the SMI encryption keys.

  • If you do not have SoC TX wired, you can dump the key buffer from 0x1f850000 to a file using bob file_dump.

Storage R/W

The provided eMMC dumper - payloads/emmc-dump - contains code to read/write eMMC as well as the SD card. It can be used for larger data handling, eMMC dump/unbrick, crypto research and more.

  • By default, the emmc dumper uses DRAM which must be first initialized. Until reimplemented, the code/binary can be copied from second_loader.
    • You can just use a different memory region, eg SPAD128K

Unbricking

At the time of writing, there is no single tool to diagnose and fix common "bricks".
You need to get the boot log, read henkaku wiki to find the probable brick cause, and use the provided tools/payloads to fix the console.

  • SoC TX - for boot log - can be redirected to Syscon TX / USB TX by changing nvs byte 0x481 from 0xFF to 0x00, nvs-write 0x481 0x1 00
  • some more uncommon bricks might require you to reverse engineer the OS, i recommend Ghidra

Credits

This project was made in collaboration with Proxima and Mathieulh.

Additional thanks to:

  • xyz - for help with hardware work, research, intial glitching, tests, spoonfeeding and handholding
  • yifanlu and Team Molecule, whose work served as the foundation for this project
  • all bert contributors
  • henkaku wiki contributors

Parts

10
QtyValueFootprintReferences
2Conn_01x04_PinConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ3, J4
2MMBF170Package_TO_SOT_SMD:SOT-23Q1, Q2
1DAT0Connector_Wire:SolderWirePad_1x01_SMD_1x2mmJ6
1GNDConnector_Wire:SolderWirePad_1x01_SMD_1x2mmJ7
1GPIOConnector_Wire:SolderWirePad_1x01_SMD_1x2mmJ5
1PWRConnector_Wire:SolderWirePad_1x01_SMD_1x2mmJ1
1RSTConnector_Wire:SolderWirePad_1x01_SMD_1x2mmJ8
1VDDConnector_Wire:SolderWirePad_1x01_SMD_1x2mmJ2

Similar boards

  • 2 layers72 × 22 mmCheating calc, the printed circuit board in 3D

    Cheating calc

    ChinesePrince07/TI-84-GPT-HACK

    A mod that gives your TI-84 Wi-Fi, ChatGPT, and the ability to disappoint your math teacher in ways never thought possible. Original idea by Chromalock, reconstructed by myself after his repo is taken down.

    8 parts9GPL-3.0
  • 6 layers44 × 118 mm3210retro test, the printed circuit board in 3D

    3210retro test

    DasBasti/NokiaRetroFit

    Retrofitting a Nokia 3210 with modern Processor

    195 parts9Apache-2.0
  • 2 layers114 × 89 mmAyn-4b, the printed circuit board in 3D

    Ayn-4b

    afiskon/ayn-4b

    Portable QRP CW Transceiver

    278 parts7MIT
  • 6 layers105 × 70 mmBUDDY v1.0.0, the printed circuit board in 3D

    BUDDY v1.0.0

    bobc/Prusa-Mini-assembly

    A Prusa Mini 3D model assembly using OpenSCAD

    364 parts7MIT
  • 2 layers100 × 90 mmAyn dc, the printed circuit board in 3D

    Ayn dc

    afiskon/ayn-dc

    DC QRP CW transceiver

    226 parts5MIT
  • 2 layers45 × 75 mmRelay board, the printed circuit board in 3D

    Relay board

    waterloo-rocketry/rlcsv3

    Arduino code and electrical schematics for Waterloo Rocketry Remote Launch Control System V3

    51 parts5MIT
  • 4 layers150 × 100 mmZynq eame 1, the printed circuit board in 3D

    Zynq eame 1

    DRubioG/Zynq-eame

    Projects based on Zynq SoCs

    185 parts3MIT

Questions

How big is the Try2 PCB?

It measures 14 × 14 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Try2 use?

10 parts, built around the MMBF170. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Try2 KiCad files?

From the SKGleba/psp2sdboot repository on GitHub, at the commit this page was made from: the board is pcb/generic/try2.kicad_pcb and its schematic pcb/generic/try2.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Try2 design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).