about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--LICENSE1
-rw-r--r--Makefile.gc4
-rw-r--r--Makefile.wii4
-rwxr-xr-xbuild.sh11
-rw-r--r--gba/Makefile4
-rw-r--r--gba/source/call_into_middle_of_titlescreen_func.s13
-rw-r--r--gba/source/gamedata.c512
-rw-r--r--gba/source/gamedata.h (renamed from gba/source/payload.h)16
-rw-r--r--gba/source/libpayload.c312
-rw-r--r--gba/source/libpayload.h160
-rw-r--r--gba/source/link.c38
-rw-r--r--gba/source/link.h17
-rw-r--r--gba/source/main.c468
-rw-r--r--gba/source/payload.c72
-rw-r--r--source/encoding.c23
-rw-r--r--source/encoding.h14
-rw-r--r--source/link.c22
-rw-r--r--source/link.h14
-rw-r--r--source/main.c514
20 files changed, 1137 insertions, 1089 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac7cf98 --- /dev/null +++ b/.gitignore
@@ -0,0 +1,7 @@
1*.elf
2build
3data
4*.dol
5tags
6*.o
7*.d
diff --git a/LICENSE b/LICENSE index 3bef6d6..b77df8a 100644 --- a/LICENSE +++ b/LICENSE
@@ -1,5 +1,6 @@
1The MIT License (MIT) 1The MIT License (MIT)
2 2
3Copyright (c) 2017 hatkirby
3Copyright (c) 2017 slipstream/RoL 4Copyright (c) 2017 slipstream/RoL
4Copyright (c) 2016 FIX94 5Copyright (c) 2016 FIX94
5 6
diff --git a/Makefile.gc b/Makefile.gc index 3fddc9b..eaaf3b9 100644 --- a/Makefile.gc +++ b/Makefile.gc
@@ -15,7 +15,7 @@ include $(DEVKITPPC)/gamecube_rules
15# SOURCES is a list of directories containing source code 15# SOURCES is a list of directories containing source code
16# INCLUDES is a list of directories containing extra header files 16# INCLUDES is a list of directories containing extra header files
17#--------------------------------------------------------------------------------- 17#---------------------------------------------------------------------------------
18TARGET := gen3multiboot_gc 18TARGET := gen3uploader_gc
19BUILD := build 19BUILD := build
20SOURCES := source 20SOURCES := source
21DATA := data 21DATA := data
@@ -33,7 +33,7 @@ LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
33#--------------------------------------------------------------------------------- 33#---------------------------------------------------------------------------------
34# any extra libraries we wish to link with the project 34# any extra libraries we wish to link with the project
35#--------------------------------------------------------------------------------- 35#---------------------------------------------------------------------------------
36LIBS := -lfat -logc 36LIBS := -logc
37 37
38 38
39#--------------------------------------------------------------------------------- 39#---------------------------------------------------------------------------------
diff --git a/Makefile.wii b/Makefile.wii index 15afd9d..92ac7e7 100644 --- a/Makefile.wii +++ b/Makefile.wii
@@ -15,7 +15,7 @@ include $(DEVKITPPC)/wii_rules
15# SOURCES is a list of directories containing source code 15# SOURCES is a list of directories containing source code
16# INCLUDES is a list of directories containing extra header files 16# INCLUDES is a list of directories containing extra header files
17#--------------------------------------------------------------------------------- 17#---------------------------------------------------------------------------------
18TARGET := gen3multiboot_wii 18TARGET := gen3uploader_wii
19BUILD := build 19BUILD := build
20SOURCES := source 20SOURCES := source
21DATA := data 21DATA := data
@@ -33,7 +33,7 @@ LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
33#--------------------------------------------------------------------------------- 33#---------------------------------------------------------------------------------
34# any extra libraries we wish to link with the project 34# any extra libraries we wish to link with the project
35#--------------------------------------------------------------------------------- 35#---------------------------------------------------------------------------------
36LIBS := -lfat -logc 36LIBS := -logc
37 37
38 38
39#--------------------------------------------------------------------------------- 39#---------------------------------------------------------------------------------
diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b521d27 --- /dev/null +++ b/build.sh
@@ -0,0 +1,11 @@
1#!/bin/bash
2cd gba
3make clean
4make
5cd ..
6mkdir data
7mv -f gba/gba_pkjb.gba data/gba_mb.gba
8make -f Makefile.gc clean
9make -f Makefile.gc
10make -f Makefile.wii clean
11make -f Makefile.wii
diff --git a/gba/Makefile b/gba/Makefile index b28e0e1..49d0777 100644 --- a/gba/Makefile +++ b/gba/Makefile
@@ -9,7 +9,7 @@ endif
9 9
10%_pkjb.elf: 10%_pkjb.elf:
11 @echo linking pkjb 11 @echo linking pkjb
12 @$(LD) -specs=../gba_pkjb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 12 $(LD) -specs=../gba_pkjb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
13 13
14include $(DEVKITARM)/gba_rules 14include $(DEVKITARM)/gba_rules
15 15
@@ -155,7 +155,7 @@ $(OUTPUT).elf : $(OFILES)
155#--------------------------------------------------------------------------------- 155#---------------------------------------------------------------------------------
156 @echo $(notdir $<) 156 @echo $(notdir $<)
157 @$(bin2o) 157 @$(bin2o)
158 158
159#--------------------------------------------------------------------------------- 159#---------------------------------------------------------------------------------
160# This rule creates assembly source files using grit 160# This rule creates assembly source files using grit
161# grit takes an image file and a .grit describing how the file is to be processed 161# grit takes an image file and a .grit describing how the file is to be processed
diff --git a/gba/source/call_into_middle_of_titlescreen_func.s b/gba/source/call_into_middle_of_titlescreen_func.s deleted file mode 100644 index 7908f6b..0000000 --- a/gba/source/call_into_middle_of_titlescreen_func.s +++ /dev/null
@@ -1,13 +0,0 @@
1 .text
2 .code 16
3
4 .global call_into_middle_of_titlescreen_func
5 .thumb_func
6call_into_middle_of_titlescreen_func:
7 push {lr}
8 push {r4-r5}
9 @ use r4 (which already got saved to the stack) as scratch space to reserve a variable amount of stack space
10 mov r4,sp
11 sub r4,r4,r1
12 mov sp,r4
13 bx r0 \ No newline at end of file
diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c new file mode 100644 index 0000000..6868b2b --- /dev/null +++ b/gba/source/gamedata.c
@@ -0,0 +1,512 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 * Copyright (C) 2017 slipstream/RoL
4 *
5 * This software may be modified and distributed under the terms
6 * of the MIT license. See the LICENSE file for details.
7 */
8#include "gamedata.h"
9
10void decryptSaveStructures(
11 pSaveBlock1 SaveBlock1,
12 pSaveBlock2 SaveBlock2,
13 pSaveBlock3 SaveBlock3)
14{
15 if (GAME_RS)
16 {
17 // R/S doesn't have save crypto.
18 return;
19 }
20
21 u8* sb1raw = (u8*)SaveBlock1;
22 u8* sb2raw = (u8*)SaveBlock2;
23 //u8* sb3raw = (u8*)SaveBlock3; // unused
24
25 u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]);
26
27 u32 xor_key = *xor_key_ptr;
28 u16 xor_key16 = (u16)xor_key;
29 if (!xor_key)
30 {
31 // xor key is zero, nothing needs to be done.
32 return;
33 }
34
35 u32* ptr_to_xor;
36 u32 save_offset;
37 int i;
38 u32* bag_pocket_offsets;
39 u32* bag_pocket_counts;
40 if (GAME_FRLG)
41 {
42 // loop over and decrypt various things
43 save_offset = 0x3D38 + 4;
44 for (i = 3; i >= 0; i--)
45 {
46 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
47 *ptr_to_xor ^= xor_key;
48 save_offset += 12;
49 }
50
51 for (i = 0; i <= 0x3f; i++)
52 {
53 save_offset = 0x1200 + (i*sizeof(u32));
54 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
55 *ptr_to_xor ^= xor_key;
56 }
57
58 // loop over each of the bag pockets and decrypt decrypt decrypt
59 bag_pocket_offsets = (u32[5]) { 0x310, 0x388, 0x430, 0x464, 0x54C };
60 bag_pocket_counts = (u32[5]) { 42, 30, 13, 58, 43 };
61
62 for (i = 0; i < 5; i++)
63 {
64 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++)
65 {
66 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
67 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
68 }
69 }
70
71 // decrypt some more stuff
72 save_offset = 0xaf8;
73 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
74 *ptr_to_xor ^= xor_key;
75
76 save_offset = 0x290;
77 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
78 *ptr_to_xor ^= xor_key;
79
80 save_offset = 0x294;
81 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
82 } else {
83 // Emerald
84
85 // loop over and decrypt various things
86 for (i = 0; i <= 0x3f; i++)
87 {
88 save_offset = 0x159c + (i*sizeof(u32));
89 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
90 *ptr_to_xor ^= xor_key;
91 }
92
93 // loop over each of the bag pockets and decrypt decrypt decrypt
94 bag_pocket_offsets = (u32[5]) { 0x560, 0x5D8, 0x650, 0x690, 0x790 };
95 bag_pocket_counts = (u32[5]) { 30, 30, 16, 64, 46 };
96
97 for (i = 0; i < 5; i++)
98 {
99 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++)
100 {
101 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
102 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
103 }
104 }
105
106 // decrypt some more stuff
107 save_offset = 0x1F4;
108 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
109 *ptr_to_xor ^= xor_key;
110
111 save_offset = 0x490;
112 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
113 *ptr_to_xor ^= xor_key;
114
115 save_offset = 0x494;
116 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
117 }
118
119 *xor_key_ptr = 0;
120}
121
122bool initSaveData(
123 pSaveBlock1* SaveBlock1,
124 pSaveBlock2* SaveBlock2,
125 pSaveBlock3* SaveBlock3)
126{
127 // check the ROM code, make sure this game is supported.
128 u8* ROM = (u8*) 0x8000000;
129
130 u32 gamecode = (*(u32*)(&ROM[0xAC]));
131
132 void(*loadsave)(char a1);
133 //void(*mainloop)();
134 //void(*load_pokemon)();
135 pSaveBlock1 gSaveBlock1;
136 pSaveBlock2 gSaveBlock2;
137 pSaveBlock3 gSaveBlock3;
138 //u32 titlemid = 0;
139
140 // get the address of the save loading function.
141 switch (gamecode)
142 {
143 // --- R/S ---
144 case 'DVXA': // Ruby German
145 case 'DPXA': // Sapphire German
146 {
147 // TODO: detect debug ROM?
148 gSaveBlock1 = (pSaveBlock1) 0x2025734;
149 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
150 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
151 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
152 //mainloop = (void(*)()) 0x80003D9;
153 //load_pokemon = (void(*)()) 0x8047da9;
154
155 break;
156 }
157
158 case 'FVXA': // Ruby French
159 case 'FPXA': // Sapphire French
160 {
161 gSaveBlock1 = (pSaveBlock1) 0x2025734;
162 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
163 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
164 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1
165 //mainloop = (void(*)()) 0x80003D9;
166 //load_pokemon = (void(*)()) 0x8047e95;
167
168 break;
169 }
170
171 case 'IVXA': // Ruby Italian
172 case 'IPXA': // Sapphire Italian
173 {
174 gSaveBlock1 = (pSaveBlock1) 0x2025734;
175 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
176 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
177 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
178 //mainloop = (void(*)()) 0x80003D9;
179 //load_pokemon = (void(*)()) 0x8047dbd;
180
181 break;
182 }
183
184 case 'SVXA': // Ruby Spanish
185 case 'SPXA': // Sapphire Spanish
186 {
187 gSaveBlock1 = (pSaveBlock1) 0x2025734;
188 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
189 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
190 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1
191 //mainloop = (void(*)()) 0x80003D9;
192 //load_pokemon = (void(*)()) 0x8047ea5;
193
194 break;
195 }
196
197 case 'EVXA': // Ruby English
198 case 'EPXA': // Sapphire English
199 {
200 gSaveBlock1 = (pSaveBlock1) 0x2025734;
201 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
202 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
203 //mainloop = (void(*)()) 0x80002A5;
204
205 // version number
206 switch (ROM[0xBC])
207 {
208 case 0:
209 {
210 loadsave = (void(*)(char)) 0x8125EC9;
211 //load_pokemon = (void(*)()) 0x8047a85;
212
213 break;
214 }
215
216 case 1:
217 case 2:
218 {
219 loadsave = (void(*)(char)) 0x8125EE9;
220 //load_pokemon = (void(*)()) 0x8047aa5;
221
222 break;
223 }
224
225 default:
226 {
227 return false; // unsupported version
228 }
229 }
230
231 break;
232 }
233
234 case 'JVXA': // Ruby Japanese
235 case 'JPXA': // Sapphire Japanese
236 {
237 gSaveBlock1 = (pSaveBlock1) 0x2025494;
238 gSaveBlock2 = (pSaveBlock2) 0x2024C04;
239 gSaveBlock3 = (pSaveBlock3) 0x202FDBC;
240 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1
241 //mainloop = (void(*)()) 0x80002A9;
242 //load_pokemon = (void(*)()) 0x8044d55;
243
244 break;
245 }
246
247 /// --- FR/LG ---
248 // In FR/LG, the function that initialises the save-block pointers to
249 // default does not set up saveblock3. Which will need to be set up before
250 // loading the save if we want boxed Pokémon to not disappear. Oh, and
251 // loadsave() offset is different between FR and LG...
252
253 case 'DRPB': // FireRed German
254 case 'DGPB': // LeafGreen German
255 {
256 gSaveBlock1 = (pSaveBlock1) 0x202552C;
257 gSaveBlock2 = (pSaveBlock2) 0x2024588;
258 gSaveBlock3 = (pSaveBlock3) 0x2029314;
259 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
260 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
261 //mainloop = (void(*)()) 0x8000425;
262 //titlemid = 0x80791df;
263 //load_pokemon = (void(*)()) 0x804c251;
264
265 break;
266 }
267
268 case 'FRPB': // FireRed French
269 case 'FGPB': // LeafGreen French
270 {
271 gSaveBlock1 = (pSaveBlock1) 0x202552C;
272 gSaveBlock2 = (pSaveBlock2) 0x2024588;
273 gSaveBlock3 = (pSaveBlock3) 0x2029314;
274 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
275 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
276 //mainloop = (void(*)()) 0x8000417;
277 //titlemid = 0x807929f;
278 //load_pokemon = (void(*)()) 0x804c311;
279
280 break;
281 }
282
283 case 'IRPB': // FireRed Italian
284 case 'IGPB': // LeafGreen Italian
285 {
286 gSaveBlock1 = (pSaveBlock1) 0x202552C;
287 gSaveBlock2 = (pSaveBlock2) 0x2024588;
288 gSaveBlock3 = (pSaveBlock3) 0x2029314;
289 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
290 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
291 //mainloop = (void(*)()) 0x8000425;
292 //titlemid = 0x80791cb;
293 //load_pokemon = (void(*)()) 0x804c23d;
294
295 break;
296 }
297
298 case 'SRPB': // FireRed Spanish
299 case 'SGPB': // LeafGreen Spanish
300 {
301 gSaveBlock1 = (pSaveBlock1) 0x202552C;
302 gSaveBlock2 = (pSaveBlock2) 0x2024588;
303 gSaveBlock3 = (pSaveBlock3) 0x2029314;
304 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
305 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
306 //mainloop = (void(*)()) 0x8000417;
307 //titlemid = 0x80792b3;
308 //load_pokemon = (void(*)()) 0x804c325;
309
310 break;
311 }
312
313 case 'ERPB': // FireRed English
314 case 'EGPB': // LeafGreen English
315 {
316 gSaveBlock1 = (pSaveBlock1) 0x202552C;
317 gSaveBlock2 = (pSaveBlock2) 0x2024588;
318 gSaveBlock3 = (pSaveBlock3) 0x2029314;
319 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
320
321 // version number
322 switch (ROM[0xBC])
323 {
324 case 0:
325 {
326 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
327 //mainloop = (void(*)()) 0x800041b;
328 //titlemid = 0x807927b;
329 //load_pokemon = (void(*)()) 0x804c231;
330
331 break;
332 }
333
334 case 1:
335 {
336 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
337 //mainloop = (void(*)()) 0x8000429;
338 //titlemid = 0x807928f;
339 //load_pokemon = (void(*)()) 0x804c245;
340
341 break;
342 }
343
344 default:
345 {
346 return false; // unsupported version
347 }
348 }
349
350 break;
351 }
352
353 case 'JRPB': // FireRed Japanese
354 case 'JGPB': // LeafGreen Japanese
355 {
356 gSaveBlock1 = (pSaveBlock1) 0x202548C;
357 gSaveBlock2 = (pSaveBlock2) 0x20244E8;
358 gSaveBlock3 = (pSaveBlock3) 0x202924C;
359 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
360
361 // version number
362 switch (ROM[0xBC])
363 {
364 case 0:
365 {
366 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
367 //mainloop = (void(*)()) 0x800041b;
368 //titlemid = 0x8078a0f;
369 //load_pokemon = (void(*)()) 0x804b9e9;
370
371 break;
372 }
373
374 case 1:
375 {
376 if ((gamecode << 8) == 'GPB\x00')
377 {
378 // LeafGreen v1.1 Japanese is undumped.
379 // Therefore, it is unsupported.
380 // I will make guesses at the offsets in the comments, but I will
381 // not actually implement them until LeafGreen v1.1 is dumped.
382
383 return false;
384 }
385
386 loadsave = (void(*)(char)) 0x80db529;
387 // potential LG1.1 address: 0x80db4fd
388 //mainloop = (void(*)()) 0x8000417;
389 //titlemid = 0x8078987;
390 //load_pokemon = (void(*)()) 0x804b9c5;
391
392 break;
393 }
394
395 default:
396 {
397 return false; // unsupported version
398 }
399 }
400
401 break;
402 }
403
404 /// --- Emerald ---
405 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in
406 // FR/LG it was saveblock3). The initial save loading code after the
407 // copyright screen is also updated, now it sets up ASLR/crypto here before
408 // loading the save.
409
410 case 'DEPB': // Emerald German
411 {
412 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
413 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
414 gSaveBlock3 = (pSaveBlock3) 0x2029808;
415 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
416 loadsave = (void(*)(char)) 0x8153075;
417 //mainloop = (void(*)()) 0x800042b;
418 //titlemid = 0x816fdb5;
419 //load_pokemon = (void(*)()) 0x8076dd5;
420
421 break;
422 }
423
424 case 'FEPB': // Emerald French
425 {
426 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
427 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
428 gSaveBlock3 = (pSaveBlock3) 0x2029808;
429 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
430 loadsave = (void(*)(char)) 0x815319d;
431 //mainloop = (void(*)()) 0x800042b;
432 //titlemid = 0x816fedd;
433 //load_pokemon = (void(*)()) 0x8076dd1;
434
435 break;
436 }
437
438 case 'IEPB': // Emerald Italian
439 {
440 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
441 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
442 gSaveBlock3 = (pSaveBlock3) 0x2029808;
443 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
444 loadsave = (void(*)(char)) 0x8153065;
445 //mainloop = (void(*)()) 0x800042b;
446 //titlemid = 0x816fda5;
447 //load_pokemon = (void(*)()) 0x8076dd5;
448
449 break;
450 }
451
452 case 'SEPB': // Emerald Spanish
453 {
454 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
455 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
456 gSaveBlock3 = (pSaveBlock3) 0x2029808;
457 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
458 loadsave = (void(*)(char)) 0x8153175;
459 //mainloop = (void(*)()) 0x800042b;
460 //titlemid = 0x816feb5;
461 //load_pokemon = (void(*)()) 0x8076dd1;
462
463 break;
464 }
465
466 case 'EEPB': // Emerald English
467 {
468 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
469 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
470 gSaveBlock3 = (pSaveBlock3) 0x2029808;
471 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
472 loadsave = (void(*)(char)) 0x81534d1;
473 //mainloop = (void(*)()) 0x800042b;
474 //titlemid = 0x817014d;
475 //load_pokemon = (void(*)()) 0x8076dd5;
476
477 break;
478 }
479
480 case 'JEPB': // Emerald Japanese
481 {
482 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
483 gSaveBlock2 = (pSaveBlock2) 0x20246F8;
484 gSaveBlock3 = (pSaveBlock3) 0x20294AC;
485 *(pSaveBlock1*)(0x3005aec) = gSaveBlock1;
486 loadsave = (void(*)(char)) 0x815340d;
487 //mainloop = (void(*)()) 0x800042b;
488 //titlemid = 0x816ff45;
489 //load_pokemon = (void(*)()) 0x80767dd;
490
491 break;
492 }
493
494 default:
495 {
496 return false; // this game isn't supported
497 }
498 }
499
500 loadsave(0);
501
502 // now the save is loaded, we can do what we want with the loaded blocks.
503 // first, we're going to want to decrypt the parts that are crypted, if
504 // applicable.
505 decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3);
506
507 *SaveBlock1 = gSaveBlock1;
508 *SaveBlock2 = gSaveBlock2;
509 *SaveBlock3 = gSaveBlock3;
510
511 return true;
512}
diff --git a/gba/source/payload.h b/gba/source/gamedata.h index ea87200..4d0a2a9 100644 --- a/gba/source/payload.h +++ b/gba/source/gamedata.h
@@ -1,14 +1,15 @@
1/* 1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017. 2 * Copyright (C) 2017 hatkirby
3 * Copyright (C) 2017 slipstream/RoL
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details. 6 * of the MIT license. See the LICENSE file for details.
6 *
7 * payload.h: header file describing payload function
8 */ 7 */
8#ifndef _GAMEDATA_H_
9#define _GAMEDATA_H_
9 10
11#include <gba.h>
10#include "saveblocks.h" 12#include "saveblocks.h"
11#include "libpayload.h"
12 13
13#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00') 14#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00')
14#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00') 15#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00')
@@ -20,4 +21,9 @@
20 21
21#define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J') 22#define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J')
22 23
23void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3); \ No newline at end of file 24bool initSaveData(
25 pSaveBlock1* SaveBlock1,
26 pSaveBlock2* SaveBlock2,
27 pSaveBlock3* SaveBlock3);
28
29#endif
diff --git a/gba/source/libpayload.c b/gba/source/libpayload.c deleted file mode 100644 index f13a34f..0000000 --- a/gba/source/libpayload.c +++ /dev/null
@@ -1,312 +0,0 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.c: contains helper functions for the payload
8 */
9
10#include <gba.h>
11#include "payload.h"
12
13// private functions
14static void CryptBoxPokemon(struct BoxPokemon* pkm);
15static u16 crc16(const u8* data, u16 len);
16static u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript);
17
18/**
19 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
20 * Remember to call EncryptPokemon() afterwards.
21 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
22*/
23void DecryptPokemon(struct Pokemon* pkm) {
24 struct BoxPokemon* boxMon = &(pkm->box);
25 CryptBoxPokemon(boxMon);
26}
27
28/**
29 * Private function that does the actual work of crypting the substructures of a BoxPokemon.
30 * @param struct BoxPokemon* pkm The BoxPokemon whose substructures will be crypted.
31*/
32static void CryptBoxPokemon(struct BoxPokemon* pkm) {
33 for (u32 i = 0; i < 12; i++) {
34 pkm->secure.raw[i] ^= (pkm->otId ^ pkm->personality);
35 }
36}
37
38/**
39 * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily.
40 * Used by DecryptPokemon().
41 * Remember to call EncryptPokemon() afterwards.
42 * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of.
43*/
44void DecryptBoxPokemon(struct BoxPokemon* pkm) {
45 CryptBoxPokemon(pkm);
46}
47
48/**
49 * Encrypts the substructures of a Pokémon structure, and fixes the checksum.
50 * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
51 * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of.
52*/
53void EncryptPokemon(struct Pokemon* pkm) {
54 struct BoxPokemon* boxMon = &(pkm->box);
55 EncryptBoxPokemon(boxMon);
56}
57
58/**
59 * Encrypts the substructures of a core Pokémon structure, and fixes the checksum.
60 * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
61 * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of.
62*/
63void EncryptBoxPokemon(struct BoxPokemon* pkm) {
64 FixBoxPokemonChecksum(pkm);
65 CryptBoxPokemon(pkm);
66}
67
68/**
69 * Gets a substructure of a Pokémon structure.
70 * Call DecryptPokemon() first or the substructure data will be encrypted.
71 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
72 * @param u8 substructId The substructure to get.
73 * @return union PokemonSubstruct* The substructure.
74*/
75union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId) {
76 struct BoxPokemon* boxMon = &(pkm->box);
77 return GetBoxPokemonSubstruct(boxMon,substructId);
78}
79
80/**
81 * Gets a substructure of a core Pokémon structure.
82 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
83 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
84 * @param u8 substructId The substructure to get.
85 * @return union PokemonSubstruct* The substructure.
86*/
87union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId) {
88 if (substructId > 3) return NULL;
89 u32 personality = pkm->personality;
90 // Staring at the substruct indexes, I noticed the last two columns are the reverse of the first two!
91 // that is, substructId==2 column is the reverse of substructId==1, substructId==3 is the reverse of substructId==0
92 // At least that means there's no need to hardcode all four.
93 u8 substruct_idxes[2][24] = {
94 { 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3 },
95 { 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2 }
96 };
97 u32 modulo = (personality % 24);
98 if (substructId < 2) {
99 return &( pkm->secure.substructs[ substruct_idxes[substructId][modulo] ] );
100 }
101 return &( pkm->secure.substructs[ substruct_idxes[3 - substructId][23 - modulo] ] );
102}
103
104/**
105 * Gets the checksum of a core Pokémon structure.
106 * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of.
107 * @return u16 The checksum.
108*/
109u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm) {
110 u16 checksum = 0;
111 union PokemonSubstruct* substructs[4] = {
112 GetBoxPokemonSubstruct(pkm,0),
113 GetBoxPokemonSubstruct(pkm,1),
114 GetBoxPokemonSubstruct(pkm,2),
115 GetBoxPokemonSubstruct(pkm,3)
116 };
117
118 for (int substruct = 0; substruct < 4; substruct++) {
119 for (int i = 0; i < 6; i++) {
120 checksum += substructs[substruct]->raw[i];
121 }
122 }
123 return checksum;
124}
125
126/**
127 * Fixes the checksum of a core Pokémon structure.
128 * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of.
129*/
130void FixBoxPokemonChecksum(struct BoxPokemon* pkm) {
131 pkm->checksum = CalculateBoxPokemonChecksum(pkm);
132}
133
134/**
135 * Gets the zeroth substructure ("Growth") of a Pokémon structure.
136 * Call DecryptPokemon() first or the substructure data will be encrypted.
137 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
138 * @return struct PokemonSubstruct0* The substructure.
139*/
140struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm) {
141 struct BoxPokemon* boxMon = &(pkm->box);
142 return GetBoxPokemonSubstruct0(boxMon);
143}
144
145/**
146 * Gets the zeroth substructure ("Growth") of a core Pokémon structure.
147 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
148 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
149 * @return struct PokemonSubstruct0* The substructure.
150*/
151struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm) {
152 return &( GetBoxPokemonSubstruct(pkm,0)->type0 );
153}
154
155/**
156 * Gets the first substructure ("Attacks") of a Pokémon structure.
157 * Call DecryptPokemon() first or the substructure data will be encrypted.
158 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
159 * @return struct PokemonSubstruct0* The substructure.
160*/
161struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm) {
162 struct BoxPokemon* boxMon = &(pkm->box);
163 return GetBoxPokemonSubstruct1(boxMon);
164}
165
166/**
167 * Gets the first substructure ("Attacks") of a core Pokémon structure.
168 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
169 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
170 * @return struct PokemonSubstruct1* The substructure.
171*/
172struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm) {
173 return &( GetBoxPokemonSubstruct(pkm,1)->type1 );
174}
175
176/**
177 * Gets the second substructure ("EVs & Condition") of a Pokémon structure.
178 * Call DecryptPokemon() first or the substructure data will be encrypted.
179 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
180 * @return struct PokemonSubstruct0* The substructure.
181*/
182struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm) {
183 struct BoxPokemon* boxMon = &(pkm->box);
184 return GetBoxPokemonSubstruct2(boxMon);
185}
186
187/**
188 * Gets the second substructure ("EVs & Condition") of a core Pokémon structure.
189 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
190 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
191 * @return struct PokemonSubstruct2* The substructure.
192*/
193struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm) {
194 return &( GetBoxPokemonSubstruct(pkm,2)->type2 );
195}
196
197/**
198 * Gets the third substructure ("Miscellaneous") of a Pokémon structure.
199 * Call DecryptPokemon() first or the substructure data will be encrypted.
200 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
201 * @return struct PokemonSubstruct0* The substructure.
202*/
203struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm) {
204 struct BoxPokemon* boxMon = &(pkm->box);
205 return GetBoxPokemonSubstruct3(boxMon);
206}
207
208/**
209 * Gets the third substructure ("Miscellaneous") of a core Pokémon structure.
210 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
211 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
212 * @return struct PokemonSubstruct3* The substructure.
213*/
214struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm) {
215 return &( GetBoxPokemonSubstruct(pkm,3)->type3 );
216}
217
218/**
219 * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1.
220 * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for.
221 * @return u32 The checksum.
222*/
223u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry) {
224 if (!GAME_RS) return 0; // Enigma Berry structure changed in FR/LG, use CalculateEnigmaBerryChecksumFRLGE() instead.
225 u32 checksum = 0;
226 // Save off and zero out the original Enigma Berry description pointers.
227 const u8* description[2] = { enigmaBerry->berry.description1, enigmaBerry->berry.description2 };
228 enigmaBerry->berry.description1 = enigmaBerry->berry.description2 = NULL;
229 u8* enigmaBerryBytes = (u8*)enigmaBerry;
230 // Calculate the checksum.
231 for (u32 i = 0; i < 1324; i++) {
232 checksum += enigmaBerryBytes[i];
233 }
234 // Restore the saved description.
235 enigmaBerry->berry.description1 = description[0];
236 enigmaBerry->berry.description2 = description[1];
237 return checksum;
238}
239
240/**
241 * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1.
242 * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for.
243 * @return u32 The checksum.
244*/
245u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry) {
246 if (GAME_RS) return 0; // Enigma Berry structure is different in R/S, use CalculateEnigmaBerryChecksumRS() instead.
247 u32 checksum = 0;
248 u8* enigmaBerryBytes = (u8*)enigmaBerry;
249 for (int i = 0; i < 0x30; i++) {
250 checksum += enigmaBerryBytes[i];
251 }
252 return checksum;
253}
254
255/**
256 * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game)
257 * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for.
258 * @return u32 The checksum.
259 */
260u32 CalculateEnigmaBerryChecksum(void* enigmaBerry) {
261 if (GAME_RS) return CalculateEnigmaBerryChecksumRS( (struct EnigmaBerry*) enigmaBerry );
262 return CalculateEnigmaBerryChecksumFRLGE( (struct EnigmaBerryFRLGE*) enigmaBerry );
263}
264
265/**
266 * Calculates the checksum for a RAM script structure in SaveBlock1.
267 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
268 * @return u32 The checksum.
269 */
270u32 CalculateRamScriptChecksum(struct RamScript* ramScript) {
271 asm(""); // make sure the call to CalculateRamScriptDataChecksum() is *not* inlined.
272 // For some reason, if it gets inlined, something happens, and the wrong length is used when checksumming...
273 return CalculateRamScriptDataChecksum(&ramScript->data);
274}
275
276/**
277 * Calculates the checksum for a RAM script structure in SaveBlock1.
278 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
279 * @return u32 The checksum.
280 */
281static __attribute__ ((noinline)) u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript) {
282 u32 checksum = 0;
283 u32 i = 0;
284 u8* ramScriptBytes = (u8*)(ramScript);
285 if (GAME_RS) {
286 for (i = 0; i < sizeof(struct RamScriptData); i++) checksum += ramScriptBytes[i];
287 return checksum;
288 }
289
290 return (u32)crc16(ramScriptBytes,sizeof(struct RamScriptData) + 1);
291}
292
293/**
294 * Private function to CRC-16, (used by FR/LG/Emerald ramscript checksum). Adapted from http://forums.glitchcity.info/index.php?topic=7114.0
295 * @param u8* Data to checksum
296 * @param u16 Length of data
297 * @return u16 The checksum
298*/
299static u16 crc16(const u8* data, u16 len) {
300 u16 crc = 0x1121;
301 for (u16 i = 0; i < len; ++i) {
302 crc ^= data[i];
303 for (u16 j = 0; j < 8; ++j) {
304 if(crc & 1) {
305 crc = (crc >> 1) ^ 0x8408;
306 } else {
307 crc >>= 1;
308 }
309 }
310 }
311 return ~crc;
312} \ No newline at end of file
diff --git a/gba/source/libpayload.h b/gba/source/libpayload.h deleted file mode 100644 index 4be6fb3..0000000 --- a/gba/source/libpayload.h +++ /dev/null
@@ -1,160 +0,0 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.h: header for payload helper functions
8 */
9
10/**
11 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
12 * Remember to call EncryptPokemon() afterwards.
13 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
14*/
15void DecryptPokemon(struct Pokemon* pkm);
16
17/**
18 * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily.
19 * Used by DecryptPokemon().
20 * Remember to call EncryptPokemon() afterwards.
21 * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of.
22*/
23void DecryptBoxPokemon(struct BoxPokemon* pkm);
24
25/**
26 * Encrypts the substructures of a Pokémon structure, and fixes the checksum.
27 * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
28 * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of.
29*/
30void EncryptPokemon(struct Pokemon* pkm);
31
32/**
33 * Encrypts the substructures of a core Pokémon structure, and fixes the checksum.
34 * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
35 * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of.
36*/
37void EncryptBoxPokemon(struct BoxPokemon* pkm);
38
39/**
40 * Gets a substructure of a Pokémon structure.
41 * Call DecryptPokemon() first or the substructure data will be encrypted.
42 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
43 * @param u8 substructId The substructure to get.
44 * @return union PokemonSubstruct* The substructure.
45*/
46union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId);
47
48/**
49 * Gets a substructure of a core Pokémon structure.
50 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
51 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
52 * @param u8 substructId The substructure to get.
53 * @return union PokemonSubstruct* The substructure.
54*/
55union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId);
56
57/**
58 * Gets the checksum of a core Pokémon structure.
59 * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of.
60 * @return u16 The checksum.
61*/
62u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm);
63
64/**
65 * Fixes the checksum of a core Pokémon structure.
66 * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of.
67*/
68void FixBoxPokemonChecksum(struct BoxPokemon* pkm);
69
70/**
71 * Gets the zeroth substructure ("Growth") of a Pokémon structure.
72 * Call DecryptPokemon() first or the substructure data will be encrypted.
73 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
74 * @return struct PokemonSubstruct0* The substructure.
75*/
76struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm);
77
78/**
79 * Gets the zeroth substructure ("Growth") of a core Pokémon structure.
80 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
81 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
82 * @return struct PokemonSubstruct0* The substructure.
83*/
84struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm);
85
86/**
87 * Gets the first substructure ("Attacks") of a Pokémon structure.
88 * Call DecryptPokemon() first or the substructure data will be encrypted.
89 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
90 * @return struct PokemonSubstruct0* The substructure.
91*/
92struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm);
93
94/**
95 * Gets the first substructure ("Attacks") of a core Pokémon structure.
96 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
97 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
98 * @return struct PokemonSubstruct1* The substructure.
99*/
100struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm);
101
102/**
103 * Gets the second substructure ("EVs & Condition") of a Pokémon structure.
104 * Call DecryptPokemon() first or the substructure data will be encrypted.
105 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
106 * @return struct PokemonSubstruct0* The substructure.
107*/
108struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm);
109
110/**
111 * Gets the second substructure ("EVs & Condition") of a core Pokémon structure.
112 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
113 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
114 * @return struct PokemonSubstruct2* The substructure.
115*/
116struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm);
117
118/**
119 * Gets the third substructure ("Miscellaneous") of a Pokémon structure.
120 * Call DecryptPokemon() first or the substructure data will be encrypted.
121 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
122 * @return struct PokemonSubstruct0* The substructure.
123*/
124struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm);
125
126/**
127 * Gets the third substructure ("Miscellaneous") of a core Pokémon structure.
128 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
129 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
130 * @return struct PokemonSubstruct3* The substructure.
131*/
132struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm);
133
134/**
135 * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1.
136 * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for.
137 * @return u32 The checksum.
138*/
139u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry);
140
141/**
142 * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1.
143 * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for.
144 * @return u32 The checksum.
145*/
146u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry);
147
148/**
149 * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game)
150 * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for.
151 * @return u32 The checksum.
152 */
153u32 CalculateEnigmaBerryChecksum(void* enigmaBerry);
154
155/**
156 * Calculates the checksum for a RAM script structure in SaveBlock1.
157 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
158 * @return u32 The checksum.
159 */
160u32 CalculateRamScriptChecksum(struct RamScript* ramScript); \ No newline at end of file
diff --git a/gba/source/link.c b/gba/source/link.c new file mode 100644 index 0000000..c84e44d --- /dev/null +++ b/gba/source/link.c
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 */
7#include "link.h"
8
9#define JOY_WRITE 2
10#define JOY_READ 4
11#define JOY_RW 6
12
13void initializeLink()
14{
15 REG_HS_CTRL |= JOY_RW;
16 REG_JOYTR = 0;
17 while ((REG_HS_CTRL & JOY_WRITE) == 0);
18 REG_HS_CTRL |= JOY_RW;
19}
20
21void waitForAck()
22{
23 while ((REG_HS_CTRL & JOY_WRITE) == 0);
24 REG_HS_CTRL |= JOY_RW;
25 REG_JOYTR = 0;
26 while ((REG_HS_CTRL & JOY_WRITE) == 0);
27 REG_HS_CTRL |= JOY_RW;
28}
29
30void sendS32(s32 val)
31{
32 REG_JOYTR = val;
33}
34
35void sendU32(u32 val)
36{
37 REG_JOYTR = val;
38}
diff --git a/gba/source/link.h b/gba/source/link.h new file mode 100644 index 0000000..08fd998 --- /dev/null +++ b/gba/source/link.h
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 */
7#ifndef _LINK_H_
8#define _LINK_H_
9
10#include <gba.h>
11
12void initializeLink();
13void waitForAck();
14void sendS32(s32 val);
15void sendU32(u32 val);
16
17#endif
diff --git a/gba/source/main.c b/gba/source/main.c index 4e1e31f..9f97324 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -1,380 +1,110 @@
1/* 1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017. 2 * Copyright (C) 2017 hatkirby
3 * 3 *
4 * This software may be modified and distributed under the terms 4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details. 5 * of the MIT license. See the LICENSE file for details.
6 *
7 * main.c: setup, call payload, return gracefully back to game
8 */ 6 */
9#include <gba.h> 7#include <gba.h>
10#include "payload.h" 8#include "gamedata.h"
9#include "link.h"
11 10
12void call_into_middle_of_titlescreen_func(u32 addr,u32 stackspace); 11int main(void)
12{
13 initializeLink();
13 14
14void decrypt_save_structures(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) { 15 // Identify the host game.
15 if (GAME_RS) { 16 if (GAME_RUBY)
16 // R/S doesn't have save crypto. 17 {
17 return; 18 sendS32(1);
18 } 19 } else if (GAME_SAPP)
19 u8* sb1raw = (u8*)SaveBlock1; 20 {
20 u8* sb2raw = (u8*)SaveBlock2; 21 sendS32(2);
21 //u8* sb3raw = (u8*)SaveBlock3; // unused 22 } else if (GAME_FR)
22 23 {
23 u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]); 24 sendS32(3);
24 25 } else if (GAME_LG)
25 u32 xor_key = *xor_key_ptr; 26 {
26 u16 xor_key16 = (u16)xor_key; 27 sendS32(4);
27 if (!xor_key) { 28 } else if (GAME_EM)
28 // xor key is zero, nothing needs to be done. 29 {
29 return; 30 sendS32(5);
30 } 31 } else {
31 32 sendS32(-1);
32 u32* ptr_to_xor; 33 waitForAck();
33 u32 save_offset;
34 int i;
35 u32* bag_pocket_offsets;
36 u32* bag_pocket_counts;
37 if (GAME_FRLG) {
38 // loop over and decrypt various things
39 save_offset = 0x3D38 + 4;
40 for (i = 3; i >= 0; i--) {
41 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
42 *ptr_to_xor ^= xor_key;
43 save_offset += 12;
44 }
45 for (i = 0; i <= 0x3f; i++) {
46 save_offset = 0x1200 + (i*sizeof(u32));
47 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
48 *ptr_to_xor ^= xor_key;
49 }
50 // loop over each of the bag pockets and decrypt decrypt decrypt
51 bag_pocket_offsets = (u32[5]) { 0x310, 0x388, 0x430, 0x464, 0x54C };
52 bag_pocket_counts = (u32[5]) { 42, 30, 13, 58, 43 };
53 for (i = 0; i < 5; i++) {
54 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++) {
55 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
56 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
57 }
58 }
59 // decrypt some more stuff
60 save_offset = 0xaf8;
61 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
62 *ptr_to_xor ^= xor_key;
63 save_offset = 0x290;
64 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
65 *ptr_to_xor ^= xor_key;
66 save_offset = 0x294;
67 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
68 } else { // Emerald
69 // loop over and decrypt various things
70 for (i = 0; i <= 0x3f; i++) {
71 save_offset = 0x159c + (i*sizeof(u32));
72 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
73 *ptr_to_xor ^= xor_key;
74 }
75 // loop over each of the bag pockets and decrypt decrypt decrypt
76 bag_pocket_offsets = (u32[5]) { 0x560, 0x5D8, 0x650, 0x690, 0x790 };
77 bag_pocket_counts = (u32[5]) { 30, 30, 16, 64, 46 };
78 for (i = 0; i < 5; i++) {
79 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++) {
80 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
81 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
82 }
83 }
84 // decrypt some more stuff
85 save_offset = 0x1F4;
86 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
87 *ptr_to_xor ^= xor_key;
88 save_offset = 0x490;
89 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
90 *ptr_to_xor ^= xor_key;
91 save_offset = 0x494;
92 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
93 }
94
95 *xor_key_ptr = 0;
96 return;
97
98}
99 34
100int main(void) { 35 return 0;
101 // check the ROM code, make sure this game is supported. 36 }
102 u8* ROM = (u8*) 0x8000000; 37
103 38 waitForAck();
104 u32 gamecode = (*(u32*)(&ROM[0xAC])); 39
105 40 // Get access to save data.
106 void(*loadsave)(char a1); 41 pSaveBlock1 SaveBlock1;
107 void(*mainloop)(); 42 pSaveBlock2 SaveBlock2;
108 void(*load_pokemon)(); 43 pSaveBlock3 SaveBlock3;
109 pSaveBlock1 gSaveBlock1; 44
110 pSaveBlock2 gSaveBlock2; 45 if (!initSaveData(&SaveBlock1, &SaveBlock2, &SaveBlock3))
111 pSaveBlock3 gSaveBlock3; 46 {
112 u32 titlemid = 0; 47 // Unsupported game version.
113 // get the address of the save loading function. 48 sendS32(-1);
114 switch (gamecode) { 49 waitForAck();
115 // --- R/S --- 50
116 case 'DVXA': // Ruby German 51 return 0;
117 case 'DPXA': // Sapphire German 52 }
118 // TODO: detect debug ROM? 53
119 gSaveBlock1 = (pSaveBlock1) 0x2025734; 54 sendS32(1);
120 gSaveBlock2 = (pSaveBlock2) 0x2024EA4; 55 waitForAck();
121 gSaveBlock3 = (pSaveBlock3) 0x20300A0; 56
122 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1 57 // Send trainer name.
123 mainloop = (void(*)()) 0x80003D9; 58 u8* trainerName = 0;
124 load_pokemon = (void(*)()) 0x8047da9;
125 break;
126 case 'FVXA': // Ruby French
127 case 'FPXA': // Sapphire French
128 gSaveBlock1 = (pSaveBlock1) 0x2025734;
129 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
130 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
131 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1
132 mainloop = (void(*)()) 0x80003D9;
133 load_pokemon = (void(*)()) 0x8047e95;
134 break;
135 case 'IVXA': // Ruby Italian
136 case 'IPXA': // Sapphire Italian
137 gSaveBlock1 = (pSaveBlock1) 0x2025734;
138 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
139 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
140 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
141 mainloop = (void(*)()) 0x80003D9;
142 load_pokemon = (void(*)()) 0x8047dbd;
143 break;
144 case 'SVXA': // Ruby Spanish
145 case 'SPXA': // Sapphire Spanish
146 gSaveBlock1 = (pSaveBlock1) 0x2025734;
147 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
148 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
149 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1
150 mainloop = (void(*)()) 0x80003D9;
151 load_pokemon = (void(*)()) 0x8047ea5;
152 break;
153 case 'EVXA': // Ruby English
154 case 'EPXA': // Sapphire English
155 gSaveBlock1 = (pSaveBlock1) 0x2025734;
156 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
157 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
158 mainloop = (void(*)()) 0x80002A5;
159 switch (ROM[0xBC]) { // version number
160 case 0:
161 loadsave = (void(*)(char)) 0x8125EC9;
162 load_pokemon = (void(*)()) 0x8047a85;
163 break;
164 case 1:
165 case 2:
166 loadsave = (void(*)(char)) 0x8125EE9;
167 load_pokemon = (void(*)()) 0x8047aa5;
168 break;
169 default:
170 return 0; // unsupported version
171 }
172 break;
173 case 'JVXA': // Ruby Japanese
174 case 'JPXA': // Sapphire Japanese
175 gSaveBlock1 = (pSaveBlock1) 0x2025494;
176 gSaveBlock2 = (pSaveBlock2) 0x2024C04;
177 gSaveBlock3 = (pSaveBlock3) 0x202FDBC;
178 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1
179 mainloop = (void(*)()) 0x80002A9;
180 load_pokemon = (void(*)()) 0x8044d55;
181 break;
182 /// --- FR/LG ---
183 // In FR/LG, the function that initialises the save-block pointers to default does not set up saveblock3.
184 // Which will need to be set up before loading the save if we want boxed Pokémon to not disappear.
185 // Oh, and loadsave() offset is different between FR and LG...
186 case 'DRPB': // FireRed German
187 case 'DGPB': // LeafGreen German
188 gSaveBlock1 = (pSaveBlock1) 0x202552C;
189 gSaveBlock2 = (pSaveBlock2) 0x2024588;
190 gSaveBlock3 = (pSaveBlock3) 0x2029314;
191 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
192 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
193 mainloop = (void(*)()) 0x8000425;
194 titlemid = 0x80791df;
195 load_pokemon = (void(*)()) 0x804c251;
196 break;
197 case 'FRPB': // FireRed French
198 case 'FGPB': // LeafGreen French
199 gSaveBlock1 = (pSaveBlock1) 0x202552C;
200 gSaveBlock2 = (pSaveBlock2) 0x2024588;
201 gSaveBlock3 = (pSaveBlock3) 0x2029314;
202 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
203 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
204 mainloop = (void(*)()) 0x8000417;
205 titlemid = 0x807929f;
206 load_pokemon = (void(*)()) 0x804c311;
207 break;
208 case 'IRPB': // FireRed Italian
209 case 'IGPB': // LeafGreen Italian
210 gSaveBlock1 = (pSaveBlock1) 0x202552C;
211 gSaveBlock2 = (pSaveBlock2) 0x2024588;
212 gSaveBlock3 = (pSaveBlock3) 0x2029314;
213 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
214 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
215 mainloop = (void(*)()) 0x8000425;
216 titlemid = 0x80791cb;
217 load_pokemon = (void(*)()) 0x804c23d;
218 break;
219 case 'SRPB': // FireRed Spanish
220 case 'SGPB': // LeafGreen Spanish
221 gSaveBlock1 = (pSaveBlock1) 0x202552C;
222 gSaveBlock2 = (pSaveBlock2) 0x2024588;
223 gSaveBlock3 = (pSaveBlock3) 0x2029314;
224 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
225 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
226 mainloop = (void(*)()) 0x8000417;
227 titlemid = 0x80792b3;
228 load_pokemon = (void(*)()) 0x804c325;
229 break;
230 case 'ERPB': // FireRed English
231 case 'EGPB': // LeafGreen English
232 gSaveBlock1 = (pSaveBlock1) 0x202552C;
233 gSaveBlock2 = (pSaveBlock2) 0x2024588;
234 gSaveBlock3 = (pSaveBlock3) 0x2029314;
235 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
236 switch (ROM[0xBC]) { // version number
237 case 0:
238 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
239 mainloop = (void(*)()) 0x800041b;
240 titlemid = 0x807927b;
241 load_pokemon = (void(*)()) 0x804c231;
242 break;
243 case 1:
244 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
245 mainloop = (void(*)()) 0x8000429;
246 titlemid = 0x807928f;
247 load_pokemon = (void(*)()) 0x804c245;
248 break;
249 default:
250 return 0; // unsupported version
251 }
252 break;
253 case 'JRPB': // FireRed Japanese
254 case 'JGPB': // LeafGreen Japanese
255 gSaveBlock1 = (pSaveBlock1) 0x202548C;
256 gSaveBlock2 = (pSaveBlock2) 0x20244E8;
257 gSaveBlock3 = (pSaveBlock3) 0x202924C;
258 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
259 switch (ROM[0xBC]) { // version number
260 case 0:
261 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
262 mainloop = (void(*)()) 0x800041b;
263 titlemid = 0x8078a0f;
264 load_pokemon = (void(*)()) 0x804b9e9;
265 break;
266 case 1:
267 if ((gamecode << 8) == 'GPB\x00') {
268 // LeafGreen v1.1 Japanese is undumped.
269 // Therefore, it is unsupported.
270 // I will make guesses at the offsets in the comments, but I will not actually implement them until LeafGreen v1.1 is dumped.
271 return 0;
272 }
273 loadsave = (void(*)(char)) 0x80db529; // potential LG1.1 address: 0x80db4fd
274 mainloop = (void(*)()) 0x8000417;
275 titlemid = 0x8078987;
276 load_pokemon = (void(*)()) 0x804b9c5;
277 break;
278 default:
279 return 0; // unsupported version
280 }
281 break;
282 /// --- Emerald ---
283 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in FR/LG it was saveblock3).
284 // The initial save loading code after the copyright screen is also updated, now it sets up ASLR/crypto here before loading the save.
285 case 'DEPB': // Emerald German
286 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
287 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
288 gSaveBlock3 = (pSaveBlock3) 0x2029808;
289 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
290 loadsave = (void(*)(char)) 0x8153075;
291 mainloop = (void(*)()) 0x800042b;
292 titlemid = 0x816fdb5;
293 load_pokemon = (void(*)()) 0x8076dd5;
294 break;
295 case 'FEPB': // Emerald French
296 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
297 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
298 gSaveBlock3 = (pSaveBlock3) 0x2029808;
299 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
300 loadsave = (void(*)(char)) 0x815319d;
301 mainloop = (void(*)()) 0x800042b;
302 titlemid = 0x816fedd;
303 load_pokemon = (void(*)()) 0x8076dd1;
304 break;
305 case 'IEPB': // Emerald Italian
306 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
307 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
308 gSaveBlock3 = (pSaveBlock3) 0x2029808;
309 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
310 loadsave = (void(*)(char)) 0x8153065;
311 mainloop = (void(*)()) 0x800042b;
312 titlemid = 0x816fda5;
313 load_pokemon = (void(*)()) 0x8076dd5;
314 break;
315 case 'SEPB': // Emerald Spanish
316 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
317 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
318 gSaveBlock3 = (pSaveBlock3) 0x2029808;
319 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
320 loadsave = (void(*)(char)) 0x8153175;
321 mainloop = (void(*)()) 0x800042b;
322 titlemid = 0x816feb5;
323 load_pokemon = (void(*)()) 0x8076dd1;
324 break;
325 case 'EEPB': // Emerald English
326 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
327 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
328 gSaveBlock3 = (pSaveBlock3) 0x2029808;
329 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
330 loadsave = (void(*)(char)) 0x81534d1;
331 mainloop = (void(*)()) 0x800042b;
332 titlemid = 0x817014d;
333 load_pokemon = (void(*)()) 0x8076dd5;
334 break;
335 case 'JEPB': // Emerald Japanese
336 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
337 gSaveBlock2 = (pSaveBlock2) 0x20246F8;
338 gSaveBlock3 = (pSaveBlock3) 0x20294AC;
339 *(pSaveBlock1*)(0x3005aec) = gSaveBlock1;
340 loadsave = (void(*)(char)) 0x815340d;
341 mainloop = (void(*)()) 0x800042b;
342 titlemid = 0x816ff45;
343 load_pokemon = (void(*)()) 0x80767dd;
344 break;
345 default:
346 return 0; // this game isn't supported
347 }
348 loadsave(0);
349 // now the save is loaded, we can do what we want with the loaded blocks.
350 // first, we're going to want to decrypt the parts that are crypted, if applicable.
351 decrypt_save_structures(gSaveBlock1,gSaveBlock2,gSaveBlock3);
352 // time to call the payload.
353 payload(gSaveBlock1,gSaveBlock2,gSaveBlock3);
354 // Now, we better call the function that sets the pokemon-related stuff from the structure elements of the loaded save again.
355 // Just in case the payload did something with that.
356 load_pokemon();
357 // In FR/LG/Emerald, just returning to the game is unwise.
358 // The game reloads the savefile.
359 // In FR/LG, this is done at the title screen after setting ASLR/saveblock-crypto up. (probably because at initial save-load, SaveBlock3 ptr isn't set up lol)
360 // So, better bypass the title screen and get the game to return directly to the Continue/New Game screen.
361 // In Emerald, the save reload happens after the Continue option was chosen, so we have no choice but to bypass everything and get the game to go straight to the overworld.
362 // Easiest way to do this is to call into the middle of the function we want, using an ASM wrapper to set up the stack.
363 // Here goes...
364 if (titlemid) {
365 // Function reserves an extra 4 bytes of stack space in FireRed/LeafGreen, and none in Emerald.
366 call_into_middle_of_titlescreen_func(titlemid,(GAME_EM ? 0 : 4));
367 }
368 // Now we've done what we want, time to return to the game.
369 // Can't just return, the game will reload the save.
370 // So let's just call the main-loop directly ;)
371 // turn the sound back on before we head back to the game
372 *(vu16 *)(REG_BASE + 0x84) = 0x8f;
373 // re-enable interrupts
374 REG_IME = 1;
375 mainloop();
376 // Anything past here will not be executed.
377 return 0;
378}
379 59
60 if (GAME_RS)
61 {
62 trainerName = SaveBlock2->rs.playerName;
63 } else if (GAME_FRLG)
64 {
65 trainerName = SaveBlock2->frlg.playerName;
66 } else if (GAME_EM)
67 {
68 trainerName = SaveBlock2->e.playerName;
69 }
380 70
71 u32 tn1 =
72 (trainerName[0] << 24)
73 | (trainerName[1] << 16)
74 | (trainerName[2] << 8)
75 | (trainerName[3]);
76
77 u32 tn2 =
78 (trainerName[4] << 24)
79 | (trainerName[5] << 16)
80 | (trainerName[6] << 8)
81 | (trainerName[7]);
82
83 sendU32(tn1);
84 waitForAck();
85
86 sendU32(tn2);
87 waitForAck();
88
89 // Send trainer ID.
90 u8* trainerId = 0;
91 if (GAME_RS)
92 {
93 trainerId = SaveBlock2->rs.playerTrainerId;
94 } else if (GAME_FRLG)
95 {
96 trainerId = SaveBlock2->frlg.playerTrainerId;
97 } else if (GAME_EM)
98 {
99 trainerId = SaveBlock2->e.playerTrainerId;
100 }
101
102 u32 tti =
103 (trainerId[1] << 8)
104 | (trainerId[0]);
105
106 sendU32(tti);
107 waitForAck();
108
109 // Halt();
110}
diff --git a/gba/source/payload.c b/gba/source/payload.c deleted file mode 100644 index 665af70..0000000 --- a/gba/source/payload.c +++ /dev/null
@@ -1,72 +0,0 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * payload.c: place where user payload should go :)
8 */
9
10#include <gba.h>
11#include "payload.h"
12
13// Your payload code should obviously go into the body of this, the payload function.
14void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
15 // HoF-warp example payload!
16
17 // Structure offsets are different between R/S, FR/LG, and Emerald.
18 // The beginning of the structures are the same but do NOT take shortcuts here, it's not good practise.
19 // If you want to support multiple games, make specific checks for games, use the right structure for each game.
20 SaveBlock1_RS* sb1rs = &SaveBlock1->rs;
21 SaveBlock1_FRLG* sb1frlg = &SaveBlock1->frlg;
22 SaveBlock1_E* sb1e = &SaveBlock1->e;
23 if (GAME_FRLG) {
24 sb1frlg->location.mapGroup = 1; // generic indoors?
25 sb1frlg->location.mapNum = 80; // Hall of Fame
26 // set coords to the same place that the champions' room script sets them to
27 sb1frlg->location.x = sb1frlg->pos.x = 5;
28 sb1frlg->location.y = sb1frlg->pos.y = 12;
29 sb1frlg->mapDataId = 0xDA; // from HoF map-header
30 sb1frlg->location.warpId = 0xff;
31 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
32 if (sb1frlg->playerPartyCount == 0) {
33 sb1frlg->playerPartyCount = 1;
34 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
35 // so let's hack together one. i don't care about it becoming a bad egg at all.
36 sb1frlg->playerParty[0].box.personality++;
37 }
38 return;
39 } else if (GAME_RS) {
40 sb1rs->location.mapGroup = 16; // Ever Grande City
41 sb1rs->location.mapNum = 11; // Hall of Fame
42 // set coords to the same place that the champions' room script sets them to
43 sb1rs->location.x = sb1rs->pos.x = 7;
44 sb1rs->location.y = sb1rs->pos.y = 16;
45 sb1rs->mapDataId = 299; // from HoF map-header
46 sb1rs->location.warpId = 0xff;
47 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
48 if (sb1rs->playerPartyCount == 0) {
49 sb1rs->playerPartyCount = 1;
50 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
51 // so let's hack together one. i don't care about it becoming a bad egg at all.
52 sb1rs->playerParty[0].box.personality++;
53 }
54 return;
55 } else if (GAME_EM) {
56 sb1e->location.mapGroup = 16; // Ever Grande City
57 sb1e->location.mapNum = 11; // Hall of Fame
58 // set coords to the same place that the champions' room script sets them to
59 sb1e->location.x = sb1e->pos.x = 7;
60 sb1e->location.y = sb1e->pos.y = 16;
61 sb1e->mapDataId = 298; // from HoF map-header
62 sb1e->location.warpId = 0xff;
63 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
64 if (sb1e->playerPartyCount == 0) {
65 sb1e->playerPartyCount = 1;
66 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
67 // so let's hack together one. i don't care about it becoming a bad egg at all.
68 sb1e->playerParty[0].box.personality++;
69 }
70 return;
71 }
72} \ No newline at end of file
diff --git a/source/encoding.c b/source/encoding.c new file mode 100644 index 0000000..7b70df2 --- /dev/null +++ b/source/encoding.c
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * Gen 3 proprietary encoding information from Bulbapedia:
8 * https://bulbapedia.bulbagarden.net/wiki/Character_encoding_in_Generation_III
9 */
10#include "encoding.h"
11
12const char charmap[] = {
13 ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '?', '.', '-', ' ',
14 ' ', '\"', '\"', '\'', '\'', '*', '*', ' ', ',', ' ', '/', 'A', 'B', 'C', 'D', 'E',
15 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
16 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
17 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' '
18};
19
20char debugGen3Decode(u8 val)
21{
22 return charmap[val - 0xA0];
23}
diff --git a/source/encoding.h b/source/encoding.h new file mode 100644 index 0000000..4dc3b1f --- /dev/null +++ b/source/encoding.h
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 */
7#ifndef ENCODING_H_95547384
8#define ENCODING_H_95547384
9
10#include <gccore.h>
11
12char debugGen3Decode(u8 val);
13
14#endif /* end of include guard: ENCODING_H_95547384 */
diff --git a/source/link.c b/source/link.c new file mode 100644 index 0000000..4178293 --- /dev/null +++ b/source/link.c
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 */
7#include "link.h"
8
9u32 waitForButtons(u32 mask)
10{
11 for (;;)
12 {
13 PAD_ScanPads();
14 VIDEO_WaitVSync();
15
16 u32 btns = PAD_ButtonsDown(0);
17 if (btns & mask)
18 {
19 return btns;
20 }
21 }
22}
diff --git a/source/link.h b/source/link.h new file mode 100644 index 0000000..24a60b5 --- /dev/null +++ b/source/link.h
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 */
7#ifndef _LINK_H_
8#define _LINK_H_
9
10#include <gccore.h>
11
12u32 waitForButtons(u32 mask);
13
14#endif
diff --git a/source/main.c b/source/main.c index ad34eff..8a9e672 100644 --- a/source/main.c +++ b/source/main.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2017 slipstream/RoL 2 * Copyright (C) 2017 hatkirby
3 * Copyright (C) 2017 slipstream/RoL
3 * Copyright (C) 2016 FIX94 4 * Copyright (C) 2016 FIX94
4 * 5 *
5 * This software may be modified and distributed under the terms 6 * This software may be modified and distributed under the terms
@@ -7,13 +8,12 @@
7 */ 8 */
8#include <gccore.h> 9#include <gccore.h>
9#include <stdio.h> 10#include <stdio.h>
10#include <malloc.h> 11#include <stdlib.h>
11#include <unistd.h> 12#include <unistd.h>
12#include <string.h> 13#include <string.h>
13#include <stdlib.h> 14#include <malloc.h>
14#include <sys/types.h> 15#include "link.h"
15#include <sys/stat.h> 16#include "encoding.h"
16#include <fcntl.h>
17 17
18//from my tests 50us seems to be the lowest 18//from my tests 50us seems to be the lowest
19//safe si transfer delay in between calls 19//safe si transfer delay in between calls
@@ -24,10 +24,11 @@ extern u32 gba_mb_gba_size;
24 24
25void printmain() 25void printmain()
26{ 26{
27 printf("\x1b[2J"); 27 printf("\x1b[2J");
28 printf("\x1b[37m"); 28 printf("\x1b[37m");
29 printf("Pokemon Gen 3 GBA Multiboot PoC by slipstream/RoL\n"); 29 printf("Pokemon Gen III Data Extractor by hatkirby\n");
30 printf("Based on GBA Link Cable Dumper by FIX94\n\n"); 30 printf("Based on gba-gen3multiboot by slipstream/RoL\n");
31 printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n");
31} 32}
32 33
33u8 *resbuf,*cmdbuf; 34u8 *resbuf,*cmdbuf;
@@ -35,285 +36,494 @@ u8 *resbuf,*cmdbuf;
35volatile u32 transval = 0; 36volatile u32 transval = 0;
36void transcb(s32 chan, u32 ret) 37void transcb(s32 chan, u32 ret)
37{ 38{
38 transval = 1; 39 transval = 1;
39} 40}
40 41
41volatile u32 resval = 0; 42volatile u32 resval = 0;
42void acb(s32 res, u32 val) 43void acb(s32 res, u32 val)
43{ 44{
44 resval = val; 45 resval = val;
45} 46}
46 47
47unsigned int docrc(u32 crc,u32 val) { 48unsigned int docrc(u32 crc,u32 val)
49{
48 u32 result; 50 u32 result;
49 51
50 result = val ^ crc; 52 result = val ^ crc;
51 for (int i = 0; i < 0x20; i++) { 53 for (int i = 0; i < 0x20; i++)
52 if (result & 1) { 54 {
55 if (result & 1)
56 {
53 result >>= 1; 57 result >>= 1;
54 result ^= 0xA1C1; 58 result ^= 0xA1C1;
55 } else result >>= 1; 59 } else {
60 result >>= 1;
61 }
56 } 62 }
63
57 return result; 64 return result;
58} 65}
59 66
60void endproc() 67void doreset()
61{ 68{
62 printf("Start pressed, exit\n"); 69 cmdbuf[0] = 0xFF; //reset
63 VIDEO_WaitVSync(); 70 transval = 0;
64 VIDEO_WaitVSync(); 71 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
65 exit(0); 72
73 while (transval == 0);
66} 74}
67 75
68void doreset() 76void getstatus()
69{ 77{
70 cmdbuf[0] = 0xFF; //reset 78 cmdbuf[0] = 0; //status
71 transval = 0; 79 transval = 0;
72 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 80 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
73 while(transval == 0) ; 81
82 while (transval == 0);
74} 83}
75 84
76void getstatus() 85void endproc()
77{ 86{
78 cmdbuf[0] = 0; //status 87 doreset();
79 transval = 0; 88 printf("Start pressed, exit\n");
80 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 89 VIDEO_WaitVSync();
81 while(transval == 0) ; 90 VIDEO_WaitVSync();
91 exit(0);
82} 92}
83 93
84u32 recv() 94u32 recv()
85{ 95{
86 memset(resbuf,0,32); 96 memset(resbuf,0,32);
87 cmdbuf[0]=0x14; //read 97 cmdbuf[0]=0x14; //read
88 transval = 0; 98 transval = 0;
89 SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,SI_TRANS_DELAY); 99 SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY);
90 while(transval == 0) ; 100
91 return *(vu32*)resbuf; 101 while (transval == 0);
102 printf("%08lx\n", *(vu32*)resbuf);
103 return *(vu32*)resbuf;
92} 104}
93 105
94void send(u32 msg) 106void send(u32 msg)
95{ 107{
96 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF; 108 cmdbuf[0] = 0x15;
97 cmdbuf[3]=(msg>>16)&0xFF;cmdbuf[4]=(msg>>24)&0xFF; 109 cmdbuf[1] = (msg >> 0) & 0xFF;
98 transval = 0; 110 cmdbuf[2] = (msg >> 8) & 0xFF;
99 resbuf[0] = 0; 111 cmdbuf[3] = (msg >> 16) & 0xFF;
100 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY); 112 cmdbuf[4] = (msg >> 24) & 0xFF;
101 while(transval == 0) ; 113
114 transval = 0;
115 resbuf[0] = 0;
116 SI_Transfer(1, cmdbuf, 5, resbuf, 1, transcb, SI_TRANS_DELAY);
117
118 while (transval == 0);
102} 119}
103 120
104void warnError(char *msg) 121void warnError(char *msg)
105{ 122{
106 puts(msg); 123 puts(msg);
107 VIDEO_WaitVSync(); 124 VIDEO_WaitVSync();
108 VIDEO_WaitVSync(); 125 VIDEO_WaitVSync();
109 sleep(2); 126 sleep(2);
110} 127}
128
111void fatalError(char *msg) 129void fatalError(char *msg)
112{ 130{
113 puts(msg); 131 puts(msg);
114 VIDEO_WaitVSync(); 132 VIDEO_WaitVSync();
115 VIDEO_WaitVSync(); 133 VIDEO_WaitVSync();
116 sleep(5); 134 sleep(5);
117 exit(0); 135 exit(0);
118} 136}
119 137
120u32 genKeyA() { 138u32 genKeyA()
139{
121 u32 retries = 0; 140 u32 retries = 0;
122 while (true) { 141
142 for (;;)
143 {
123 u32 key = 0; 144 u32 key = 0;
124 if (retries > 32) { 145
146 if (retries > 32)
147 {
125 key = 0xDD654321; 148 key = 0xDD654321;
126 } else { 149 } else {
127 key = (rand() & 0x00ffffff) | 0xDD000000; 150 key = (rand() & 0x00ffffff) | 0xDD000000;
128 } 151 }
152
129 u32 unk = (key % 2 != 0); 153 u32 unk = (key % 2 != 0);
130 u32 v12 = key; 154 u32 v12 = key;
131 for (u32 v13 = 1; v13 < 32; v13++) { 155 for (u32 v13 = 1; v13 < 32; v13++)
156 {
132 v12 >>= 1; 157 v12 >>= 1;
133 unk += (v12 % 2 != 0); 158 unk += (v12 % 2 != 0);
134 } 159 }
135 if ((unk >= 10 && unk <= 24)) { 160
136 if (retries > 4) printf("KeyA retries = %d",retries); 161 if ((unk >= 10 && unk <= 24))
137 printf("KeyA = 0x%08x\n",key); 162 {
163 if (retries > 4)
164 {
165 printf("KeyA retries = %ld", retries);
166 }
167
168 printf("KeyA = 0x%08lx\n", key);
169
138 return key; 170 return key;
139 } 171 }
172
140 retries++; 173 retries++;
141 } 174 }
142} 175}
143 176
144u32 checkKeyB(u32 KeyBRaw) { 177u32 checkKeyB(u32 KeyBRaw)
145 if ((KeyBRaw & 0xFF) != 0xEE) { 178{
146 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",((u8)(KeyBRaw))); 179 if ((KeyBRaw & 0xFF) != 0xEE)
180 {
181 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",
182 ((u8)(KeyBRaw)));
183
147 return 0; 184 return 0;
148 } 185 }
186
149 u32 KeyB = KeyBRaw & 0xffffff00; 187 u32 KeyB = KeyBRaw & 0xffffff00;
150 u32 val = KeyB; 188 u32 val = KeyB;
151 u32 unk = (val < 0); 189 u32 unk = (val < 0);
152 for (u32 i = 1; i < 24; i++) { 190 for (u32 i = 1; i < 24; i++)
191 {
153 val <<= 1; 192 val <<= 1;
154 unk += (val < 0); 193 unk += (val < 0);
155 } 194 }
156 if (unk > 14) { 195
157 printf("Invalid KeyB - high 24 bits bad: 0x%08x\n",KeyB); 196 if (unk > 14)
197 {
198 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n", KeyB);
199
158 return 0; 200 return 0;
159 } 201 }
160 printf("Valid KeyB: 0x%08x\n",KeyB); 202
203 printf("Valid KeyB: 0x%08lx\n", KeyB);
204
161 return KeyB; 205 return KeyB;
162} 206}
163 207
164u32 deriveKeyC(u32 keyCderive, u32 kcrc) { 208u32 deriveKeyC(u32 keyCderive, u32 kcrc)
209{
165 u32 keyc = 0; 210 u32 keyc = 0;
166 u32 keyCi = 0; 211 u32 keyCi = 0;
167 do { 212
213 do
214 {
168 u32 v5 = 0x1000000 * keyCi - 1; 215 u32 v5 = 0x1000000 * keyCi - 1;
169 u32 keyCattempt = docrc(kcrc,v5); 216 u32 keyCattempt = docrc(kcrc,v5);
170 //printf("i = %d; keyCderive = %08x; keyCattempt = %08x\n",keyCi,keyCderive,keyCattempt); 217
171 if (keyCderive == keyCattempt) { 218 if (keyCderive == keyCattempt)
219 {
172 keyc = v5; 220 keyc = v5;
173 printf("Found keyC: %08x\n",keyc); 221
222 printf("Found keyC: %08lx\n",keyc);
223
174 return keyc; 224 return keyc;
175 } 225 }
226
176 keyCi++; 227 keyCi++;
177 } while (keyCi < 256); 228 } while (keyCi < 256);
229
178 return keyc; 230 return keyc;
179} 231}
180 232
181int main(int argc, char *argv[]) 233u32 getMsg()
182{ 234{
183 void *xfb = NULL; 235 u32 val = 0;
184 GXRModeObj *rmode = NULL; 236 while (val == 0)
185 VIDEO_Init();
186 rmode = VIDEO_GetPreferredMode(NULL);
187 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
188 VIDEO_Configure(rmode);
189 VIDEO_SetNextFramebuffer(xfb);
190 VIDEO_SetBlack(FALSE);
191 VIDEO_Flush();
192 VIDEO_WaitVSync();
193 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
194 int x = 24, y = 32, w, h;
195 w = rmode->fbWidth - (32);
196 h = rmode->xfbHeight - (48);
197 CON_InitEx(rmode, x, y, w, h);
198 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
199 PAD_Init();
200 cmdbuf = memalign(32,32);
201 resbuf = memalign(32,32);
202 int i;
203 while(1)
204 { 237 {
205 printmain(); 238 val = __builtin_bswap32(recv());
206 printf("Waiting for a GBA in port 2...\n"); 239 sleep(1);
207 resval = 0; 240 }
241
242 send(0);
243 while (recv()!=0) {sleep(1);};
244 send(0);
245
246 return val;
247}
248
249int main(int argc, char *argv[])
250{
251 void *xfb = NULL;
252 GXRModeObj *rmode = NULL;
253 VIDEO_Init();
254 rmode = VIDEO_GetPreferredMode(NULL);
255 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
256 VIDEO_Configure(rmode);
257 VIDEO_SetNextFramebuffer(xfb);
258 VIDEO_SetBlack(FALSE);
259 VIDEO_Flush();
260 VIDEO_WaitVSync();
261 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
262 int x = 24, y = 32, w, h;
263 w = rmode->fbWidth - (32);
264 h = rmode->xfbHeight - (48);
265 CON_InitEx(rmode, x, y, w, h);
266 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
267 PAD_Init();
268 cmdbuf = memalign(32,32);
269 resbuf = memalign(32,32);
208 270
209 SI_GetTypeAsync(1,acb); 271 for (;;)
210 while(1) 272 {
273 printmain();
274
275 printf("Press A to begin, press Start to quit.\n");
276 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START)
211 { 277 {
212 if(resval) 278 endproc();
213 {
214 if(resval == 0x80 || resval & 8)
215 {
216 resval = 0;
217 SI_GetTypeAsync(1,acb);
218 }
219 else if(resval)
220 break;
221 }
222 PAD_ScanPads();
223 VIDEO_WaitVSync();
224 if(PAD_ButtonsDown(0) & PAD_BUTTON_START)
225 endproc();
226 } 279 }
227 if (resval & SI_GBA) 280
228 { 281 printf("Waiting for a GBA in port 2...\n");
229 printf("GBA Found! Waiting on BIOS\n"); 282 resval = 0;
283
284 SI_GetTypeAsync(1,acb);
285 while(1)
286 {
287 if (resval)
288 {
289 if (resval == 0x80 || resval & 8)
290 {
291 resval = 0;
292 SI_GetTypeAsync(1,acb);
293 } else if (resval)
294 {
295 break;
296 }
297 }
298
299 PAD_ScanPads();
300 VIDEO_WaitVSync();
301 if (PAD_ButtonsHeld(0) & PAD_BUTTON_START)
302 {
303 getstatus();
304 endproc();
305 }
306 }
307
308 if (resval & SI_GBA)
309 {
310 printf("GBA Found! Waiting on BIOS\n");
311
230 resbuf[2]=0; 312 resbuf[2]=0;
231 u32 oldresult = 0; 313
232 u32 newresult = 0;
233 // wait for the BIOS to hand over to the game 314 // wait for the BIOS to hand over to the game
234 do { 315 do
316 {
235 doreset(); 317 doreset();
236 } while (!(resbuf[1] > 4)); 318 } while (!(resbuf[1] > 4));
319
237 printf("BIOS handed over to game, waiting on game\n"); 320 printf("BIOS handed over to game, waiting on game\n");
321
238 do 322 do
239 { 323 {
240 doreset(); 324 doreset();
241 } while((resbuf[0] != 0) || !(resbuf[2]&0x10)); 325 } while ((resbuf[0] != 0) || !(resbuf[2] & 0x10));
326
242 // receive the game-code from GBA side. 327 // receive the game-code from GBA side.
243 u32 gamecode = recv(); 328 u32 gamecode = recv();
329
244 printf("Ready, sending multiboot ROM\n"); 330 printf("Ready, sending multiboot ROM\n");
331
245 unsigned int sendsize = ((gba_mb_gba_size+7)&~7); 332 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
333
246 // generate KeyA 334 // generate KeyA
247 unsigned int ourkey = genKeyA(); 335 unsigned int ourkey = genKeyA();
336
248 //printf("Our Key: %08x\n", ourkey); 337 //printf("Our Key: %08x\n", ourkey);
249 printf("Sending game code that we got: 0x%08x\n",__builtin_bswap32(gamecode)); 338 printf("Sending game code that we got: 0x%08lx\n",
339 __builtin_bswap32(gamecode));
340
250 // send the game code back, then KeyA. 341 // send the game code back, then KeyA.
251 send(__builtin_bswap32(gamecode)); 342 send(__builtin_bswap32(gamecode));
252 send(ourkey); 343 send(ourkey);
253 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA to derive the initial CRC value and the sessionkey. 344
345 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA
346 // to derive the initial CRC value and the sessionkey.
254 u32 sessionkeyraw = 0; 347 u32 sessionkeyraw = 0;
255 do { 348 do
349 {
256 sessionkeyraw = recv(); 350 sessionkeyraw = recv();
257 } while (sessionkeyraw == gamecode); 351 } while (sessionkeyraw == gamecode);
352
258 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw)); 353 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
354 if (sessionkeyraw == 0)
355 {
356 warnError("Cannot continue.\n");
357
358 continue;
359 }
360
259 u32 sessionkey = sessionkeyraw ^ ourkey; 361 u32 sessionkey = sessionkeyraw ^ ourkey;
260 u32 kcrc = sessionkey; 362 u32 kcrc = sessionkey;
261 printf("start kCRC=%08x\n",kcrc); 363 printf("start kCRC=%08lx\n",kcrc);
364
262 sessionkey = (sessionkey*0x6177614b)+1; 365 sessionkey = (sessionkey*0x6177614b)+1;
366
263 // send hacked up send-size in uint32s 367 // send hacked up send-size in uint32s
264 u32 hackedupsize = (sendsize >> 3) - 1; 368 u32 hackedupsize = (sendsize >> 3) - 1;
265 printf("Sending hacked up size 0x%08x\n",hackedupsize); 369
370 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
266 send(hackedupsize); 371 send(hackedupsize);
372
267 //unsigned int fcrc = 0x00bb; 373 //unsigned int fcrc = 0x00bb;
268 // send over multiboot binary header, in the clear until the end of the nintendo logo. 374 // send over multiboot binary header, in the clear until the end of the
269 // GBA checks this, if nintendo logo does not match the one in currently inserted cart's ROM, it will not accept any more data. 375 // nintendo logo. GBA checks this, if nintendo logo does not match the
270 for(i = 0; i < 0xA0; i+=4) { 376 // one in currently inserted cart's ROM, it will not accept any more data.
377 for (int i = 0; i < 0xA0; i+=4)
378 {
271 vu32 rom_dword = *(vu32*)(gba_mb_gba+i); 379 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
272 send(__builtin_bswap32(rom_dword)); 380 send(__builtin_bswap32(rom_dword));
273 } 381 }
382
274 printf("\n"); 383 printf("\n");
275 printf("Header done! Sending ROM...\n"); 384 printf("Header done! Sending ROM...\n");
276 // 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. 385
277 for(i = 0xA0; i < sendsize; i+=4) 386 // Add each uint32 of the multiboot image to the checksum, encrypt the
387 // uint32 with the session key, increment the session key, send the
388 // encrypted uint32.
389 for (int i = 0xA0; i < sendsize; i+=4)
278 { 390 {
279 u32 dec = ( 391 u32 dec = (
280 ((gba_mb_gba[i+3]) << 24) & 0xff000000 | 392 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
281 ((gba_mb_gba[i+2]) << 16) & 0x00ff0000 | 393 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
282 ((gba_mb_gba[i+1]) << 8) & 0x0000ff00 | 394 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
283 ((gba_mb_gba[i]) << 0) & 0x000000ff 395 (((gba_mb_gba[i]) << 0) & 0x000000ff)
284 ); 396 );
397
285 u32 enc = (dec - kcrc) ^ sessionkey; 398 u32 enc = (dec - kcrc) ^ sessionkey;
286 kcrc=docrc(kcrc,dec); 399 kcrc = docrc(kcrc,dec);
287 sessionkey = (sessionkey*0x6177614B)+1; 400 sessionkey = (sessionkey * 0x6177614B) + 1;
288 //enc^=((~(i+(0x20<<20)))+1); 401 //enc^=((~(i+(0x20<<20)))+1);
289 //enc^=0x6f646573;//0x20796220; 402 //enc^=0x6f646573;//0x20796220;
403
290 send(enc); 404 send(enc);
291 } 405 }
406
292 //fcrc |= (sendsize<<16); 407 //fcrc |= (sendsize<<16);
293 printf("ROM done! CRC: %08x\n", kcrc); 408 printf("ROM done! CRC: %08lx\n", kcrc);
294 //get crc back (unused) 409 //get crc back (unused)
410
295 // Get KeyC derivation material from GBA (eventually) 411 // Get KeyC derivation material from GBA (eventually)
296 u32 keyCderive = 0; 412 u32 keyCderive = 0;
297 do { 413 do
414 {
298 keyCderive = recv(); 415 keyCderive = recv();
299 } while (keyCderive <= 0xfeffffff); 416 } while (keyCderive <= 0xfeffffff);
417
300 keyCderive = __builtin_bswap32(keyCderive); 418 keyCderive = __builtin_bswap32(keyCderive);
301 keyCderive >>= 8; 419 keyCderive >>= 8;
302 printf("KeyC derivation material: %08x\n",keyCderive); 420
303 421 printf("KeyC derivation material: %08lx\n",keyCderive);
304 // (try to) find the KeyC, using the checksum of the multiboot image, and the derivation material that GBA sent to us 422
305 423 // (try to) find the KeyC, using the checksum of the multiboot image, and
424 // the derivation material that GBA sent to us
306 u32 keyc = deriveKeyC(keyCderive,kcrc); 425 u32 keyc = deriveKeyC(keyCderive,kcrc);
307 if (keyc == 0) printf("Could not find keyC - kcrc=0x%08x\n",kcrc); 426 if (keyc == 0)
308 427 {
309 // 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. 428 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
429 warnError("Cannot continue.\n");
430
431 continue;
432 }
433
434 // derive the boot key from the found KeyC, and send to GBA. if this is
435 // not correct, GBA will not jump to the multiboot image it was sent.
310 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000; 436 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
311 printf("BootKey = 0x%08x\n",bootkey); 437 printf("BootKey = 0x%08lx\n",bootkey);
438
312 send(bootkey); 439 send(bootkey);
313 440 sleep(2);
314 printf("Done! Press any key to start sending again.\n"); 441
315 do { PAD_ScanPads(); } while (!PAD_ButtonsDown(0)); 442 printf("Waiting for GBA...\n");
316 } 443 while (recv() != 0) {sleep(1);};
317 } 444 send(0);
318 return 0; 445
446 VIDEO_WaitVSync();
447
448 // Get game
449 // -1 - unsupported game
450 // 1 - Ruby
451 // 2 - Sapphire
452 // 3 - FireRed
453 // 4 - LeafGreen
454 // 5 - Emerald
455 u32 gameId = getMsg();
456 if (gameId == -1)
457 {
458 warnError("ERROR: Unsupported GBA game inserted!\n");
459
460 continue;
461 }
462
463 printf("\nPokemon ");
464 switch (gameId)
465 {
466 case 1: printf("Ruby"); break;
467 case 2: printf("Sapphire"); break;
468 case 3: printf("FireRed"); break;
469 case 4: printf("LeafGreen"); break;
470 case 5: printf("Emerald"); break;
471 }
472
473 printf("\n");
474 VIDEO_WaitVSync();
475
476 u32 isValid = getMsg();
477 if (isValid == -1)
478 {
479 warnError("ERROR: Unsupported game version inserted!\n");
480
481 continue;
482 }
483
484 // Get trainer name
485 u8 trainerName[8];
486
487 u32 tnd = getMsg();
488 trainerName[0] = (tnd & 0xFF000000) >> 24;
489 trainerName[1] = (tnd & 0x00FF0000) >> 16;
490 trainerName[2] = (tnd & 0x0000FF00) >> 8;
491 trainerName[3] = (tnd & 0x000000FF);
492
493 tnd = getMsg();
494 trainerName[4] = (tnd & 0xFF000000) >> 24;
495 trainerName[5] = (tnd & 0x00FF0000) >> 16;
496 trainerName[6] = (tnd & 0x0000FF00) >> 8;
497 trainerName[7] = (tnd & 0x000000FF);
498
499 // Get trainer ID
500 u32 trainerId = getMsg();
501
502 printf("Trainer: ");
503
504 for (int i = 0; i < 8; i++)
505 {
506 if (trainerName[i] == 0xFF)
507 {
508 break;
509 } else {
510 printf("%c", debugGen3Decode(trainerName[i]));
511 }
512 }
513
514 printf(" (%ld)\n", trainerId);
515
516 // Wait for confirmation.
517 printf("Press A to import the data from this game.\n");
518 printf("Press B to cancel.\n");
519 VIDEO_WaitVSync();
520
521 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B)
522 {
523 continue;
524 }
525 }
526 }
527
528 return 0;
319} 529}