about summary refs log tree commit diff stats
path: root/source/multiboot.c
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-07-13 20:38:04 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-07-13 20:38:04 -0400
commit2190722ac1f0732cf35e7b63572afa698a47789d (patch)
tree004d2302ece1d9f8feb4d3d435d0393739ebd1bd /source/multiboot.c
parent252e2911383a5267673f00c08419e2afeac35a31 (diff)
downloadgen3uploader-2190722ac1f0732cf35e7b63572afa698a47789d.tar.gz
gen3uploader-2190722ac1f0732cf35e7b63572afa698a47789d.tar.bz2
gen3uploader-2190722ac1f0732cf35e7b63572afa698a47789d.zip
Organized code more
Now the link-specific stuff is abstracted into its own file, and the
code for negotiating the "different" multiboot protocol is in its own
file. Also, removed support for compiling for GC because eventually we
will be using Wii-only features. Also put the main extractor code into a
thread so that we can monitor for the user pressing the start button to
exit.
Diffstat (limited to 'source/multiboot.c')
-rw-r--r--source/multiboot.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/source/multiboot.c b/source/multiboot.c new file mode 100644 index 0000000..06cbd6f --- /dev/null +++ b/source/multiboot.c
@@ -0,0 +1,246 @@
1#include "multiboot.h"
2#include <gccore.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include "link.h"
7
8extern u8 gba_mb_gba[];
9extern u32 gba_mb_gba_size;
10
11unsigned int docrc(u32 crc,u32 val)
12{
13 u32 result;
14
15 result = val ^ crc;
16 for (int i = 0; i < 0x20; i++)
17 {
18 if (result & 1)
19 {
20 result >>= 1;
21 result ^= 0xA1C1;
22 } else {
23 result >>= 1;
24 }
25 }
26
27 return result;
28}
29
30u32 genKeyA()
31{
32 u32 retries = 0;
33
34 for (;;)
35 {
36 u32 key = 0;
37
38 if (retries > 32)
39 {
40 key = 0xDD654321;
41 } else {
42 key = (rand() & 0x00ffffff) | 0xDD000000;
43 }
44
45 u32 unk = (key % 2 != 0);
46 u32 v12 = key;
47 for (u32 v13 = 1; v13 < 32; v13++)
48 {
49 v12 >>= 1;
50 unk += (v12 % 2 != 0);
51 }
52
53 if ((unk >= 10 && unk <= 24))
54 {
55 if (retries > 4)
56 {
57 printf("KeyA retries = %ld", retries);
58 }
59
60 printf("KeyA = 0x%08lx\n", key);
61
62 return key;
63 }
64
65 retries++;
66 }
67}
68
69u32 checkKeyB(u32 KeyBRaw)
70{
71 if ((KeyBRaw & 0xFF) != 0xEE)
72 {
73 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",
74 ((u8)(KeyBRaw)));
75
76 return 0;
77 }
78
79 u32 KeyB = KeyBRaw & 0xffffff00;
80 u32 val = KeyB;
81 u32 unk = (val < 0);
82 for (u32 i = 1; i < 24; i++)
83 {
84 val <<= 1;
85 unk += (val < 0);
86 }
87
88 if (unk > 14)
89 {
90 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n", KeyB);
91
92 return 0;
93 }
94
95 printf("Valid KeyB: 0x%08lx\n", KeyB);
96
97 return KeyB;
98}
99
100u32 deriveKeyC(u32 keyCderive, u32 kcrc)
101{
102 u32 keyc = 0;
103 u32 keyCi = 0;
104
105 do
106 {
107 u32 v5 = 0x1000000 * keyCi - 1;
108 u32 keyCattempt = docrc(kcrc,v5);
109
110 if (keyCderive == keyCattempt)
111 {
112 keyc = v5;
113
114 printf("Found keyC: %08lx\n",keyc);
115
116 return keyc;
117 }
118
119 keyCi++;
120 } while (keyCi < 256);
121
122 return keyc;
123}
124
125bool sendMultibootImage()
126{
127 printf("Waiting on BIOS\n");
128 waitForBIOS();
129
130 printf("BIOS handed over to game, waiting on game\n");
131 waitForGame();
132
133 // receive the game-code from GBA side.
134 u32 gamecode = recv();
135
136 printf("Ready, sending multiboot ROM\n");
137
138 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
139
140 // generate KeyA
141 unsigned int ourkey = genKeyA();
142
143 //printf("Our Key: %08x\n", ourkey);
144 printf("Sending game code that we got: 0x%08lx\n",
145 __builtin_bswap32(gamecode));
146
147 // send the game code back, then KeyA.
148 send(__builtin_bswap32(gamecode));
149 send(ourkey);
150
151 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA
152 // to derive the initial CRC value and the sessionkey.
153 u32 sessionkeyraw = 0;
154 do
155 {
156 sessionkeyraw = recv();
157 } while (sessionkeyraw == gamecode);
158
159 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
160 if (sessionkeyraw == 0)
161 {
162 return false;
163 }
164
165 u32 sessionkey = sessionkeyraw ^ ourkey;
166 u32 kcrc = sessionkey;
167 printf("start kCRC=%08lx\n",kcrc);
168
169 sessionkey = (sessionkey*0x6177614b)+1;
170
171 // send hacked up send-size in uint32s
172 u32 hackedupsize = (sendsize >> 3) - 1;
173
174 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
175 send(hackedupsize);
176
177 //unsigned int fcrc = 0x00bb;
178 // send over multiboot binary header, in the clear until the end of the
179 // nintendo logo. GBA checks this, if nintendo logo does not match the
180 // one in currently inserted cart's ROM, it will not accept any more data.
181 for (int i = 0; i < 0xA0; i+=4)
182 {
183 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
184 send(__builtin_bswap32(rom_dword));
185 }
186
187 printf("\n");
188 printf("Header done! Sending ROM...\n");
189
190 // Add each uint32 of the multiboot image to the checksum, encrypt the
191 // uint32 with the session key, increment the session key, send the
192 // encrypted uint32.
193 for (int i = 0xA0; i < sendsize; i+=4)
194 {
195 u32 dec = (
196 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
197 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
198 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
199 (((gba_mb_gba[i]) << 0) & 0x000000ff)
200 );
201
202 u32 enc = (dec - kcrc) ^ sessionkey;
203 kcrc = docrc(kcrc,dec);
204 sessionkey = (sessionkey * 0x6177614B) + 1;
205 //enc^=((~(i+(0x20<<20)))+1);
206 //enc^=0x6f646573;//0x20796220;
207
208 send(enc);
209 }
210
211 //fcrc |= (sendsize<<16);
212 printf("ROM done! CRC: %08lx\n", kcrc);
213 //get crc back (unused)
214
215 // Get KeyC derivation material from GBA (eventually)
216 u32 keyCderive = 0;
217 do
218 {
219 keyCderive = recv();
220 } while (keyCderive <= 0xfeffffff);
221
222 keyCderive = __builtin_bswap32(keyCderive);
223 keyCderive >>= 8;
224
225 printf("KeyC derivation material: %08lx\n",keyCderive);
226
227 // (try to) find the KeyC, using the checksum of the multiboot image, and
228 // the derivation material that GBA sent to us
229 u32 keyc = deriveKeyC(keyCderive,kcrc);
230 if (keyc == 0)
231 {
232 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
233
234 return false;
235 }
236
237 // derive the boot key from the found KeyC, and send to GBA. if this is
238 // not correct, GBA will not jump to the multiboot image it was sent.
239 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
240 printf("BootKey = 0x%08lx\n",bootkey);
241
242 send(bootkey);
243 sleep(2);
244
245 return true;
246}