/** * wii_wad.c */ #include #include #include "wii_wad.h" #include "crypto.h" #include "ucs.h" void print_wad(wad_header *wad) { printf("- wad_header\n"); printf("size : %1$08x (%1$d)\n", wad->size); printf("type : %04x (%.2s)\n", wad->type, (char*)&wad->type); printf("unknown : %04x\n", wad->unk0); printf("cert_chain_size : %1$08x (%1$d)\n", wad->cert_chain_size); printf("crl_size : %1$08x (%1$d)\n", wad->crl_size); printf("ticket_size : %1$08x (%1$d)\n", wad->ticket_size); printf("tmd_size : %1$08x (%1$d)\n", wad->tmd_size); printf("data_size : %1$08x (%1$d)\n", wad->data_size); printf("footer_size : %1$08x (%1$d)\n", wad->footer_size); } int wad_read(FILE *f, wad_header *wad) { /* read head into struct */ fread(wad, sizeof(wad_header), 1, f); /* convert to big endian */ wad->size = be32((u8*)&wad->size); if (wad->size != 0x20) return 0; //wad->type = be16((u8*)&wad->type); wad->unk0 = be16((u8*)&wad->unk0); wad->cert_chain_size = be32((u8*)&wad->cert_chain_size); wad->crl_size = be32((u8*)&wad->crl_size); wad->ticket_size = be32((u8*)&wad->ticket_size); wad->tmd_size = be32((u8*)&wad->tmd_size); wad->data_size = be32((u8*)&wad->data_size); wad->footer_size = be32((u8*)&wad->footer_size); if (wad->ticket_size == 0) return 0; if (wad->tmd_size == 0) return 0; if (wad->data_size == 0) return 0; if (wad->footer_size == 0) return 0; return 1; } void wad_read_tmd(FILE *f, wad_header *wad, tmd_header *tmd) { u32 rounded_len; rounded_len = round_up(wad->size + wad->cert_chain_size + wad->ticket_size, 0x40); /* seek to tmd start offset */ fseek(f, rounded_len, SEEK_SET); tmd_read(f, tmd); } void wad_read_tik(FILE *f, wad_header *wad, tmd_header *tmd, wii_tik *tik) { u32 rounded_len; rounded_len = round_up(wad->size + wad->cert_chain_size, 0x40); /* seek to tik start offset */ fseek(f, rounded_len, SEEK_SET); tik_read(f, tik); } void wad_read_app_info(FILE *f, wad_header *wad, tmd_content_record *tmd_content, wii_tik *tik, wii_build_info *bi, wii_imet *imet) { u8 title_key[16]; u8 iv[16]; u32 rounded_len; u32 data_len; u8 *data; u16 i; /* decrypt_title_key */ decrypt_title_key(tik, title_key); /* read wad data chunk */ data_len = round_up(wad->data_size, 0x40); data = malloc(data_len); rounded_len = wad_get_section_offset(wad, SECTION_DATA); fseek(f, rounded_len, SEEK_SET); fread(data, data_len, 1, f); rounded_len = round_up(tmd_content->size, 0x40); i = be16((u8*)&tmd_content->index); /* decrypt first content */ memset(iv, 0, sizeof(iv)); memcpy(iv, &i, 2); aes_cbc_dec(title_key, iv, data, rounded_len, data); /* read buildinfo */ memset(bi, 0, sizeof(wii_build_info)); memcpy((u8*)bi, data, sizeof(wii_build_info)); /*. parse first content's IMET tag */ memset(imet, 0, sizeof(wii_imet)); memcpy((u8*)imet, data + IMET_OFFSET, sizeof(wii_imet)); for (i = 0; i < IMET_NAME_COUNT; i++) { beucs2(imet->name[i]); } free(data); } u32 wad_get_section_offset(wad_header *wad, u8 section) { u32 ret = 0; switch(section) { case SECTION_FOOTER: ret += round_up(wad->data_size, 0x40); case SECTION_DATA: ret += round_up(wad->tmd_size, 0x40); case SECTION_TMD: ret += round_up(wad->ticket_size, 0x40); case SECTION_TICKET: ret += round_up(wad->cert_chain_size, 0x40); case SECTION_CERT_CHAIN: ret += round_up(wad->size, 0x40); case SECTION_WAD_HEADER: break; } return ret; }