LumaTeam / Luma3DS

Nintendo 3DS "Custom Firmware"
GNU General Public License v3.0
5.18k stars 556 forks source link

Setting NoCrypto NCCH flag causes ROMs to fail to load #1827

Open Popax21 opened 1 year ago

Popax21 commented 1 year ago

Recently, I've been toying around with getting a console running Luma3DS to play custom CCI / .3ds cartridge ROMs using a Sky3DS+ flash cart (mostly just for the fun of it). I've been successful in getting the flash cart to pick up these ROMs as valid by reencrypting their title keys (using this script I wrote, alternatively using the -target p option for makerom works as well). This results in gm9 picking up and validating the files just fine, however they do not show up in the home menu when the flashcart is inserted.

Here's the output of ctrtool -y -q <file> for both the original CIA of Super Mario 3D land I dumped using gm9, and the converted .3ds file created using makerom -ciatocci <CIA file> -o <3ds file> and my own script (note that I have tried all three makerom -target options, and none of them work):

Note that the only other invalid signature in the .3ds file is the one in the NCSD header (the NCCH header signature is invalid in both the CIA and CCI, and its check is, to my knowledge, patched by Luma3DS anyway). This leads me to the conclusion that Luma3DS currently does not patch these NCSD signature checks. I also checked the source code, and also could not find these patches (maybe they exist and I just missed them though). Additionally, I tried to verify this theory by signing a CCI file's header with developer keys (using makerom -target d ...), and setting my console's UNITINFO to be that of a developer unit, but this also failed - I believe this to be the case because the patched UNITINFO only affects the arm11 side (according to the docs), while to my knowledge signature checks reside on the arm9 side.

Note that I have at least a bit of experience when it comes to reverse engineering, however I have no experience specifically reverse engineering 3DS firmware. If someone could give me some pointers on how to get started with this / where to look first, I would be willing to help find / write a patch for the relevant check(s).

PS: I am aware that flashcards like the Sky3DS+ are made completely obsolete by CFW like Luma3DS, and that using such patched ROMs on unmodified systems will never work. However, I've started work on this project more for the technical challenge than the practicality, and I still believe that patching these header checks would at least not hurt anyone, assuming the effort to find/patch them isn't too high.

Popax21 commented 1 year ago

Update: I've ran some more checks, and it turns out the actual issue isn't the NCSD header, nor the NCCH header for that matter. Corrupting neither of them causes a legit ROM file dumped from a real cartridge to fail to load. Upon closer comparison of the two types of files, the most likely candidates for the actual issue are:

I will continue to run more tests to narrow the issue down more.

Popax21 commented 1 year ago

Update: I've ran some more checks, and it turns out the actual issue isn't the NCSD header, nor the NCCH header for that matter. Corrupting neither of them causes a legit ROM file dumped from a real cartridge to fail to load. Upon closer comparison of the two types of files, the most likely candidates for the actual issue are:

* ~Missing Download Play / Update NCSD partitions~ not the issue, erasing these partitions doesn't cause a ROM to fail to load

* NCCH header `NoCrypto` flag (not present on ROMs which manage to load)

* ~NCCH exheader `SDApplication` flag (not present on ROMs which manage to load)~ not the issue, clearing it doesn't result in the ROM loading (I can't (easily) test the other direction because of exheader encryption)

I will continue to run more tests to narrow the issue down more.

OK, I've got a working decompilation setup now, but I couldn't find any checks which prohibit the usage of the NoCrypto flag on non-development consoles like I thought there would be. On the other hand, I only just now realized that the exheader signature isn't checked by ctrtool, so it is probably a lot more likely that this is the issue. Nvm it is checked, so that is not the issue.

Popax21 commented 1 year ago

Update: I've ran some more checks, and it turns out the actual issue isn't the NCSD header, nor the NCCH header for that matter. Corrupting neither of them causes a legit ROM file dumped from a real cartridge to fail to load. Upon closer comparison of the two types of files, the most likely candidates for the actual issue are:

* ~Missing Download Play / Update NCSD partitions~ not the issue, erasing these partitions doesn't cause a ROM to fail to load

* NCCH header `NoCrypto` flag (not present on ROMs which manage to load)

* ~NCCH exheader `SDApplication` flag (not present on ROMs which manage to load)~ not the issue, clearing it doesn't result in the ROM loading (I can't (easily) test the other direction because of exheader encryption)

I will continue to run more tests to narrow the issue down more.

OK, I've got a working decompilation setup now, but I couldn't find any checks which prohibit the usage of the NoCrypto flag on non-development consoles like I thought there would be. ~On the other hand, I only just now realized that the exheader signature isn't checked by ctrtool, so it is probably a lot more likely that this is the issue.~ Nvm it is checked, so that is not the issue.

Ran some more tests, and can now confirm it's the NoCrypto flag - I took a legit ROM, and stitched it back together, just with NoCrypto enabled (also deleted partitions 2 and 7, which are not required - I tested just this modification already). This also broke the NCSD / NCCH signatures, but earlier tests already showed that those are not the issue.

Output of diff ctrtool_legit.txt ctrtool_nocrypto.txt (confirms that the two files are identical except that one has NoCrypto set):

13c13
<  RomSize:                512MB (Used: 0x1C2D0000)
---
>  RomSize:                512MB (Used: 0x19202000)
28,39d27
<  Partition 2
<   Id:                    0006000000111c00
<   Area:                  0x19202000-0x1A469000
<   FsType:                00
<   CryptoType:            00
< 
<  Partition 7
<   Id:                    1c13000000111c00
<   Area:                  0x1A469000-0x1C2D0000
<   FsType:                00
<   CryptoType:            00
< 
85,86c73,74
< Flags:                  0000000001030000
<  > Crypto Key           Secure (0)
---
> Flags:                  0000000001030004
>  > Crypto Key           None
Popax21 commented 1 year ago

I've reverse engineered / debugged the home menu code, and can now confirm the exact mode of failure: when reading the icon file from the game cartridge (using ReadNCCHFile [0x001371bc], called by ReadIcon [0x0010ea40]), it can open the file just fine using FS:OpenFileDirectly (archive type ARCHIVE_SAVEDATA_AND_CONTENT), but the FSFile:Read call to actually read it fails using error 0xe0c046f8. I'll try to find the code path throwing this error in the process9 code base.

urherenow commented 1 year ago

Pardon me, but why are you treating GitHub like a personal blog? You’re essentially having a conversation with yourself, and pinging everyone who subscribes to changes here, in the process. You can make a blog on gbatemp, if you find it useful.

If you are able to track this down and submit a pull request that takes care of it, then great! But if you’re looking for assistance with it, a forum or discord is more suited…

Popax21 commented 1 year ago

Pardon me, but why are you treating GitHub like a personal blog? You’re essentially having a conversation with yourself, and pinging everyone who subscribes to changes here, in the process. You can make a blog on gbatemp, if you find it useful.

If you are able to track this down and submit a pull request that takes care of it, then great! But if you’re looking for assistance with it, a forum or discord is more suited…

My thought process was to post updates for anything which changed the subject of the issue (see the progression of the issue title, it basically has narrowed in on the actual issue from a very vague first hunch), as well as to provide more info on the concrete issue I'm experiencing and post the results of any troubleshooting steps I might have undertaken to obtain more info about what's going (so basically anything which could help someone more experienced than me to narrow down the issue). Looking back I might have been a bit too verbose on that though, so thanks for reminding me, I'll town that down a bit (in fact my next action will probably the PR as soon as I find the codepath).

UPDATE: figured it out + got a working patch, will open a PR tomorrow