SC Communication: Difference between revisions
Jump to navigation
Jump to search
Line 79: | Line 79: | ||
| 0x20 || Syscon Debug Output(?) - Used to send a string to syscon. | | 0x20 || Syscon Debug Output(?) - Used to send a string to syscon. | ||
|- | |- | ||
| 0x2D || | | 0x2D || Syscon Patch Servuce | ||
|- | |- | ||
| 0x30 || A/V Service. | | 0x30 || A/V Service. | ||
|- | |||
| 0x50 || Storage Service | |||
|- | |- | ||
| 0x1F || Authenticated Services. (sc_secure_service) | | 0x1F || Authenticated Services. (sc_secure_service) |
Revision as of 15:39, 27 January 2020
Introduction
- The following information was reverse engineered from lv0ldr, lv0, lv1.self, and Iso module sc_iso.self.
- Big thanks to graf_chokolo for a large part of the basis of this page, and to Jestero for Syscon Authentication info!
Overview of Syscon Communication
- Syscon lives at the mmio space of 0x24000080000.
- Communication occurs through mmio read/writes.
List of known offsets in Syscon:
Offset (from start of address space) | Size | Description |
---|---|---|
0xC000 | 0xFF0 | Syscon packet send area |
0xCFF0 | 0x4 | Syscon sent packet counter |
0xCFF4 | 0x4 | Syscon sent packet acknowledge counter |
0xD000 | 0xFF0 | Syscon packet receive area |
0xDFF0 | 0x4 | Syscon received packet counter |
0xDFF4 | 0x4 | Syscon received packet acknowledge counter |
0xE100 | 0x4 | Tells syscon there is a packet to be received |
Quick explanation of the packet counters:
- There are two counters that are incremented by each side (Cell / Syscon).
- 0xCFF0 and 0xDFF0 are incremented by the sending side (Syscon for 0xCFF0, Cell for 0xDFF0)
- 0xCFF4 and 0xDFF4 are incremented by the receiving side (Cell for 0xCFF4, Syscon for 0xDFF4)
Syscon Services
- To be completed... (see Discussion page for examples)
SERV_INTR_NOTIF 0x17 SERV_LS 0x40 SERV STORAGE 0x50 SERV_Patch 0x2D SERV VERS 0x18 SERV LIVELOCK 0x1B SERV OSWDT 0x1C SERV SIRCS 0x15 SERV NOTIF 0x16 SERV NVS 0x14 SERV DEVPM 0x10 SERV SETCFG 0x12 SERV SDA 0x3 SERV SYSPM 0x13
Service ID | Description |
---|---|
0x03 | Device Access Service - Used for eeprom read/write. |
0x10 | PS2 PCI Bus Power On/Off |
0x11 | Time Zone Presence, Temperature, Thermal Alert Mode, |
0x12 | Config Info Service (BE Count, Error Log....) |
0x13 | Power Service - Controls system power and related info. (Power Up/Power Button Mode, Wake Source, RTC too.) |
0x14 | NVS Service - Used for eeprom read/write. |
0x16 | LED / Buzzer Service - Controls the lights on the console and the ring buzzer. |
0x18 | Version Service - Versioning related (SC Type/Major-,Minor Version) |
0x1B | Livelock(?) Service - Checks for permission to use other services. |
0x20 | Syscon Debug Output(?) - Used to send a string to syscon. |
0x2D | Syscon Patch Servuce |
0x30 | A/V Service. |
0x50 | Storage Service |
0x1F | Authenticated Services. (sc_secure_service) |
0xFF | Syscon Init (Seen in lv0ldr init sequence to syscon: User_talk:JuanNadie) |
Syscon Packet Headers
- Some useful packet headers...
- If the header is shorter than 0x10, you must add your own size.
- If greater than 0x10, it's a full packet ;)
What? | Description | Data | Notes |
---|---|---|---|
AUTH1 | AUTH1 Header | 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30 |
On AUTH1 UART SC Packets it's instead 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
AUTH2 | AUTH2 Header | 0x1F, 0x01, 0x00, 0x01, 0x00, 0x00, 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30 |
On AUTH2 UART SC Packets it's instead 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
Debug Output | Sends string to Syscon TTY | 0x20, 0x01, 0x00, 0x07, 0x00, 0x00, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00 |
Start message with 0x00. Will print as much as packet length. |
Triple Beep | 0x16, 0x01, 0x16, 0x20, 0x00, 0x00, 0x80, 0x4D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x08, 0x20, 0x29, 0x0A, 0x00, 0x00, 0x00, 0x01, 0xB6 |
||
Shutdown | 0x13, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 |
Will not gracefully shut down HD. | |
Soft Restart | 0x13, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x11, 0x00, 0x00, 0x01 |
Restarts, but doesn't kill power between boots. | |
Hard Restart | 0x13, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x11, 0x00, 0x00, 0x02 |
Restarts, but kills power between boots. | |
Panic | 0x13, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x11, 0x00, 0x00, 0x03 |
Shuts down, beeps, and kills power LED until power button pressed, or power removed. |
Syscon Authentication
- An IV of 0x00 is used for most AES steps.
Step 1 - Generate Individual Seeds
Encrypt sc_iso metadata seeds w/ eid root key / iv.
aes256cbc_enc(eid_root_erk, eid_root_riv, sc_module_seeds, 0x40, sc_module_seeds);
Step 2 - Generate SC_ISO encrypted keys
Encrypt the sc_key_seeds.
indiv_key = sc_module_seeds + 0x20; for (int i = 0; i < 0x100; i += 0x10) aes256cbc_enc(indiv_key, zero_iv, key_seeds + i, 0x10, enc_key_seeds + i);
Step 3 - Authenticate with Syscon
Pick a session_id. Must be <= 7.
Step 3a - Secure Packet Header
struct secure_payload_header { u8 session_id; u8 seq_service_id; //service_ID (Unsecure uses 0xFF, AUTH1 = 0x02, AUTH2 = 0x03, READ_DATA = 0x04, WRITE_DATA = 0x05) u8 packet_type; //0xFF for BE->SC, 0x00 for SC->BE (if success) u8 magic[0x2]; //0xAD1A u8 prng_random[0xB] //Random shit for padding };
Step 3b - AUTH 1 to SC
uint8_t random_shit[0x10]; auth_key_1_0x01 = enc_key_seeds + (session_id * (0x10*2)); auth_key_2_0x01 = enc_key_seeds + (session_id * (0x10*2) + 0x10); //generating random payload for auth1 rnd_gen(random_shit, 0x10); //create auth1 random data aes128cbc_enc(auth_key_1_0x01, zero_iv, random_shit, 0x10, secure_payload_buf + 0x10); //length = 0x20 //Create secure header/footer // create header: 5 bytes + random stuff (0xb) payload_header->session_id = session_id; payload_header->seq_service_id = seq_service_id++; // starts at 0 payload_header->packet_type = 0xFF; payload_header->magic[0] = 0xAD; payload_header->magic[1] = 0x1A; rnd_gen((u8*) &payload_header->prng_random, 0x0B); //encrypt payload aes128cbc_enc(be2sc_key, zero_iv, secure_payload_buf, length, secure_payload_buf); // create footer: omac1 of the whole packet aesOmac1Mode(secure_payload_buf + length, secure_payload_buf, length, be2sc_key, sizeof(be2sc_key)*8); //Set regular header memcpy(sc_packet, auth1_pkt_header, 0x10); //Send packet. 0x40 Bytes
Step 3c - Validate AUTH1
First, check the header/footer.
- Calculate AES OMAC over the packet length and compare to OMAC from syscon. Use sc2be key.
- Decrypt internal packet with sc2be key. Use AES128CBC
- Compare returned session_id and seq_service_id.
- Check secure_payload_buf[0x2] == 0.
Then check the AUTH1 response
// decrypt secure_payload for (i = 0x0; i < 0x20; i += 0x10) aes128cbc(auth_key_2_0x01, zero_iv, secure_payload_buf + 0x10 + i, 0x10, secure_payload_buf + 0x10 + i); // check if challange returned from syscon is correct res = memcmp(secure_payload_buf + 0x10, random_shit, 0x10); if (res != 0) return -1; // save the new challange needed for AUTH2 memcpy(auth_challenge, secure_payload_buf + 0x20, 0x10);
Step 3d - AUTH2 to SC
//AUTH2 Challenge Payload aes128cbc_enc(auth_key_1_0x01, zero_iv, auth_challenge, 0x10, secure_payload_buf + 0x10); //length = 0x20 //Create secure header/footer // create header: 5 bytes + random stuff (0xb) payload_header->session_id = session_id; payload_header->seq_service_id = seq_service_id++; // starts at 0 payload_header->packet_type = 0xFF; payload_header->magic[0] = 0xAD; payload_header->magic[1] = 0x1A; rnd_gen((u8*) &payload_header->prng_random, 0x0B); //encrypt payload aes128cbc_enc(be2sc_key, zero_iv, secure_payload_buf, length, secure_payload_buf); // create footer: omac1 of the whole packet aesOmac1Mode(secure_payload_buf + length, secure_payload_buf, length, be2sc_key, sizeof(be2sc_key)*8); //Set regular header memcpy(sc_packet, auth2_pkt_header, 0x10); //Put packet - 0x40 packet length
Step 3e - Validate AUTH2
Again, check the header/footer.
- Calculate AES OMAC over the packet length and compare to OMAC from syscon. Use sc2be key.
- Decrypt internal packet with sc2be key. Use AES128-CBC
- Compare returned session_id and seq_service_id.
- Check secure_payload_buf[0x2] == 0.
// encrypt random_shit using auth_challenge (returned from AUTH1 reply) as key and 0 IV aes128cbc_enc(auth_challenge, zero_iv, random_shit, 0x10, session_key); // encrypt result in place with session_key_create[0x10 * sess_id] and IV 0 (result will be the session_key) aes128cbc_enc(session_key_create + (session_id * 0x10), zero_iv, session_key, 0x10, session_key); // use the session_key to decrypt auth2_payload in place (0x10) aes128cbc(session_key, zero_iv, secure_payload_buf + 0x10, 0x10, secure_payload_buf + 0x10); // compare the result with a 0x10 zero string res = memcmp(secure_payload_buf + 0x10, zero_iv, 0x10); //res == 0x0 is good.
Step 4 - Profit?
You are now authenticated with syscon, and can use privileged commands. Just use the session_key calculated from the AUTH2 reply to encrypt/decrypt responses.
Some Samples from DYN-001 Syscon SPI SC Comms
00 70 0B 93 FF DC CF 43 97 68 49 06 71 32 27 C1 E8 9F D1 73 DA 4D FA A2 7C 6F 24 F7 BD 95 37 EC F9 17 5B BB DB 32 E8 82 55 3F 51 23 F1 71 E6 88