BlackShark Posted June 17, 2018 Posted June 17, 2018 Does anyone know how the save files of the first Pokemon Ranger game are encrypted? Or at least if there is any kind of encryption that has been commonly used for other NDS games which might have been used for Pokemon Ranger as well? Shadows of Almia and Guardian Signs are not encrypted and I don't know any other NDS Pokemon game that has a fully encrypted save file. Any idea about this matter would be appreciated, thanks.
theSLAYER Posted September 28, 2018 Posted September 28, 2018 12 minutes ago, BlackShark said: Nobody got an idea? I've got no clue. Are they even encrypted? (I assume that you determined that with before and after saves? )
Guest Posted September 28, 2018 Posted September 28, 2018 (edited) The thing is we have a Japanese save file with all 3 DLC packages WMission (Deoxys Mission & Manaphy Mission), Celebi Mission & Mew Mission. Thanks to this website just btw: https://ux.getuploader.com/savedate/download/226. The Mew Mission was extreme rare and I have been looking for it for quite a while. (Years!) It was distributed in partnership with ANA and you were only able to get it on respective airport terminals for the most part. Now the save file with all missions got finally leaked this year so we are damn lucky! The problem is the missions are already played and we would like to have a blank save file with the untouched special missions. One idea from my side would be to maybe edit everything from memory and then save the game. It's complicated too though and regardless of which way we go some research might be required, to learn what activated the missions ect... since there was no option to delete the save file but a new game option, I kinda wonder how fresh a newly started game is? At least the missions won't be removed from what I remember? Edited September 28, 2018 by ajxpk
Guest Posted March 8, 2021 Posted March 8, 2021 (edited) Meanwhile I did some reverse engineering and I found the encryption/decryption algorithm, it's this function... unsigned int __fastcall PokemonRangerCrypt(int a1, unsigned int s_rand, int size, _DWORD *dest) { unsigned int i; // r5 unsigned int result; // r0 unsigned int rand; // ST04_4 unsigned int h_rand; // r0 for(i = 0; i < size/4;) { rand = 1566083941 * s_rand; // the initial seed is located before the decrypted/encrypted data h_rand = rand; s_rand = 1566083941 * rand; *dest ^= h_rand & 0xFFFF0000 | (s_rand >> 16); ++dest; // this increments by 4 (u32 data) ++i; } return result; } The initial seed for this comes right before the encrypted data itself... for example, the first two chunks include a header with the string "PKR-059 a00 ". Right after that (loc 0xC) there is the initial seed which becomes the first "s_rand" value, the encrypted data follows (at loc 0x10). The encrypted chunk size for the first chunk is 496 bytes, the 2nd chunk starts at location 0x200, size of this chunk is still unknown. We can't just loop through this thing from start to end and have to figure out where each chunk starts and hopefully their seeds are stored there as well, but I think this should be easy from here now and tests should reveal that... It's still unknown how the initial seed was originally calculated... (could be a checksum?). At least the two first chunks are sharing the same seed. It looks like there could be different initial seeds for other chunks, so if something doesn't decrypt properly watch out. Edited March 13, 2021 by ajxpk
BlackShark Posted March 8, 2021 Author Posted March 8, 2021 @ajxpk nice work! Thank you very much! Spoiler I was able to figure out the offsets of the other chunks/seeds. Seed Start Length 0x00C 0x010 0x1F0 0x20C 0x210 0x1F0 0x400 0x404 0x2620 0x2B00 0x2B04 0x2620 0x5200 0x5204 0x30E8 0x8300 0x8304 0x30E8 0xB400 0xB404 0x30E8 0xE500 0xE504 0x30E8 0x11600 0x11604 0xE7FC 0x1FE00 0x1FE04 0x67FC 0x26600 0x26604 0x4FFC 0x2B600 0x2B604 0x57FC The checksum of a chunk is a simple CRC16 right after the seed (first 4 bytes of the encrypted data). Ok, forget what I wrote previously. Only the first two chunks are static they contain the information about the other chunks. Save Info Chunk (512 bytes) 0x000-0x00B PKR-059 a00 0x00C seed 0x010 CRC16 over the next 492 bytes 0x014 time stamp 0x018 time stamp (see https://projectpokemon.org/home/forums/topic/45846-pokemon-ranger-save-file-encryption/?tab=comments#comment-265265) 0x01C always 0x000000A0 0x020-0x1FF chunk info entries Chunk Info Entry (48 bytes) 0x00 file name 0x1E number of copies 0x20 offset 0x24 data size 0x28 reserved space Each of the other chunks has a 24 byte header. Chunk 0x00 seed 0x04 CRC16 over the chunk data starting at 0x18 0x08 unknown 0x0C unknown 0x10 save counter 0x14 always 0x00000001 0x18-0x?? chunk data A small tool to decrypt/encrypt and fix checksums for Ranger saves (use with caution!): https://github.com/Bl4ckSh4rk/rangercrypt/releases/latest 1
Guest Posted March 9, 2021 Posted March 9, 2021 (edited) Good work! Now I finally understand why there were 3 functions for decryption. One was for the first two chunks with the save info, the second is a hardcoded decryption function with a * 5 loop to decrypt the first 20 bytes of a chunk, (I guess just for save file checks) and the third one for the rest of the non-static chunks. This is the directory list struct based on my understanding. (Updated! @BlackShark Sorry for the confusion, I think I mixed the numbers up a little, the struct with the save info is complete now...) Savedata List 0x00 File name (28 chars) 0x1C Unknown (u16) 0x1E Mirror (u16) 0x20 Address (u32) 0x24 Data Size (u32) 0x28 Sector Size (u32) 0x2C Unknown (u32) file name type data size sector size siskin.tsd 2 0x260C 0x4E00 wren.tsd 2 0x30D4 0x6200 hazel.tsd 2 0x30D4 0x6200 set_delivery001.dat 1 0xE7E8 0xE800 set_delivery003.dat 1 0x67E8 0x6800 set_delivery002.dat 1 0x57E8 0x5800 set_delivery004.dat 1 0x4FE8 0x5000 The most interesting one is siskin.tsd, which starts with the setting data, it also includes the ranger id (offset 0x10) and data related to the special missions, like the "new mission" flag (offset 0xA) and manaphy egg information at offset 0x8 (not received yet/received/sent) and the time info when it was obtained year/month/day (starts at offset 0xC). There's also the title and desciption strings, wren.tsd apparently includes player info... the name is at offset 0xE for example. Last but not least, hazel.tsd is used for quick save/save states... And then we have the Special Mission .dat files... the international versions have those localized included in the directory data\mission. Edit: I extracted the special mission .dat files and attached them to this post In addition I attached a thingy table which I made in case you want to look for strings. Pokemon Ranger Special Missions (JP).zip Pokemon Ranger Character Encoding (JP).tbl I still don't know how we can utilize the .dat files at this point... they seem to include all the data that is needed for the missions, including the title and description, but just using them with a ZP3J cartridge doesn't seem to work, I still get this screen when I boot the game with it... I will have to find out in what kind of form it wants to receive the data. I already located the functions (in version 1.1), the Ranger Net jump table function for Slot-2 is in overlay_0009.bin (loc 0x020FC628), there's the call to a familiar function that gets the cartridge data at 0x0209A558 (it's almost identical to the one in Diamond & Pearl ect.). It seems everything is ok, At least it gets the size information from 0x8100000 and the data starting from 0x8100010. Just for some reasons it returns false when the data is checked. Maybe because of failed validation checks. Now if I force it to return true I get this btw... I found some pictures online related to the download process... Source: https://www.inside-games.jp/article/2006/08/12/18877.html Edited September 4, 2022 by ajxpk
BlackShark Posted March 9, 2021 Author Posted March 9, 2021 2 hours ago, ajxpk said: I attached the extracted .dat files. Still don't know how we can utilize them... In addition I attached a thingy table I made in case you want to look for strings. With a modified siskin.tsd the missions will show up ingame. Idk where the data comes from, it probably gets written there during the download process. Now I need to find a save file that doesn't have any missions yet to test if the injected misiions are properly playable. Pokemon Ranger (JP).sav
Guest Posted March 9, 2021 Posted March 9, 2021 (edited) Recently I found out that when you do something like writing on these encrypted save file chunks the game will delete them. When you for example overwrite the encrypted "PKR-059 a00 " save block (or its seed) it erases the whole save file. And that's for example how you can delete the save game but still keep the special missions... I think the same will also work vice versa, so you can just destroy the data/do anything that the sum check fails. The field at offset 0x1C is a u32 value and always 0xA, it's set when the game creates the header. Can be used to check whether a save file is already decrypted/encrypted. Also... Offset 0x10 of these other save file headers could be some kind of save count. Looks like the 2nd is really a backup save, its chunk is created when you save for the 2nd time (before that it only has these blocks only have the save file header). Edit: Meanwhile I located the functions for checking the agb ("beacon") & mission data. The first 128 bytes starting from offset 0x08100010 is an array which is swapped for some kind of cryptostuff which reminds me on RC4, but tbh I don't know much about this and it looks tough to reverse engineer so I think I will leave it there. If I understand it correctly it's in fact very similar to what I've seen in the localized versions of Diamond & Pearl etc. where it does a signature verification with 128 bytes from 0x08020000, it looks almost identical (just the key is different from what I've seen). In addition there are SHA1 checks for the mission data starting at offset 0x08100090, apparently the total size checked is the size of the full data -191 bytes. I didn't even go further (it's possible that the data is compressed), this whole thing is more complicated than I thought, a lot research would be necessary to make it work... If someone is interested in it... the initiate BL to the subroutines for the SHA1 and the cryptostuff is at offset 0x020B0284. The function that makes the .dat save file block and updates the main save (PKR) is at 0x02001D80. I think the best approach would be to figure out how saving works in detail, which would have to be done either way as we need to know more about these other values from the header... Edit 2: Btw. Meanwhile I know where the Special Mission data struct from siskin.tsd is coming from, they were installed from the .dat files... This also exists in the localized versions, the data is for accessing the missions via Ranger Net. The D00X struct is always 100 bytes copied straight from the .dat or maybe it's coming from another payload, we might never know unless someone wants to give it a try and reserve engineer it. Missions are sorted by their IDs, regardless in which order they were downloaded. The data includes information like mission ID, lengths (u16) for description and client name and strings for title, description and the name of the client. set_delivery001.dat Mission: D001 (0x50D0) Description offset: 16 chars Client name offset: 97 chars Title: "だいじなタマゴを とりもどせ!" (0xD490) Description: "シンバラきょうじゅが てにいれた マナフィの タマゴを ゴーゴーだんに うばわれてしまった! かれらに あくようされる まえに だいじな タマゴを とりもどせ!" (0xD4B0) Client: "シンバラ" (0xD554) set_delivery003.dat Mission: D002 (0x1D10) Description offset: 16 chars Client name offset: 111 chars Title: "デオキシスと わかりあえるか?" (0x5874) Description: "なんらかの りゆうで こうげきてきに なった デオキシスが はっけんされた。 まわりの ポケモンや にんげんに ひがいが でるまえに デオキシスを せいじょうな じょうたいに もどすのだ!" (0x5894) Client: "ハヤテ" (0x5954) set_delivery002.dat Mission: D003 (0x1BC0) Description offset: 13 chars Client name offset: 107 chars Title: "セレビィを すくいだせ!" (0x43A4) Description: "ライラのもりに あらわれた セレビィを ゴーゴーだんの れんちゅうが ねらっているという じょうほうが ある。 セレビィを ぶじに ほごするために かれらよりも さきに キャプチャせよ!" (0x43C0) Client name: "ハヤテ" (0x447C) set_delivery004.dat Mission: D004 (0x1520) Description offset: 15 chars Client name offset: 115 chars Title: "まぼろしのミュウを さがせ!" (0x397C) Description: "まぼろしのポケモンと いわれている ミュウが ジャングルで もくげきされた。 シンバラきょうじゅの けんきゅうの ため ひとりの レンジャーの めいよの ため ぜひ ミュウを キャプチャしてほしい!" (0x399C) Client name: "シンバラ" (0x3A64) Edited August 8, 2022 by ajxpk
Guest Posted March 12, 2021 Posted March 12, 2021 (edited) It turns out that the PKR-059 a00's header fields at offset 0x14 and 0x18 are time stamps representing minute, second, hour (u32) and year, month, day (u16). The .tsd and .dat save headers have their time stamps too at field offset 0x8 (minute, second, hour) & 0xC (year, month, day). date(u16) format = year, month, day time(u32) format = minute, second, hour PKR-059 a00 date = Previous date from header offset 0x18 (default value = 0xFFFF) time = Previous time from header offset 0x14 (default value = 0xFFFFFFFF) .tsd & .dat Whatever is currently on the stack (gets XORed all the time from what I've seen so far) *date = *date & 0xFF80 | year & 0x7F; *date = *date & 0xF87F | ((month & 0xF) << 7); *date = *date & 0x7FF | ((day & 0x1F) << 11); *time = *time & 0xFFE0FFFF | ((hour & 0x1F) << 16); *time = *time & 0xFFFFFFC0 | minute & 0x3F; *time = *time & 0xFFFFF03F | ((second & 0x3F) << 6); Field at 0x1A (u16) (PKR-059 a00 ) is a count. It's defaults at 0 in increments when the file is created and each time the file is overwritten until it maxes out at 0xFFFF (it doesn't overflow). With siskin.tsd, wren.tsd, hazel.tsd, set_delivery001.dat, set_delivery003.dat, set_delivery002.dat & set_delivery004.dat set it reaches 8 and will never be updated from here. Field 0x1C is always 10, the value is used as the maximum of files that can be saved and to calculate the reserved space (0xA * 0x30 + 0x20 = 0x200). .tsd & .dat files have a save count too at 0x10 (u32), which serves to select the current mirror, the top .tsd file being saved first takes the odd and the 2nd takes the even numbers. It maxes out at 0xFFFFFFFF without overflowing, there is an additional count for the block at 0xE (u32), which increments with each time the block is saved. It maxes out at 0xFFFF (again, no overflow). Field 0x14 in .tsd & .dat is used for enabling/disabling a save block, mainly used for the backup where the first time these save files are created an empty disabled backup block is created. Hazel.tsd (used for save states) makes use of this commonly as save states are deleted when they're used. PKR Main Save File header Adrs Description Type 0x00 "PKR-059 " str 0x07 "a00 " str 0x0C Seed u32 0x10 CRC16 u32 0x14 Time u32 0x18 Date u16 0x1A Count u16 0x1C Save Data Table Max u16 0x1E Unknown u16 Save Data header (.tsd & .dat) Adrs Description Type 0x00 Seed u32 0x04 CRC16 u32 0x08 Time u32 0x0C Date u16 0x0E Block Count u16 0x10 Global Count u32 0x14 Enable Flag u16 0x16 Unknown u16 Btw. the seeds for the encryption is created by via timer 0 (REG_TM0D) + a counter of its overflow (REG_TM0CNT = TIMER_ON | TM_IRQ | TM_FREQ_64). (REG_TM0D | (TM_IRQ_count << 16)) + 1 Edited February 8, 2022 by ajxpk
NickPlayeZ Posted August 7, 2021 Posted August 7, 2021 On 3/8/2021 at 10:15 PM, BlackShark said: A small tool to decrypt/encrypt and fix checksums for Ranger saves (use with caution!): https://github.com/Bl4ckSh4rk/rangercrypt/releases/latest Hey there so I was just trying to use this but when I drag my (german) ranger save onto it (open the save with that) it just quickly opens the command thingy and immediately closes it again without having any effect from what I can tell... I'm not really familiar with programming or anything like that; do you know what I might be doing wrong? 1 hour ago, NickPlayeZ said: Hey there so I was just trying to use this but when I drag my (german) ranger save onto it (open the save with that) it just quickly opens the command thingy and immediately closes it again without having any effect from what I can tell... I'm not really familiar with programming or anything like that; do you know what I might be doing wrong? all good now for some reason worked after trying it 3 more times? Weird but alright Another Question though: whenever I decrypt, then change some stuff and try to encrypt it again it wont work (even if I revert any changes I made back). Why could that be?
Wokann Posted 4 hours ago Posted 4 hours ago (edited) I have to say, AI has become incredibly powerful when it comes to program analysis. With GPT's help, I've managed to figure out the structure of ranger1jp's Slot 2 distribution ROM. This is how the Slot 2 structure is organized: Spoiler #ifndef RANGER_SLOT2_FORMAT_H #define RANGER_SLOT2_FORMAT_H #include <stddef.h> #include <stdint.h> /* * Pokemon Ranger 1 (ARGJ) Slot-2 ROM layout. * ROM offset X is mapped at NDS address 0x08000000 + X. * Multi-byte integers in the container are little-endian. */ /* GBA header: game_code is four ASCII bytes at ROM 0xAC, without a NUL. */ #define RANGER_GAME_CODE_OFFSET 0x000000ACu #define RANGER_GAME_CODE_SIZE 4u #define RANGER_DEFAULT_GAME_CODE "ZP3J" #define RANGER_MAKER_CODE "01" #define RANGER_GBA_FIXED_VALUE 0x96u /* * ARGJ accepts all ten codes below. ZP3J is only the build default. * A valid GBA header using any other game code is not a Ranger beacon. */ #define RANGER_ALLOWED_GAME_CODES(X) \ X("ZP3J") X("ZP4J") X("ZP5J") X("ZP6J") X("ZP7J") \ X("ZR3J") X("ZR4J") X("ZR5J") X("ZR6J") X("ZR7J") /* Ranger payload positions in the GBA ROM. */ #define RANGER_META_OFFSET 0x00100000u #define RANGER_SIGNED_PAYLOAD_OFFSET 0x00100010u #define RANGER_RSA_SIGNATURE_SIZE 0x80u #define RANGER_CONTAINER_OFFSET 0x00100090u #define RANGER_CONTAINER_RECORD_SIZE 0x28u #define RANGER_CONTAINER_NAME_SIZE 0x24u #pragma pack(push, 1) typedef struct RangerGbaHeader { /*0x000*/ uint8_t entry_and_logo[0xA0]; /*0x0A0*/ char title[12]; /*0x0AC*/ char game_code[4]; /* one of RANGER_ALLOWED_GAME_CODES */ /*0x0B0*/ char maker_code[2]; /*0x0B2*/ uint8_t fixed_value; /* 0x96 */ /*0x0B3*/ uint8_t unit_code; /*0x0B4*/ uint8_t device_type; /*0x0B5*/ uint8_t reserved_b5_bb[7]; /*0x0BC*/ uint8_t software_version; /*0x0BD*/ uint8_t header_complement; /*0x0BE*/ uint8_t reserved_be_bf[2]; } RangerGbaHeader; /* ROM 0x100000: payload_size includes the 0x80-byte signature and container. */ typedef struct RangerSlot2Meta { /*0x00*/ uint32_t payload_size; /*0x04*/ uint8_t reserved[0x0C]; } RangerSlot2Meta; /* * All container entries use the same physical 0x28-byte layout: * record[0] offset -> display-title glyph codes; name[] unused. * record[1..] offset -> mission body; name[] is set_delivery00X.dat. * final offset == 0; terminates the table. * Offsets are relative to the container at ROM 0x100090. */ typedef struct RangerContainerRawRecord { /*0x00*/ uint32_t data_offset; /*0x04*/ uint8_t raw_name[RANGER_CONTAINER_NAME_SIZE]; } RangerContainerRawRecord; typedef struct RangerContainerTitleRecord { /*0x00*/ uint32_t title_offset; /*0x04*/ uint8_t reserved[RANGER_CONTAINER_NAME_SIZE]; } RangerContainerTitleRecord; typedef struct RangerContainerFileRecord { /*0x00*/ uint32_t file_offset; /*0x04*/ char save_filename[RANGER_CONTAINER_NAME_SIZE]; } RangerContainerFileRecord; typedef struct RangerContainerEndRecord { /*0x00*/ uint32_t zero_offset; /*0x04*/ uint8_t reserved[RANGER_CONTAINER_NAME_SIZE]; } RangerContainerEndRecord; /* One physical 0x28-byte slot, interpreted according to its table position. */ typedef union RangerContainerRecord { RangerContainerRawRecord raw; RangerContainerTitleRecord title; /* records[0] */ RangerContainerFileRecord file; /* records[1..N] */ RangerContainerEndRecord end; /* records[N+1], zero_offset == 0 */ } RangerContainerRecord; /* * Variable-sized container beginning at ROM 0x100090. * records[1] expresses the first record only. Physically it is followed by * more records through the zero-offset terminator, then title and DLC bodies. */ typedef struct RangerContainer { /*0x00*/ RangerContainerRecord records[1]; /* dynamic: more records, title glyphs, then every mission body */ } RangerContainer; /* * RSA/SHA-1 rules for both single- and multi-DLC packages: * * payload_size = RANGER_RSA_SIGNATURE_SIZE + container_size * container_size = payload_size - RANGER_RSA_SIGNATURE_SIZE * digest = SHA1(container[0 .. container_size)) * rsa_signature = RSA-1024 PKCS#1 v1.5 signature of that SHA-1 digest * * A multi-DLC package does NOT contain one RSA signature per mission. Its one * continuous container contains the title record, every DLC file record, the * end record, title glyph data, and every DLC body. One signature at ROM * 0x100010 authenticates that complete container. Adding, removing, swapping, * renaming, or changing any DLC therefore changes the digest and requires one * new signature for the rebuilt whole container. * * The signature bytes themselves and RangerSlot2Meta are outside the SHA-1 * input. With no private key, rsa_signature stays zero and the NDS-side RSA * result bypass is required; container parsing and save checks still run. */ typedef struct RangerSignedPayload { /*0x00*/ uint8_t rsa_signature[RANGER_RSA_SIGNATURE_SIZE]; /*0x80*/ RangerContainer container; } RangerSignedPayload; /* * Complete nesting: * RangerSlot2Rom * +- gba_program[] ROM 0x000000..0x0FFFFF * +- meta ROM 0x100000..0x10000F * `- signed_payload ROM 0x100010.. * +- rsa_signature[0x80] ROM 0x100010..0x10008F * `- container ROM 0x100090.. * +- records[] title, each DLC, terminator * `- data[] title glyphs and all DLC bodies */ typedef struct RangerSlot2Rom { /*0x000000*/ uint8_t gba_program[RANGER_META_OFFSET]; /*0x100000*/ RangerSlot2Meta meta; /*0x100010*/ RangerSignedPayload signed_payload; } RangerSlot2Rom; #pragma pack(pop) _Static_assert(sizeof(RangerGbaHeader) == 0xC0, "GBA header size"); _Static_assert(offsetof(RangerGbaHeader, game_code) == RANGER_GAME_CODE_OFFSET, "GBA game code offset"); _Static_assert(sizeof(RangerSlot2Meta) == 0x10, "metadata size"); _Static_assert(sizeof(RangerContainerRecord) == RANGER_CONTAINER_RECORD_SIZE, "container record size"); _Static_assert(sizeof(RangerContainerTitleRecord) == RANGER_CONTAINER_RECORD_SIZE, "title record size"); _Static_assert(sizeof(RangerContainerFileRecord) == RANGER_CONTAINER_RECORD_SIZE, "file record size"); _Static_assert(sizeof(RangerContainerEndRecord) == RANGER_CONTAINER_RECORD_SIZE, "end record size"); _Static_assert(offsetof(RangerSignedPayload, container) == RANGER_RSA_SIGNATURE_SIZE, "container offset within signed payload"); _Static_assert(offsetof(RangerSlot2Rom, meta) == RANGER_META_OFFSET, "metadata offset"); _Static_assert(offsetof(RangerSlot2Rom, signed_payload) == RANGER_SIGNED_PAYLOAD_OFFSET, "signature offset"); _Static_assert(offsetof(RangerSlot2Rom, signed_payload.container) == RANGER_CONTAINER_OFFSET, "container offset"); #endif I also had it use this structure together with the existing distribution data to generate ROMs that can actually be run. See the attached file for details. Here are some screenshots of the program running. D001: Spoiler If player has already received mission, it will show note: And here are other mission D002: D003: D004: However, there is one important thing to note: Slot 2 requires RSA verification. Without the official private key, it cannot be used directly. If used directly with the original ROM, the game will get stuck on the loading screen, as shown below. So for now I’ll provide two ways to bypass the verification. 1. Modify the ROM: revision | rom_address ARGJ v1.0 | 0x125368 ARGJ v1.1 | 0x125F68 change 32 D0 to FF D0 2. Cheat-code method: It can be used for both emulator or retail cartirdges. When used together with nds homebrew NitroHax, this method can also be used with an original retail cartridge. I’ll also include the corresponding cheats.xml file in the attachments. ARGJ revision 1.0 Game ID: ARGJ 137BF043 520FBB28 A802D032 120FBB28 0000D0FF ARGJ revision 1.1 Game ID: ARGJ D1359FD4 520FC6A8 A802D032 120FC6A8 0000D0FF In addition, based on analysis of the internal program logic, the Slot 2 ROM supports loading multiple DLC packages at the same time, with a maximum of three. The game will only display the title for the first DLC; the titles of the subsequent ones will not be shown, and they will all be downloaded silently in sequence. I’ve also attached a sample ROM containing D001, D002, and D003 for reference. ranger_slot2_D001.gba ranger_slot2_D002.gba ranger_slot2_D003.gba ranger_slot2_D004.gba cheats.xml ranger_slot2_D1-D2-D3.gba Edited 4 hours ago by Wokann
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now