Talk:BD Drive Reverse Engineering

From PS3 Developer wiki
Revision as of 16:40, 24 December 2015 by Mysis (talk | contribs) (→‎SACD ripper)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Getting keys the easier way

EID4

First you need to get the sv_iso_spu_module.self individuals seed that can be found in the metadata header:

 3E C2 0C 17 02 19 01 97 8A 29 71 79 38 29 D3 08
 04 29 FA 84 E3 3E 7F 73 0C 1D 41 6E EA 25 CA FB
 3D E0 2B C0 05 EA 49 0B 03 E9 91 98 F8 3F 10 1F
 1B A3 4B 50 58 94 28 AD D2 B3 EB 3F F4 C3 1A 58

Using your console specific eid_root_key/iv (e.g. from metldr dump) and libeeid (insert the seed in keys.c) you can then decrypt EID4 directly by calling

 u8 eid4[0x30] = {/* your EID4 */};
 eid4_decrypt_buffer(eid4);

Now you got the two keys you need in eid4+0x00 and eid4+0x10 :)

EID2

First you need to get the fdm_spu_module.self individuals seed that can be found in the metadata header:

 74 92 E5 7C 2C 7C 63 F4 49 42 26 8F B4 1C 58 ED
 66 83 41 F9 C9 7B 29 83 96 FA 9D 82 07 51 99 D8
 BC 1A 93 4B 37 4F A3 8D 46 AF 94 C7 C3 33 73 B3
 09 57 20 84 FE 2D E3 44 57 E0 F8 52 7A 34 75 3D

Using your console specific eid_root_key/iv (e.g. from metldr dump) and libeeid (insert the seed, key and IV in keys.c) you can then decrypt EID2 directly by calling

 u8 eid2[0x730] = {/* your EID2 */};
 p_block = eid2_generate_block_buffer(p_block_enc, EID2_BLOCKTYPE_P);
 s_block = eid2_generate_block_buffer(s_block_enc, EID2_BLOCKTYPE_S);
 eid2_decrypt_block(p_block + 0x10, 0x60);
 eid2_decrypt_block(s_block + 0x10, 0x670);

SACD ripper

source: [1]


/* The generic packet command opcodes for CD/DVD Logical Units,
 * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
#define GPCMD_GET_CONFIGURATION		    0x46
#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
#define GPCMD_MODE_SELECT_10		    0x55
#define GPCMD_MODE_SENSE_10		    0x5a
#define GPCMD_READ_CD			    0xbe
#define GPCMD_READ_DVD_STRUCTURE	    0xad
#define GPCMD_READ_TRACK_RZONE_INFO	    0x52
#define GPCMD_READ_TOC_PMA_ATIP		    0x43
#define GPCMD_REPORT_KEY		    0xa4
#define GPCMD_SEND_KEY			    0xa3

#define LV2_STORAGE_SEND_ATAPI_COMMAND	(1)

struct lv2_atapi_cmnd_block {
    uint8_t pkt[32]; /* packet command block           */
    uint32_t pktlen; /* should be 12 for ATAPI 8020    */
    uint32_t blocks;
    uint32_t block_size;
    uint32_t proto; /* transfer mode                  */
    uint32_t in_out; /* transfer direction             */
    uint32_t unknown;
} __attribute__((packed));

typedef struct {
    int fd;
    uint64_t device_id;
    sys_ppu_thread_t thread_id;
    sys_mutex_t read_async_mutex_id;
    sys_event_queue_t queue;
	int io_buffer;
	int io_buffer_piece;
} sac_accessor_driver_t;

enum lv2_atapi_proto {
    NON_DATA_PROTO = 0,
    PIO_DATA_IN_PROTO = 1,
    PIO_DATA_OUT_PROTO = 2,
    DMA_PROTO = 3
};

enum lv2_atapi_in_out {
    DIR_WRITE = 0, /* memory -> device */
    DIR_READ = 1 /* device -> memory */
};


static inline void init_atapi_cmnd_block(
        struct lv2_atapi_cmnd_block *atapi_cmnd
        , uint32_t block_size
        , uint32_t proto
        , uint32_t type) {
    memset(atapi_cmnd, 0, sizeof(struct lv2_atapi_cmnd_block));
    atapi_cmnd->pktlen = 12;
    atapi_cmnd->blocks = 1;
    atapi_cmnd->block_size = block_size; /* transfer size is block_size * blocks */
    atapi_cmnd->proto = proto;
    atapi_cmnd->in_out = type;
}


static inline int sys_storage_send_atapi_command(uint32_t fd, struct lv2_atapi_cmnd_block *atapi_cmnd, uint8_t *buffer) {
    uint64_t tag;
    system_call_7(SYS_STORAGE_EXECUTE_DEVICE_COMMAND
            , fd
            , LV2_STORAGE_SEND_ATAPI_COMMAND
            , (uint32_t) atapi_cmnd
            , sizeof (struct lv2_atapi_cmnd_block)
            , (uint32_t) buffer
            , atapi_cmnd->block_size
            , (uint32_t) & tag);

    return_to_user_prog(int);
}


int ps3rom_lv2_get_configuration(int fd, uint8_t *buffer) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 0x10, PIO_DATA_IN_PROTO, DIR_READ);
    atapi_cmnd.pkt[0] = GPCMD_GET_CONFIGURATION;
    atapi_cmnd.pkt[1] = 0;
    atapi_cmnd.pkt[2] = 0xff;
    atapi_cmnd.pkt[3] = 0x41;
    atapi_cmnd.pkt[8] = 0x10;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);
    // if (buffer[10] & 1 == 0) return 0xF000FFFF
    // if (buffer[0] & 1 != 0) exec_mode_sense
    return res;
}

int ps3rom_lv2_mode_sense(int fd, uint8_t *buffer) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 0x10, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_MODE_SENSE_10;
    atapi_cmnd.pkt[1] = 0x08;
    atapi_cmnd.pkt[2] = 0x03;
    atapi_cmnd.pkt[8] = 0x10;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);
    // if (buffer[11] == 2) exec_mode_select
    return res;
}

int ps3rom_lv2_mode_select(int fd) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;
    static uint8_t buffer[256];
    memset(buffer, 0, sizeof (buffer));

    buffer[1] = 0x0e;
    buffer[7] = 8;
    buffer[8] = 3;
    buffer[9] = 6;
    buffer[11] = 3; // ? 3 == SACD
    buffer[255] = 0x10;

    init_atapi_cmnd_block(&atapi_cmnd, 0x10, PIO_DATA_OUT_PROTO, DIR_WRITE);

    atapi_cmnd.pkt[0] = GPCMD_MODE_SELECT_10;
    atapi_cmnd.pkt[1] = 0x10; /* PF */
    atapi_cmnd.pkt[8] = 0x10;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_enable_encryption(int fd, uint8_t *buffer, uint32_t lba) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 0x0a, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_READ_DVD_STRUCTURE;
    atapi_cmnd.pkt[1] = 2;
    
		atapi_cmnd.pkt[2] = lba >> 24; 
		atapi_cmnd.pkt[3] = lba >> 16;
		atapi_cmnd.pkt[4] = lba >> 8;
		atapi_cmnd.pkt[5] = lba & 0xff;
    
    atapi_cmnd.pkt[9] = 0x0a;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_get_event_status_notification(int fd, uint8_t *buffer) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 0x08, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
    atapi_cmnd.pkt[1] = 1; /* IMMED */
    atapi_cmnd.pkt[4] = 4; /* media event */
    atapi_cmnd.pkt[8] = 0x08;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_report_key_start(int fd, uint8_t *buffer) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 0x08, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_REPORT_KEY;

    atapi_cmnd.pkt[2] = 0;
    atapi_cmnd.pkt[3] = 0;
    atapi_cmnd.pkt[4] = 0;
    atapi_cmnd.pkt[5] = 0x08;

    atapi_cmnd.pkt[6] = 0;
    atapi_cmnd.pkt[7] = 0x10;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_send_key(int fd, uint8_t agid, uint32_t key_size, uint8_t *key, uint8_t sequence) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;
    uint32_t buffer_size;
    uint8_t buffer[256];
    uint8_t buffer_align = 0;
    
    if ((key_size & 3) != 0) {
      buffer_align = ~(key_size & 3) + 4 + 1;
    }
    buffer_size = key_size + 4 + buffer_align;

    init_atapi_cmnd_block(&atapi_cmnd, buffer_size, PIO_DATA_OUT_PROTO, DIR_WRITE);

    atapi_cmnd.pkt[0] = GPCMD_SEND_KEY;

		atapi_cmnd.pkt[2] = buffer_size >> 24; 
		atapi_cmnd.pkt[3] = buffer_size >> 16;
		atapi_cmnd.pkt[4] = buffer_size >> 8;
		atapi_cmnd.pkt[5] = buffer_size & 0xff;
    
    atapi_cmnd.pkt[6] = sequence;
    atapi_cmnd.pkt[7] = 0x10;
    atapi_cmnd.pkt[10] = agid;

		memset(buffer, 0, sizeof(buffer));

		buffer[0] = key_size >> 24; 
		buffer[1] = key_size >> 16;
		buffer[2] = key_size >> 8;
		buffer[3] = key_size & 0xff;
    memcpy(buffer + 4, key, key_size);

		if (buffer_align != 0) {
  		memset(buffer + key_size + 4, 0, buffer_align);
  	}

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_report_key(int fd, uint8_t agid, uint32_t *key_size, uint8_t *key, uint8_t sequence) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;
    uint32_t buffer_size;
    uint8_t buffer[256];
    uint8_t buffer_align = 0;
    uint32_t new_key_size, old_key_size = *key_size;

    memset(buffer, 0xff, sizeof(buffer));
    
    if ((old_key_size & 3) != 0) {
      buffer_align = ~(old_key_size & 3) + 4 + 1;
    }
    buffer_size = old_key_size + 4 + buffer_align;

    init_atapi_cmnd_block(&atapi_cmnd, buffer_size, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_REPORT_KEY;

		atapi_cmnd.pkt[2] = buffer_size >> 24; 
		atapi_cmnd.pkt[3] = buffer_size >> 16;
		atapi_cmnd.pkt[4] = buffer_size >> 8;
		atapi_cmnd.pkt[5] = buffer_size & 0xff;

    atapi_cmnd.pkt[6] = sequence;
    atapi_cmnd.pkt[7] = 0x10;
    atapi_cmnd.pkt[10] = agid;
    
    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    new_key_size = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
    *key_size = new_key_size;

    memcpy(key, buffer + 4, (old_key_size > new_key_size ? new_key_size : old_key_size));

    return res;
}

int ps3rom_lv2_report_key_finish(int fd, uint8_t agid) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 0, NON_DATA_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_REPORT_KEY;

    atapi_cmnd.pkt[6] = 0xff;
    atapi_cmnd.pkt[7] = 0x10;
    atapi_cmnd.pkt[10] = agid;

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, 0);

    return res;
}


int ps3rom_lv2_read_toc_header(int fd, uint8_t *buffer) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 12, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_READ_TOC_PMA_ATIP;
    atapi_cmnd.pkt[6] = 0;
    atapi_cmnd.pkt[8] = 12; /* LSB of length */

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_read_toc_entry(int fd, uint8_t *buffer) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 12, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_READ_TOC_PMA_ATIP;
    atapi_cmnd.pkt[6] = 0x01;
    atapi_cmnd.pkt[8] = 12; /* LSB of length */

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}

int ps3rom_lv2_read_track(int fd, uint8_t *buffer, uint8_t track) {
    int res;
    struct lv2_atapi_cmnd_block atapi_cmnd;

    init_atapi_cmnd_block(&atapi_cmnd, 48, PIO_DATA_IN_PROTO, DIR_READ);

    atapi_cmnd.pkt[0] = GPCMD_READ_TRACK_RZONE_INFO;
    atapi_cmnd.pkt[1] = 1;
    atapi_cmnd.pkt[5] = track; /* track */
    atapi_cmnd.pkt[8] = 48; /* LSB of length */

    res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer);

    return res;
}