about summary refs log tree commit diff stats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/link.c16
-rw-r--r--source/link.h8
-rw-r--r--source/main.c1287
3 files changed, 852 insertions, 459 deletions
diff --git a/source/link.c b/source/link.c new file mode 100644 index 0000000..7229191 --- /dev/null +++ b/source/link.c
@@ -0,0 +1,16 @@
1#include "link.h"
2
3u32 waitForButtons(u32 mask)
4{
5 for (;;)
6 {
7 PAD_ScanPads();
8 VIDEO_WaitVSync();
9
10 u32 btns = PAD_ButtonsDown(0);
11 if (btns & mask)
12 {
13 return btns;
14 }
15 }
16}
diff --git a/source/link.h b/source/link.h new file mode 100644 index 0000000..4e536b4 --- /dev/null +++ b/source/link.h
@@ -0,0 +1,8 @@
1#ifndef _LINK_H_
2#define _LINK_H_
3
4#include <gccore.h>
5
6u32 waitForButtons(u32 mask);
7
8#endif
diff --git a/source/main.c b/source/main.c index 7fd5683..79fd2fc 100644 --- a/source/main.c +++ b/source/main.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 hatkirby
2 * Copyright (C) 2016 FIX94 3 * Copyright (C) 2016 FIX94
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
@@ -15,6 +16,7 @@
15#include <fcntl.h> 16#include <fcntl.h>
16#include <dirent.h> 17#include <dirent.h>
17#include <fat.h> 18#include <fat.h>
19#include "link.h"
18 20
19//from my tests 50us seems to be the lowest 21//from my tests 50us seems to be the lowest
20//safe si transfer delay in between calls 22//safe si transfer delay in between calls
@@ -25,11 +27,12 @@ extern u32 gba_mb_gba_size;
25 27
26void printmain() 28void printmain()
27{ 29{
28 printf("\x1b[2J"); 30 printf("\x1b[2J");
29 printf("\x1b[37m"); 31 printf("\x1b[37m");
30 printf("GBA Link Cable Dumper v1.6 by FIX94\n"); 32 printf("Pokemon Gen III Data Extractor by hatkirby\n");
31 printf("Save Support based on SendSave by Chishm\n"); 33 printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n");
32 printf("GBA BIOS Dumper by Dark Fader\n \n"); 34 printf("Save Support based on SendSave by Chishm\n");
35 printf("Save Structure based on gba-gen3multiboot by slipstream/RoL\n");
33} 36}
34 37
35u8 *resbuf,*cmdbuf; 38u8 *resbuf,*cmdbuf;
@@ -37,520 +40,886 @@ u8 *resbuf,*cmdbuf;
37volatile u32 transval = 0; 40volatile u32 transval = 0;
38void transcb(s32 chan, u32 ret) 41void transcb(s32 chan, u32 ret)
39{ 42{
40 transval = 1; 43 transval = 1;
41} 44}
42 45
43volatile u32 resval = 0; 46volatile u32 resval = 0;
44void acb(s32 res, u32 val) 47void acb(s32 res, u32 val)
45{ 48{
46 resval = val; 49 resval = val;
47} 50}
48 51/*
49unsigned int docrc(u32 crc, u32 val) 52unsigned int docrc(u32 crc, u32 val)
50{ 53{
51 int i; 54 int i;
52 for(i = 0; i < 0x20; i++) 55 for (i = 0; i < 0x20; i++)
53 { 56 {
54 if((crc^val)&1) 57 if ((crc ^ val) & 1)
55 { 58 {
56 crc>>=1; 59 crc>>=1;
57 crc^=0xa1c1; 60 crc^=0xa1c1;
58 } 61 } else {
59 else 62 crc>>=1;
60 crc>>=1; 63 }
61 val>>=1; 64
65 val>>=1;
66 }
67
68 return crc;
69}*/
70unsigned int docrc(u32 crc,u32 val) {
71 u32 result;
72
73 result = val ^ crc;
74 for (int i = 0; i < 0x20; i++) {
75 if (result & 1) {
76 result >>= 1;
77 result ^= 0xA1C1;
78 } else result >>= 1;
62 } 79 }
63 return crc; 80 return result;
64} 81}
65 82
66void endproc()
67{
68 printf("Start pressed, exit\n");
69 VIDEO_WaitVSync();
70 VIDEO_WaitVSync();
71 exit(0);
72}
73void fixFName(char *str) 83void fixFName(char *str)
74{ 84{
75 u8 i = 0; 85 u8 i = 0;
76 for(i = 0; i < strlen(str); ++i) 86 for (i = 0; i < strlen(str); ++i)
77 { 87 {
78 if(str[i] < 0x20 || str[i] > 0x7F) 88 if (str[i] < 0x20 || str[i] > 0x7F)
79 str[i] = '_'; 89 {
80 else switch(str[i]) 90 str[i] = '_';
81 { 91 } else {
82 case '\\': 92 switch (str[i])
83 case '/': 93 {
84 case ':': 94 case '\\':
85 case '*': 95 case '/':
86 case '?': 96 case ':':
87 case '\"': 97 case '*':
88 case '<': 98 case '?':
89 case '>': 99 case '\"':
90 case '|': 100 case '<':
91 str[i] = '_'; 101 case '>':
92 break; 102 case '|':
93 default: 103 str[i] = '_';
94 break; 104 break;
95 } 105 default:
96 } 106 break;
107 }
108 }
109 }
97} 110}
111
98unsigned int calckey(unsigned int size) 112unsigned int calckey(unsigned int size)
99{ 113{
100 unsigned int ret = 0; 114 unsigned int ret = 0;
101 size=(size-0x200) >> 3; 115 size= (size - 0x200) >> 3;
102 int res1 = (size&0x3F80) << 1; 116 int res1 = (size & 0x3F80) << 1;
103 res1 |= (size&0x4000) << 2; 117 res1 |= (size & 0x4000) << 2;
104 res1 |= (size&0x7F); 118 res1 |= (size & 0x7F);
105 res1 |= 0x380000; 119 res1 |= 0x380000;
106 int res2 = res1; 120 int res2 = res1;
107 res1 = res2 >> 0x10; 121 res1 = res2 >> 0x10;
108 int res3 = res2 >> 8; 122 int res3 = res2 >> 8;
109 res3 += res1; 123 res3 += res1;
110 res3 += res2; 124 res3 += res2;
111 res3 <<= 24; 125 res3 <<= 24;
112 res3 |= res2; 126 res3 |= res2;
113 res3 |= 0x80808080; 127 res3 |= 0x80808080;
114 128
115 if((res3&0x200) == 0) 129 if ((res3 & 0x200) == 0)
116 { 130 {
117 ret |= (((res3)&0xFF)^0x4B)<<24; 131 ret |= (((res3) & 0xFF) ^ 0x4B) << 24;
118 ret |= (((res3>>8)&0xFF)^0x61)<<16; 132 ret |= (((res3>>8) & 0xFF) ^ 0x61) << 16;
119 ret |= (((res3>>16)&0xFF)^0x77)<<8; 133 ret |= (((res3>>16) & 0xFF) ^ 0x77) << 8;
120 ret |= (((res3>>24)&0xFF)^0x61); 134 ret |= (((res3>>24) & 0xFF) ^ 0x61);
121 } 135 } else {
122 else 136 ret |= (((res3) & 0xFF) ^ 0x73) << 24;
123 { 137 ret |= (((res3>>8) & 0xFF) ^ 0x65) << 16;
124 ret |= (((res3)&0xFF)^0x73)<<24; 138 ret |= (((res3>>16) & 0xFF) ^ 0x64) << 8;
125 ret |= (((res3>>8)&0xFF)^0x65)<<16; 139 ret |= (((res3>>24) & 0xFF) ^ 0x6F);
126 ret |= (((res3>>16)&0xFF)^0x64)<<8; 140 }
127 ret |= (((res3>>24)&0xFF)^0x6F); 141
128 } 142 return ret;
129 return ret;
130} 143}
144
131void doreset() 145void doreset()
132{ 146{
133 cmdbuf[0] = 0xFF; //reset 147 cmdbuf[0] = 0xFF; //reset
134 transval = 0; 148 transval = 0;
135 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 149 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
136 while(transval == 0) ; 150
151 while (transval == 0);
137} 152}
153
138void getstatus() 154void getstatus()
139{ 155{
140 cmdbuf[0] = 0; //status 156 cmdbuf[0] = 0; //status
141 transval = 0; 157 transval = 0;
142 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 158 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
143 while(transval == 0) ; 159
160 while (transval == 0);
161}
162
163void endproc()
164{
165 doreset();
166 printf("Start pressed, exit\n");
167 VIDEO_WaitVSync();
168 VIDEO_WaitVSync();
169 exit(0);
170}
171
172void fsleep(int i)
173{
174 sleep(i);
175 /*PAD_ScanPads();
176 if (PAD_ButtonsDown(0) & PAD_BUTTON_START)
177 {
178 getstatus();
179 endproc();
180 }*/
144} 181}
182
145u32 recv() 183u32 recv()
146{ 184{
147 memset(resbuf,0,32); 185 memset(resbuf,0,32);
148 cmdbuf[0]=0x14; //read 186 cmdbuf[0]=0x14; //read
149 transval = 0; 187 transval = 0;
150 SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,SI_TRANS_DELAY); 188 SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY);
151 while(transval == 0) ; 189
152 return *(vu32*)resbuf; 190 while (transval == 0);
191 printf("%08lx\n", *(vu32*)resbuf);
192 return *(vu32*)resbuf;
153} 193}
194
154void send(u32 msg) 195void send(u32 msg)
155{ 196{
156 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF; 197 cmdbuf[0] = 0x15;
157 cmdbuf[3]=(msg>>16)&0xFF;cmdbuf[4]=(msg>>24)&0xFF; 198 cmdbuf[1] = (msg >> 0) & 0xFF;
158 transval = 0; 199 cmdbuf[2] = (msg >> 8) & 0xFF;
159 resbuf[0] = 0; 200 cmdbuf[3] = (msg >> 16) & 0xFF;
160 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY); 201 cmdbuf[4] = (msg >> 24) & 0xFF;
161 while(transval == 0) ; 202
203 transval = 0;
204 resbuf[0] = 0;
205 SI_Transfer(1, cmdbuf, 5, resbuf, 1, transcb, SI_TRANS_DELAY);
206
207 while (transval == 0);
162} 208}
209
163bool dirExists(const char *path) 210bool dirExists(const char *path)
164{ 211{
165 DIR *dir; 212 DIR *dir = opendir(path);
166 dir = opendir(path); 213 if (dir)
167 if(dir) 214 {
168 { 215 closedir(dir);
169 closedir(dir); 216
170 return true; 217 return true;
171 } 218 }
172 return false; 219
220 return false;
173} 221}
222
174void createFile(const char *path, size_t size) 223void createFile(const char *path, size_t size)
175{ 224{
176 int fd = open(path, O_WRONLY|O_CREAT); 225 int fd = open(path, O_WRONLY | O_CREAT);
177 if(fd >= 0) 226 if (fd >= 0)
178 { 227 {
179 ftruncate(fd, size); 228 ftruncate(fd, size);
180 close(fd); 229 close(fd);
181 } 230 }
182} 231}
232
183void warnError(char *msg) 233void warnError(char *msg)
184{ 234{
185 puts(msg); 235 puts(msg);
186 VIDEO_WaitVSync(); 236 VIDEO_WaitVSync();
187 VIDEO_WaitVSync(); 237 VIDEO_WaitVSync();
188 sleep(2); 238 sleep(2);
189} 239}
240
190void fatalError(char *msg) 241void fatalError(char *msg)
191{ 242{
192 puts(msg); 243 puts(msg);
193 VIDEO_WaitVSync(); 244 VIDEO_WaitVSync();
194 VIDEO_WaitVSync(); 245 VIDEO_WaitVSync();
195 sleep(5); 246 sleep(5);
196 exit(0); 247 exit(0);
197} 248}
198int main(int argc, char *argv[]) 249
199{ 250u32 genKeyA() {
200 void *xfb = NULL; 251 u32 retries = 0;
201 GXRModeObj *rmode = NULL; 252 while (true) {
202 VIDEO_Init(); 253 u32 key = 0;
203 rmode = VIDEO_GetPreferredMode(NULL); 254 if (retries > 32) {
204 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); 255 key = 0xDD654321;
205 VIDEO_Configure(rmode); 256 } else {
206 VIDEO_SetNextFramebuffer(xfb); 257 key = (rand() & 0x00ffffff) | 0xDD000000;
207 VIDEO_SetBlack(FALSE); 258 }
208 VIDEO_Flush(); 259 u32 unk = (key % 2 != 0);
209 VIDEO_WaitVSync(); 260 u32 v12 = key;
210 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); 261 for (u32 v13 = 1; v13 < 32; v13++) {
211 int x = 24, y = 32, w, h; 262 v12 >>= 1;
212 w = rmode->fbWidth - (32); 263 unk += (v12 % 2 != 0);
213 h = rmode->xfbHeight - (48); 264 }
214 CON_InitEx(rmode, x, y, w, h); 265 if ((unk >= 10 && unk <= 24)) {
215 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); 266 if (retries > 4) printf("KeyA retries = %ld",retries);
216 PAD_Init(); 267 printf("KeyA = 0x%08lx\n",key);
217 cmdbuf = memalign(32,32); 268 return key;
218 resbuf = memalign(32,32); 269 }
219 u8 *testdump = memalign(32,0x400000); 270 retries++;
220 if(!testdump) return 0;
221 if(!fatInitDefault())
222 {
223 printmain();
224 fatalError("ERROR: No usable device found to write dumped files to!");
225 } 271 }
226 mkdir("/dumps", S_IREAD | S_IWRITE); 272}
227 if(!dirExists("/dumps")) 273
228 { 274u32 checkKeyB(u32 KeyBRaw) {
229 printmain(); 275 if ((KeyBRaw & 0xFF) != 0xEE) {
230 fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!"); 276 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",((u8)(KeyBRaw)));
277 return 0;
231 } 278 }
232 int i; 279 u32 KeyB = KeyBRaw & 0xffffff00;
233 while(1) 280 u32 val = KeyB;
234 { 281 u32 unk = (val < 0);
235 printmain(); 282 for (u32 i = 1; i < 24; i++) {
236 printf("Waiting for a GBA in port 2...\n"); 283 val <<= 1;
237 resval = 0; 284 unk += (val < 0);
238 285 }
239 SI_GetTypeAsync(1,acb); 286 if (unk > 14) {
240 while(1) 287 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n",KeyB);
241 { 288 return 0;
242 if(resval) 289 }
243 { 290 printf("Valid KeyB: 0x%08lx\n",KeyB);
244 if(resval == 0x80 || resval & 8) 291 return KeyB;
245 { 292}
246 resval = 0; 293
247 SI_GetTypeAsync(1,acb); 294u32 deriveKeyC(u32 keyCderive, u32 kcrc) {
248 } 295 u32 keyc = 0;
249 else if(resval) 296 u32 keyCi = 0;
250 break; 297 do {
251 } 298 u32 v5 = 0x1000000 * keyCi - 1;
252 PAD_ScanPads(); 299 u32 keyCattempt = docrc(kcrc,v5);
253 VIDEO_WaitVSync(); 300 //printf("i = %d; keyCderive = %08x; keyCattempt = %08x\n",keyCi,keyCderive,keyCattempt);
254 if(PAD_ButtonsHeld(0)) 301 if (keyCderive == keyCattempt) {
255 endproc(); 302 keyc = v5;
303 printf("Found keyC: %08lx\n",keyc);
304 return keyc;
256 } 305 }
257 if(resval & SI_GBA) 306 keyCi++;
307 } while (keyCi < 256);
308 return keyc;
309}
310
311int main(int argc, char *argv[])
312{
313 void *xfb = NULL;
314 GXRModeObj *rmode = NULL;
315 VIDEO_Init();
316 rmode = VIDEO_GetPreferredMode(NULL);
317 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
318 VIDEO_Configure(rmode);
319 VIDEO_SetNextFramebuffer(xfb);
320 VIDEO_SetBlack(FALSE);
321 VIDEO_Flush();
322 VIDEO_WaitVSync();
323 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
324 int x = 24, y = 32, w, h;
325 w = rmode->fbWidth - (32);
326 h = rmode->xfbHeight - (48);
327 CON_InitEx(rmode, x, y, w, h);
328 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
329 PAD_Init();
330 cmdbuf = memalign(32,32);
331 resbuf = memalign(32,32);
332 u8 *testdump = memalign(32,0x400000);
333 if(!testdump) return 0;
334
335 /*if (!fatInitDefault())
336 {
337 printmain();
338 fatalError("ERROR: No usable device found to write dumped files to!");
339 }
340
341 mkdir("/dumps", S_IREAD | S_IWRITE);
342 if (!dirExists("/dumps"))
343 {
344 printmain();
345 fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!");
346 }*/
347
348 int i;
349 while(1)
350 {
351 printmain();
352
353 printf("Press A to begin, press Start to quit.\n");
354 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START)
258 { 355 {
259 printf("GBA Found! Waiting on BIOS\n"); 356 endproc();
357 }
358
359 printf("Waiting for a GBA in port 2...\n");
360 resval = 0;
361
362 SI_GetTypeAsync(1,acb);
363 while(1)
364 {
365 if (resval)
366 {
367 if (resval == 0x80 || resval & 8)
368 {
369 resval = 0;
370 SI_GetTypeAsync(1,acb);
371 } else if (resval)
372 {
373 break;
374 }
375 }
376
377 PAD_ScanPads();
378 VIDEO_WaitVSync();
379 if (PAD_ButtonsHeld(0) & PAD_BUTTON_START)
380 {
381 getstatus();
382 endproc();
383 }
384 }
385
386 if (resval & SI_GBA)
387 {
388 printf("GBA Found! Waiting on BIOS\n");
260 resbuf[2]=0; 389 resbuf[2]=0;
261 while(!(resbuf[2]&0x10)) 390 //u32 oldresult = 0;
391 //u32 newresult = 0;
392 // wait for the BIOS to hand over to the game
393 do {
394 doreset();
395
396 } while (!(resbuf[1] > 4));
397 printf("BIOS handed over to game, waiting on game\n");
398 do
262 { 399 {
263 doreset(); 400 doreset();
264 getstatus(); 401 } while((resbuf[0] != 0) || !(resbuf[2]&0x10));
265 } 402 // receive the game-code from GBA side.
266 printf("Ready, sending dumper\n"); 403 u32 gamecode = recv();
404 printf("Ready, sending multiboot ROM\n");
267 unsigned int sendsize = ((gba_mb_gba_size+7)&~7); 405 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
268 unsigned int ourkey = calckey(sendsize); 406 // generate KeyA
407 unsigned int ourkey = genKeyA();
269 //printf("Our Key: %08x\n", ourkey); 408 //printf("Our Key: %08x\n", ourkey);
270 //get current sessionkey 409 printf("Sending game code that we got: 0x%08lx\n",__builtin_bswap32(gamecode));
271 u32 sessionkeyraw = recv(); 410 // send the game code back, then KeyA.
272 u32 sessionkey = __builtin_bswap32(sessionkeyraw^0x7365646F); 411 send(__builtin_bswap32(gamecode));
273 //send over our own key 412 send(ourkey);
274 send(__builtin_bswap32(ourkey)); 413 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA to derive the initial CRC value and the sessionkey.
275 unsigned int fcrc = 0x15a0; 414 u32 sessionkeyraw = 0;
276 //send over gba header 415 do {
277 for(i = 0; i < 0xC0; i+=4) 416 sessionkeyraw = recv();
278 send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i))); 417 } while (sessionkeyraw == gamecode);
279 //printf("Header done! Sending ROM...\n"); 418 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
280 for(i = 0xC0; i < sendsize; i+=4) 419 if (sessionkeyraw == 0)
281 { 420 {
282 u32 enc = ((gba_mb_gba[i+3]<<24)|(gba_mb_gba[i+2]<<16)|(gba_mb_gba[i+1]<<8)|(gba_mb_gba[i])); 421 warnError("Cannot continue.\n");
283 fcrc=docrc(fcrc,enc); 422
423 continue;
424 }
425
426 u32 sessionkey = sessionkeyraw ^ ourkey;
427 u32 kcrc = sessionkey;
428 printf("start kCRC=%08lx\n",kcrc);
429 sessionkey = (sessionkey*0x6177614b)+1;
430 // send hacked up send-size in uint32s
431 u32 hackedupsize = (sendsize >> 3) - 1;
432 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
433 send(hackedupsize);
434 //unsigned int fcrc = 0x00bb;
435 // send over multiboot binary header, in the clear until the end of the nintendo logo.
436 // GBA checks this, if nintendo logo does not match the one in currently inserted cart's ROM, it will not accept any more data.
437 for(i = 0; i < 0xA0; i+=4) {
438 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
439 send(__builtin_bswap32(rom_dword));
440 }
441 printf("\n");
442 printf("Header done! Sending ROM...\n");
443 // Add each uint32 of the multiboot image to the checksum, encrypt the uint32 with the session key, increment the session key, send the encrypted uint32.
444 for(i = 0xA0; i < sendsize; i+=4)
445 {
446 u32 dec = (
447 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
448 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
449 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
450 (((gba_mb_gba[i]) << 0) & 0x000000ff)
451 );
452 u32 enc = (dec - kcrc) ^ sessionkey;
453 kcrc=docrc(kcrc,dec);
284 sessionkey = (sessionkey*0x6177614B)+1; 454 sessionkey = (sessionkey*0x6177614B)+1;
285 enc^=sessionkey; 455 //enc^=((~(i+(0x20<<20)))+1);
286 enc^=((~(i+(0x20<<20)))+1); 456 //enc^=0x6f646573;//0x20796220;
287 enc^=0x20796220;
288 send(enc); 457 send(enc);
289 } 458 }
290 fcrc |= (sendsize<<16); 459 //fcrc |= (sendsize<<16);
291 //printf("ROM done! CRC: %08x\n", fcrc); 460 printf("ROM done! CRC: %08lx\n", kcrc);
292 //send over CRC
293 sessionkey = (sessionkey*0x6177614B)+1;
294 fcrc^=sessionkey;
295 fcrc^=((~(i+(0x20<<20)))+1);
296 fcrc^=0x20796220;
297 send(fcrc);
298 //get crc back (unused) 461 //get crc back (unused)
299 recv(); 462 // Get KeyC derivation material from GBA (eventually)
300 printf("Done!\n"); 463 u32 keyCderive = 0;
301 sleep(2); 464 do {
302 //hm 465 keyCderive = recv();
303 while(1) 466 } while (keyCderive <= 0xfeffffff);
304 { 467 keyCderive = __builtin_bswap32(keyCderive);
305 printmain(); 468 keyCderive >>= 8;
306 printf("Press A once you have a GBA Game inserted.\n"); 469 printf("KeyC derivation material: %08lx\n",keyCderive);
307 printf("Press Y to backup the GBA BIOS.\n \n"); 470
308 PAD_ScanPads(); 471 // (try to) find the KeyC, using the checksum of the multiboot image, and the derivation material that GBA sent to us
309 VIDEO_WaitVSync(); 472
310 u32 btns = PAD_ButtonsDown(0); 473 u32 keyc = deriveKeyC(keyCderive,kcrc);
311 if(btns&PAD_BUTTON_START) 474 if (keyc == 0)
312 endproc();
313 else if(btns&PAD_BUTTON_A)
314 { 475 {
315 if(recv() == 0) //ready 476 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
316 { 477 warnError("Cannot continue.\n");
317 printf("Waiting for GBA\n"); 478 continue;
318 VIDEO_WaitVSync(); 479 }
319 int gbasize = 0; 480
320 while(gbasize == 0) 481 // derive the boot key from the found KeyC, and send to GBA. if this is not correct, GBA will not jump to the multiboot image it was sent.
321 gbasize = __builtin_bswap32(recv()); 482 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
322 send(0); //got gbasize 483 printf("BootKey = 0x%08lx\n",bootkey);
323 u32 savesize = __builtin_bswap32(recv()); 484 send(bootkey);
324 send(0); //got savesize 485 /*
325 if(gbasize == -1) 486 printf("GBA Found! Waiting on BIOS...\n");
326 { 487
327 warnError("ERROR: No (Valid) GBA Card inserted!\n"); 488 resbuf[2]=0;
328 continue; 489 while (!(resbuf[2] & 0x10))
329 } 490 {
330 //get rom header 491 doreset();
331 for(i = 0; i < 0xC0; i+=4) 492 getstatus();
332 *(vu32*)(testdump+i) = recv(); 493 }
333 //print out all the info from the game 494
334 printf("Game Name: %.12s\n",(char*)(testdump+0xA0)); 495 printf("Ready, sending extractor.\n");
335 printf("Game ID: %.4s\n",(char*)(testdump+0xAC)); 496
336 printf("Company ID: %.2s\n",(char*)(testdump+0xB0)); 497 unsigned int sendsize = ((gba_mb_gba_size + 7) & ~7);
337 printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f); 498 unsigned int ourkey = calckey(sendsize);
338 if(savesize > 0) 499
339 printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f); 500 //get current sessionkey
340 else 501 u32 sessionkeyraw = recv();
341 printf("No Save File\n \n"); 502 u32 sessionkey = __builtin_bswap32(sessionkeyraw ^ 0x7365646F);
342 //generate file paths 503
343 char gamename[64]; 504 //send over our own key
344 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba", 505 send(__builtin_bswap32(ourkey));
345 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); 506 unsigned int fcrc = 0x15a0;
346 fixFName(gamename+7); //fix name behind "/dumps/" 507
347 char savename[64]; 508 //send over gba header
348 sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav", 509 for(i = 0; i < 0xC0; i+=4)
349 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); 510 {
350 fixFName(savename+7); //fix name behind "/dumps/" 511 send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i)));
351 //let the user choose the option 512 }
352 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); 513
353 printf("Press B if you want to cancel dumping this game.\n"); 514 for (i = 0xC0; i < sendsize; i+=4)
354 if(savesize > 0) 515 {
355 { 516 u32 enc = (
356 printf("Press Y to backup this save file.\n"); 517 (gba_mb_gba[i+3] << 24)
357 printf("Press X to restore this save file.\n"); 518 | (gba_mb_gba[i+2] << 16)
358 printf("Press Z to clear the save file on the GBA Cartridge.\n\n"); 519 | (gba_mb_gba[i+1] << 8)
359 } 520 | (gba_mb_gba[i]));
360 else 521
361 printf("\n"); 522 fcrc = docrc(fcrc,enc);
362 int command = 0; 523 sessionkey = (sessionkey * 0x6177614B) + 1;
363 while(1) 524 enc ^= sessionkey;
364 { 525 enc ^= ((~(i + (0x20 << 20))) + 1);
365 PAD_ScanPads(); 526 enc ^= 0x20796220;
366 VIDEO_WaitVSync(); 527
367 u32 btns = PAD_ButtonsDown(0); 528 send(enc);
368 if(btns&PAD_BUTTON_START) 529 }
369 endproc(); 530
370 else if(btns&PAD_BUTTON_A) 531 fcrc |= (sendsize<<16);
371 { 532
372 command = 1; 533 //send over CRC
373 break; 534 sessionkey = (sessionkey * 0x6177614B) + 1;
374 } 535 fcrc ^= sessionkey;
375 else if(btns&PAD_BUTTON_B) 536 fcrc ^= ((~(i + (0x20 << 20))) + 1);
376 break; 537 fcrc ^= 0x20796220;
377 else if(savesize > 0) 538
378 { 539 send(fcrc);
379 if(btns&PAD_BUTTON_Y) 540
380 { 541 //get crc back (unused)
381 command = 2; 542 recv();
382 break; 543 printf("Done!\n");
383 } 544 sleep(2);
384 else if(btns&PAD_BUTTON_X) 545
385 { 546 //hm
386 command = 3; 547 while (1)
387 break; 548 {
388 } 549 printmain();
389 else if(btns&PAD_TRIGGER_Z) 550 printf("Press A once you have a GBA Game inserted.\n \n");
390 { 551
391 command = 4; 552 PAD_ScanPads();
392 break; 553 VIDEO_WaitVSync();
393 } 554 u32 btns = PAD_ButtonsDown(0);
394 } 555 if (btns & PAD_BUTTON_START)
395 } 556 {
396 if(command == 1) 557 endproc();
397 { 558 } else if (btns & PAD_BUTTON_A)
398 FILE *f = fopen(gamename,"rb"); 559 {*/
399 if(f) 560 sleep(1);
400 { 561 //recv();
401 fclose(f); 562
402 command = 0; 563 //if (recv() == 0) //ready
403 warnError("ERROR: Game already dumped!\n"); 564 {
404 } 565
405 } 566 printf("Waiting for GBA...\n");
406 else if(command == 2) 567 while (recv() != 0) {fsleep(1);};
407 { 568 send(0);
408 FILE *f = fopen(savename,"rb"); 569
409 if(f) 570 VIDEO_WaitVSync();
410 { 571
411 fclose(f); 572 /*int gbasize = 0;
412 command = 0; 573 while(gbasize == 0)
413 warnError("ERROR: Save already backed up!\n"); 574 {
414 } 575 gbasize = __builtin_bswap32(recv());
415 } 576 }
416 else if(command == 3) 577
417 { 578 send(0); //got gbasize
418 size_t readsize = 0; 579 while (recv()!=0) {sleep(1);};
419 FILE *f = fopen(savename,"rb"); 580
420 if(f) 581 //u32 savesize = __builtin_bswap32(recv());
421 { 582 //send(0); //got savesize
422 fseek(f,0,SEEK_END); 583
423 readsize = ftell(f); 584 if (gbasize == -1)
424 if(readsize != savesize) 585 {
425 { 586 warnError("ERROR: No (Valid) GBA Card inserted!\n");
426 command = 0; 587
427 warnError("ERROR: Save has the wrong size, aborting restore!\n"); 588 continue;
428 } 589 }*/
429 else 590
430 { 591 // Get game
431 rewind(f); 592 // -1 - unsupported game
432 fread(testdump,readsize,1,f); 593 // 1 - Ruby
433 } 594 // 2 - Sapphire
434 fclose(f); 595 // 3 - FireRed
435 } 596 // 4 - LeafGreen
436 else 597 // 5 - Emerald
437 { 598 u32 gameId = 0;
438 command = 0; 599 while (gameId == 0)
439 warnError("ERROR: No Save to restore!\n");
440 }
441 }
442 send(command);
443 //let gba prepare
444 sleep(1);
445 if(command == 0)
446 continue;
447 else if(command == 1)
448 { 600 {
449 //create base file with size 601 gameId = __builtin_bswap32(recv());
450 printf("Preparing file...\n"); 602 fsleep(1);
451 createFile(gamename,gbasize);
452 FILE *f = fopen(gamename,"wb");
453 if(!f)
454 fatalError("ERROR: Could not create file! Exit...");
455 printf("Dumping...\n");
456 u32 bytes_read = 0;
457 while(gbasize > 0)
458 {
459 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
460 int j;
461 for(j = 0; j < toread; j+=4)
462 {
463 *(vu32*)(testdump+j) = recv();
464 bytes_read+=4;
465 if((bytes_read&0xFFFF) == 0)
466 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
467 }
468 fwrite(testdump,toread,1,f);
469 gbasize -= toread;
470 }
471 printf("\nClosing file\n");
472 fclose(f);
473 printf("Game dumped!\n");
474 sleep(5);
475 } 603 }
476 else if(command == 2) 604
605 send(0);
606 while (recv()!=0) {fsleep(1);};
607 //sleep(1);
608
609 if (gameId == -1)
610 {
611 warnError("ERROR: Unsupported GBA game inserted!\n");
612
613 continue;
614 }
615
616 printf("\nPokemon ");
617 switch (gameId)
618 {
619 case 1: printf("Ruby"); break;
620 case 2: printf("Sapphire"); break;
621 case 3: printf("FireRed"); break;
622 case 4: printf("LeafGreen"); break;
623 case 5: printf("Emerald"); break;
624 }
625
626 printf("\n");
627 VIDEO_WaitVSync();
628
629 u32 isValid = 0;
630 while (isValid == 0)
477 { 631 {
478 //create base file with size 632 isValid = __builtin_bswap32(recv());
479 printf("Preparing file...\n"); 633 fsleep(1);
480 createFile(savename,savesize);
481 FILE *f = fopen(savename,"wb");
482 if(!f)
483 fatalError("ERROR: Could not create file! Exit...");
484 printf("Waiting for GBA\n");
485 VIDEO_WaitVSync();
486 u32 readval = 0;
487 while(readval != savesize)
488 readval = __builtin_bswap32(recv());
489 send(0); //got savesize
490 printf("Receiving...\n");
491 for(i = 0; i < savesize; i+=4)
492 *(vu32*)(testdump+i) = recv();
493 printf("Writing save...\n");
494 fwrite(testdump,savesize,1,f);
495 fclose(f);
496 printf("Save backed up!\n");
497 sleep(5);
498 } 634 }
499 else if(command == 3 || command == 4) 635
636 if (isValid == -1)
637 {
638 //send(0);
639
640 warnError("ERROR: Unsupported game version inserted!\n");
641
642 continue;
643 }
644
645 send(0);
646 while (recv()!=0) {fsleep(1);};
647 //sleep(1);
648 /*
649 // Get trainer name
650 u8 trainerName[8];
651
652 u32 tnd = recv();
653 send(0);
654 trainerName[0] = (tnd & 0xFF000000);
655 trainerName[1] = (tnd & 0x00FF0000) >> 8;
656 trainerName[2] = (tnd & 0x0000FF00) >> 16;
657 trainerName[3] = (tnd & 0x000000FF) >> 24;
658
659 tnd = recv();
660 send(0);
661 trainerName[4] = (tnd & 0xFF000000);
662 trainerName[5] = (tnd & 0x00FF0000) >> 8;
663 trainerName[6] = (tnd & 0x0000FF00) >> 16;
664 trainerName[7] = (tnd & 0x000000FF) >> 24;
665
666 printf("Trainer: %s", (char*) trainerName);
667*/
668 // Get trainer ID
669 u32 trainerId = 0;
670 while (trainerId == 0)
500 { 671 {
501 u32 readval = 0; 672 trainerId = __builtin_bswap32(recv());
502 while(readval != savesize) 673 fsleep(1);
503 readval = __builtin_bswap32(recv());
504 if(command == 3)
505 {
506 printf("Sending save\n");
507 VIDEO_WaitVSync();
508 for(i = 0; i < savesize; i+=4)
509 send(__builtin_bswap32(*(vu32*)(testdump+i)));
510 }
511 printf("Waiting for GBA\n");
512 while(recv() != 0)
513 VIDEO_WaitVSync();
514 printf(command == 3 ? "Save restored!\n" : "Save cleared!\n");
515 send(0);
516 sleep(5);
517 } 674 }
518 } 675 send(0);
519 } 676 while (recv()!=0) {fsleep(1);};
520 else if(btns&PAD_BUTTON_Y) 677 //sleep(1);
521 { 678
522 const char *biosname = "/dumps/gba_bios.bin"; 679 printf(" (%ld)\n", trainerId);
523 FILE *f = fopen(biosname,"rb"); 680
524 if(f) 681 //continue;
525 { 682
526 fclose(f); 683 // Wait for confirmation.
527 warnError("ERROR: BIOS already backed up!\n"); 684 printf("Press A to import the data from this game.\n");
528 } 685 printf("Press B to cancel.\n");
529 else 686 VIDEO_WaitVSync();
530 { 687
531 //create base file with size 688 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B)
532 printf("Preparing file...\n"); 689 {
533 createFile(biosname,0x4000); 690 continue;
534 f = fopen(biosname,"wb"); 691 }
535 if(!f) 692
536 fatalError("ERROR: Could not create file! Exit..."); 693
537 //send over bios dump command 694
538 send(5); 695
539 //the gba might still be in a loop itself 696/*
540 sleep(1); 697 //get rom header
541 //lets go! 698 for(i = 0; i < 0xC0; i+=4)
542 printf("Dumping...\n"); 699 *(vu32*)(testdump+i) = recv();
543 for(i = 0; i < 0x4000; i+=4) 700 //print out all the info from the game
544 *(vu32*)(testdump+i) = recv(); 701 printf("Game Name: %.12s\n",(char*)(testdump+0xA0));
545 fwrite(testdump,0x4000,1,f); 702 printf("Game ID: %.4s\n",(char*)(testdump+0xAC));
546 printf("Closing file\n"); 703 printf("Company ID: %.2s\n",(char*)(testdump+0xB0));
547 fclose(f); 704 printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f);
548 printf("BIOS dumped!\n"); 705 if(savesize > 0)
549 sleep(5); 706 printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f);
550 } 707 else
551 } 708 printf("No Save File\n \n");
552 } 709 //generate file paths
553 } 710 char gamename[64];
554 } 711 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba",
555 return 0; 712 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
713 fixFName(gamename+7); //fix name behind "/dumps/"
714 char savename[64];
715 sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav",
716 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
717 fixFName(savename+7); //fix name behind "/dumps/"
718 //let the user choose the option
719 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2);
720 printf("Press B if you want to cancel dumping this game.\n");
721 if(savesize > 0)
722 {
723 printf("Press Y to backup this save file.\n");
724 printf("Press X to restore this save file.\n");
725 printf("Press Z to clear the save file on the GBA Cartridge.\n\n");
726 }
727 else
728 printf("\n");
729
730 int command = 0;
731 while(1)
732 {
733 PAD_ScanPads();
734 VIDEO_WaitVSync();
735 u32 btns = PAD_ButtonsDown(0);
736 if(btns&PAD_BUTTON_START)
737 endproc();
738 else if(btns&PAD_BUTTON_A)
739 {
740 command = 1;
741 break;
742 }
743 else if(btns&PAD_BUTTON_B)
744 break;
745 else if(savesize > 0)
746 {
747 if(btns&PAD_BUTTON_Y)
748 {
749 command = 2;
750 break;
751 }
752 else if(btns&PAD_BUTTON_X)
753 {
754 command = 3;
755 break;
756 }
757 else if(btns&PAD_TRIGGER_Z)
758 {
759 command = 4;
760 break;
761 }
762 }
763 }
764 if(command == 1)
765 {
766 FILE *f = fopen(gamename,"rb");
767 if(f)
768 {
769 fclose(f);
770 command = 0;
771 warnError("ERROR: Game already dumped!\n");
772 }
773 }
774 else if(command == 2)
775 {
776 FILE *f = fopen(savename,"rb");
777 if(f)
778 {
779 fclose(f);
780 command = 0;
781 warnError("ERROR: Save already backed up!\n");
782 }
783 }
784 else if(command == 3)
785 {
786 size_t readsize = 0;
787 FILE *f = fopen(savename,"rb");
788 if(f)
789 {
790 fseek(f,0,SEEK_END);
791 readsize = ftell(f);
792 if(readsize != savesize)
793 {
794 command = 0;
795 warnError("ERROR: Save has the wrong size, aborting restore!\n");
796 }
797 else
798 {
799 rewind(f);
800 fread(testdump,readsize,1,f);
801 }
802 fclose(f);
803 }
804 else
805 {
806 command = 0;
807 warnError("ERROR: No Save to restore!\n");
808 }
809 }
810 send(command);
811 //let gba prepare
812 sleep(1);
813 if(command == 0)
814 continue;
815 else if(command == 1)
816 {
817 //create base file with size
818 printf("Preparing file...\n");
819 createFile(gamename,gbasize);
820 FILE *f = fopen(gamename,"wb");
821 if(!f)
822 fatalError("ERROR: Could not create file! Exit...");
823 printf("Dumping...\n");
824 u32 bytes_read = 0;
825 while(gbasize > 0)
826 {
827 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
828 int j;
829 for(j = 0; j < toread; j+=4)
830 {
831 *(vu32*)(testdump+j) = recv();
832 bytes_read+=4;
833 if((bytes_read&0xFFFF) == 0)
834 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
835 }
836 fwrite(testdump,toread,1,f);
837 gbasize -= toread;
838 }
839 printf("\nClosing file\n");
840 fclose(f);
841 printf("Game dumped!\n");
842 sleep(5);
843 }
844 else if(command == 2)
845 {
846 //create base file with size
847 printf("Preparing file...\n");
848 createFile(savename,savesize);
849 FILE *f = fopen(savename,"wb");
850 if(!f)
851 fatalError("ERROR: Could not create file! Exit...");
852 printf("Waiting for GBA\n");
853 VIDEO_WaitVSync();
854 u32 readval = 0;
855 while(readval != savesize)
856 readval = __builtin_bswap32(recv());
857 send(0); //got savesize
858 printf("Receiving...\n");
859 for(i = 0; i < savesize; i+=4)
860 *(vu32*)(testdump+i) = recv();
861 printf("Writing save...\n");
862 fwrite(testdump,savesize,1,f);
863 fclose(f);
864 printf("Save backed up!\n");
865 sleep(5);
866 }
867 else if(command == 3 || command == 4)
868 {
869 u32 readval = 0;
870 while(readval != savesize)
871 readval = __builtin_bswap32(recv());
872 if(command == 3)
873 {
874 printf("Sending save\n");
875 VIDEO_WaitVSync();
876 for(i = 0; i < savesize; i+=4)
877 send(__builtin_bswap32(*(vu32*)(testdump+i)));
878 }
879 printf("Waiting for GBA\n");
880 while(recv() != 0)
881 VIDEO_WaitVSync();
882 printf(command == 3 ? "Save restored!\n" : "Save cleared!\n");
883 send(0);
884 sleep(5);
885 }*/
886 }
887 }
888 /*else if(btns&PAD_BUTTON_Y)
889 {
890 const char *biosname = "/dumps/gba_bios.bin";
891 FILE *f = fopen(biosname,"rb");
892 if(f)
893 {
894 fclose(f);
895 warnError("ERROR: BIOS already backed up!\n");
896 }
897 else
898 {
899 //create base file with size
900 printf("Preparing file...\n");
901 createFile(biosname,0x4000);
902 f = fopen(biosname,"wb");
903 if(!f)
904 fatalError("ERROR: Could not create file! Exit...");
905 //send over bios dump command
906 send(5);
907 //the gba might still be in a loop itself
908 sleep(1);
909 //lets go!
910 printf("Dumping...\n");
911 for(i = 0; i < 0x4000; i+=4)
912 *(vu32*)(testdump+i) = recv();
913 fwrite(testdump,0x4000,1,f);
914 printf("Closing file\n");
915 fclose(f);
916 printf("BIOS dumped!\n");
917 sleep(5);
918 }
919 }*/
920// }
921 // }
922// }
923 }
924 return 0;
556} 925}