summaryrefslogtreecommitdiffstats
path: root/wii_wad.c
blob: 792c84cfc115457e1c0920ef9d4681d1d55be7a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
 * wii_wad.c
 */

#include <stdio.h>
#include <string.h>
#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;
}