Talk:BD Drive Reverse Engineering
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; }