Talk:BD Drive Reverse Engineering

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.

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;
}