borntohonk / Switch-Ghidra-Guides

Various patches for the Nintendo Switch, and how to make them.
MIT License
112 stars 12 forks source link

FS patch3 - FW19 #19

Closed mrdude2478 closed 1 week ago

mrdude2478 commented 1 week ago

I see you have added a new patch for FW19 for the fat/exfat fs.

patch3 = '%06X%s%s' % (result2.start() - 0x84, '0004', '10000014') #

I have XCI and NSP working without that patch (just using the same patches as before), NRO forwarders are not working for now even with your new patch, what is this new patch meant to do? I am just interested in why it exists? I know it's a branch to a new address but is it for NRO forwarders?

Maybe AtmosphereNX needs finished and this is why they are not working for now?

borntohonk commented 1 week ago

I see you have added a new patch for FW19 for the fat/exfat fs.

patch3 = '%06X%s%s' % (result2.start() - 0x84, '0004', '10000014') #

I have XCI and NSP working without that patch (just using the same patches as before), NRO forwarders are not working for now even with your new patch, what is this new patch meant to do? I am just interested in why it exists? I know it's a branch to a new address but is it for NRO forwarders?

Maybe AtmosphereNX needs finished and this is why they are not working for now?

Are you sure you're on 19.0.0? Because unless you're compiling atmosphere yourself or running the build from the reswitched discord, how could you tell? :) and also i guess, ontop of that is, "atmosphere loader patch"

also, patch 2 requires 0x08 offset now, ontop of new regex.

1728553318330661

1728553457959450

borntohonk commented 1 week ago

This is what the patch 2 and patch 3 does.

1728563887254942

borntohonk commented 1 week ago

there's also a second CMP added togheter with the B.EQ which checks the value of TST w0,#0xFF, inside of the existing old instruction block, which goes back and forth, it gets confusing, but that is why the "third value" is patched now.

tl:dr i now patch it out, to control the outcome to what is desired, and not leave some weird race condition that is 100% guranteed to fail, if called for, which seemed foreign enough for me to address, as its called from outside this function.

borntohonk commented 1 week ago

I have XCI and NSP working without that patch

Also to add to this......

modern day "xci installs" are signature intact and not byteflipped to eshop, thus don't need the nca header patch, nor atmosphere loader patch, only ES is required for "NSP" sourced from eshop. note: to this, xci installs that nca's are not altered do require the first patch, but not the second (and now new third)

forwarders ("homebrew signed installed binaries") require both the loader patch AND all patches to FS. So the reason you have things working and assume nothing is wrong, is more of just coincidence.

the difference is that homebrew signed binaries are not only signature broken, they are custom signed.

"xci installs" that are "converted" (byteflipped source to digital in header using bad converters), or repackaged .nca's require all patches.

also note: atmosphere does not support forwarders in any way, and if broken (from their side), will not fix functionality unless something else is broken unrelated to forwarders.

borntohonk commented 1 week ago

also...

https://github.com/Atmosphere-NX/Atmosphere/compare/master...1900_support#diff-8f4f075aef2c24447ccda4c26924401ac8ee494eb948d971e1116e8df73bda07R433

 /* 19.0.0+ disallows more than one flag set; we are always DebugMode for kernel, so ForceDebug is the most powerful/flexible flag to set. */

to me it seems like a loader permission issue, related to this, which will require a fork / new loader patch

borntohonk commented 1 week ago

@mrdude2478 https://github.com/switchbrew/nx-hbloader/blob/master/hbl.json#L246-L250

the code which all forwarders are based off of sets two debug flags, which is disallowed now...

So yeah, uhm, yup. All forwarders, homebrew, etc will need to be recompiled with only one debug flag set.

feel free to comment further, i will respond, but i consider this investigated enough from my end.

            "type": "debug_flags",
            "value": {
                "allow_debug": false,
                "force_debug_prod": false,
                "force_debug": true
            }
mrdude2478 commented 1 week ago

Thanks for the detailed information, It will take me a while to get through investigating all that and I only had 3 hours sleep last night so I'll probably do that tomorrow.

I compiled the 1900_support branch and modded fusee to be able use IPS patches as sys-patch doesn't apply any patches (I recompiled that as well) and Hekate was causing a yellow screen so maybe needs updating as well for 19.0 fw and new.

I used the "test" AtmosphereNX files that were posted on the discord server (apart from the modded fusee.bin) .

Anyway, thanks for replying, you have given a great deal of info for me to get through and have been most helpful.

EDIT: Also, FYI I tried converted nsp to xci and also bit flipping distribution bit for nca's and they worked fine as well, also I see hekate has now been updated and works well with patches.ini.

I guess you are correct in that forwarders will need redone and I had a look at sys-patch code and debug flags are set like this:

"type": "debug_flags",
            "value":    {
                "allow_debug":  false,
                "force_debug":  true
            }

So I am not sure why that's not patching now as expected?

Thanks again,your information is proving very useful.

EDIT2: You were correct abot debug flags, I rebuilt HackBrewPack with the modded flags and was then able to build a working NRO forwarder, so all patches are good.

borntohonk commented 1 week ago

I guess you are correct in that forwarders will need redone and I had a look at sys-patch code and debug flags are set like this:

            "type": "debug_flags",
            "value": {
                "allow_debug": false,
                "force_debug_prod": false,
                "force_debug": true
            }

with this commit for switch-tools https://github.com/switchbrew/switch-tools/pull/47/files

borntohonk commented 1 week ago

and also to re-iterate, the third new patch is not done because it "does something", it's done because it's new and called from externally outside this function, and whatever value sent to it's TST #0xFF value when called for, can prematurely cockblock the other patch, since it's before the other one.

I see what it does, i know what it does, i know it's not ran automatically in this specific function, but it's a variable that can be set outside, so the logical thing to do, is to patch it to never be able to be called for that way.

it is patched so that whatever is external calling for this very clearly signature checking function, does not pass a value that fails the race condition, because games and other modules can do that, it's calling for a fatal/fail, which is not wanted.

control what you can control, letting it be unpatched is unwanted behavior.

Desired behavior for us, is to reach RET with a ZERO, if TST #0xFF from outside function fails the CMP/B.EQ condition it sends non-zero out of THIS FUNCTION, which in the usecase results in FAIL. (old other patch is still needed, but would be bypassed if that happens !!!!)

the BL we patch with mov x0, XZR removes function capable of setting non-zero (when the signature is actually checked), with a guranteed zero, we control the instruction chain by doing that, and it arrives at RET with a zero.

We could have just RET 0 at the beginning of function and end it, but there's loops and whatnot other filesystem related, so we let it play out, that's why mov x0, XZR. that's what XZR does. It sets a zero.

The new thing I patch, is paralell/before that XZR we set, and can also be set outside of this function, and fail independant of the "old patch".

(from images above, it's the one labelled BAD END 0)

by changing b.eq to b (no branch if equal), the cmp of tst 0xFF is irrelevant as it goes to (B)ranch ("LAB" ghidra nomenclature) containing the function-call ("BL"/"Branch-Loader") we XZR. That function call is the actual function checking signatures, and this new b.eq test 0xFF is PARALLEL TO THAT

mrdude2478 commented 1 week ago

Very interesting. Also thanks for posting the commit to switch tools. I'm going to have a look at that patch again now that you have explained in a lot of detail. I was pretty tired yesterday so couldn't think straight but now I read again what you posted it makes more sense.

Thanks again.

borntohonk commented 1 week ago

Very interesting. Also thanks for posting the commit to switch tools. I'm going to have a look at that patch again now that you have explained in a lot of detail. I was pretty tired yesterday so couldn't think straight but now I read again what you posted it makes more sense.

Thanks again.

diffing the functions responsible for calling the responsible function

18.1.0 calling for FUN_741F0 (function of within we change a BL to mov x0, xzr): FUN_72710 FUN_74530 FUN_74AA0

19.0.0 calling for FUN_743F0 (function of within we change a BL to mov x0, xzr): FUN_722A0 (1 cmp less than 18.1.0 before calling FUN_743F0) FUN_74750 (1 cmp less than 18.1.0 before calling FUN_743F0) FUN_74D00 (similar to 18.1.0)

and in 19.0.0 in FUN_743F0 we now have a new cmp of tst 0xFF, not by coincidence i assume! Before i assume said cmp would not really fail, and now it has an actual fail condition. What exactly its calling for i'm not going to put much time into investigating

NOT THAT IT EVER FAILED BEFORE! but who knows, anything is possible, we could just not have triggered it yet, and now that race condition is in the function of interest, so that is why to patch it out.

an alternative is do mov x0, xzr to replace the 3 function-calls ("BL FUN_71000743f0") (I believe that was the old standard for patching afaik, so that it's never called at all, but we keep it now for code flow to not cause quirks.)

borntohonk commented 1 week ago

I basically am not very trusting of the new value, one can generally get a good idea of how things work by utilizing the graph functionality of ghidra, and if one is not familiar with what instructions do what, one can use arm's documentation https://developer.arm.com/documentation/ graph

this being the loop that reads the signature 0x10 at a time by loop until end loop

borntohonk commented 1 week ago

hmm i just made the realization that we end with a NOP inside of FUN_7100076AC0, lmao

in other words the mov 0x, xzr ensures we hit that TBNZ condition with a zero NOP'ing the chain and do not go down to the 0x200 test.

mrdude2478 commented 1 week ago

hmm i just made the realization that we end with a NOP inside of FUN_7100076AC0, lmao

in other words the mov 0x, xzr ensures we hit that TBNZ condition with a zero NOP'ing the chain and do not go down to the 0x200 test.

I use IDAPro, it also has graphing feature and when you change the hex in the program to the new patch, it shows the new graph and the address to where the branch is made. I can post you a link for the 9.0.240807 version - fully activated if you want to try it.

borntohonk commented 1 week ago

when you change the hex in the program to the new patch, it shows the new graph and the address to where the branch is made.

Ghidra lets you patch instructions and it also renews the graph, as well as pseudocode live.