Homebrew Homebrew app sys-patch - sysmod that patches on boot

it's mostly just a refactor of all patterns/conds.

but it introduces two new patches:
(NIM - for blocking firmware updates from atum when user has no cal0 blanking or dns.mitm configured)
(OLSC - for spinning icon when using fake linked account or de-synced real account from too many firmware versions ago)
attempt to address overlap boundary buffer.

and removes:
disable_ca_verification patch as users shouldn't be enabling that without real mitm (not dns.mitm)
Congratulations on your work!
 
it's mostly just a refactor of all patterns/conds.

but it introduces two new patches:
(NIM - for blocking firmware updates from atum when user has no cal0 blanking or dns.mitm configured)
(OLSC - for spinning icon when using fake linked account or de-synced real account from too many firmware versions ago)
attempt to address overlap boundary buffer.

and removes:
disable_ca_verification patch as users shouldn't be enabling that without real mitm (not dns.mitm)
And as I see, the NO ERPT patch is now enabled by default.
 
  • Like
Reactions: bth and johw
i'm going to admit, i have zero interest in this, as your answer doesn't make sense.

it's not against any rules to just name what game, that's just nonsense.
DBI causing said check with parental controls flag is a red herring, and unrelated. It's most definitively a rights management check, (NS.RIGHTS),, probably spawned by DLC being installed.

anyway this can be your project, good luck.



Diff:
--- a/sysmod/src/main.cpp
+++ b/sysmod/src/main.cpp
@@ -314,7 +314,7 @@ auto is_emummc() -> bool {
     return (paths.unk[0] != '\0') || (paths.nintendo[0] != '\0');
 }
 
-void patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patterns> patterns) {
+void patcher(Handle handle, const u8* data, size_t data_size, u64 addr, std::span<Patterns> patterns) {
     for (auto& p : patterns) {
         // skip if disabled (controller by config.ini)
         if (p.result == PatchResult::DISABLED) {
@@ -336,8 +336,8 @@ void patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patter
             continue;
         }
 
-        for (u32 i = 0; i < data.size(); i++) {
-            if (i + p.byte_pattern.size >= data.size()) {
+        for (u32 i = 0; i < data_size; i++) {
+            if (i + p.byte_pattern.size >= data_size) {
                 break;
             }
 
@@ -356,22 +356,22 @@ void patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patter
                 // fetch the instruction
                 u32 inst{};
                 const auto inst_offset = i + p.inst_offset;
-                std::memcpy(&inst, data.data() + inst_offset, sizeof(inst));
+                std::memcpy(&inst, data + inst_offset, sizeof(inst));
 
                 // check if the instruction is the one that we want
                 if (p.cond(inst)) {
-                    const auto [patch_data, patch_size] = p.patch(inst);
+                    const auto patch_data = p.patch(inst);
                     const auto patch_offset = addr + inst_offset + p.patch_offset;
 
                     // todo: log failed writes, although this should in theory never fail
-                    if (R_FAILED(svcWriteDebugProcessMemory(handle, &patch_data, patch_offset, patch_size))) {
+                    if (R_FAILED(svcWriteDebugProcessMemory(handle, &patch_data, patch_offset, patch_data.size))) {
                         p.result = PatchResult::FAILED_WRITE;
                     } else {
                         p.result = PatchResult::PATCHED_SYSPATCH;
                     }
                     // move onto next pattern
                     break;
-                } else if (p.applied(data.data() + inst_offset + p.patch_offset, inst)) {
+                } else if (p.applied(data + inst_offset + p.patch_offset, inst)) {
                     // patch already applied by sigpatches
                     p.result = PatchResult::PATCHED_FILE;
                     break;
@@ -434,12 +434,14 @@ auto apply_patch(PatchEntry& patch) -> bool {
                     if (R_FAILED(svcReadDebugProcessMemory(buffer + overlap_size, handle, mem_info.addr + sz, actual_size))) {
                         break;
                     } else {
-                        patcher(handle, std::span{buffer, actual_size + overlap_size}, mem_info.addr + sz - overlap_size, patch.patterns);
+                        patcher(handle, buffer, actual_size + overlap_size, mem_info.addr + sz - overlap_size, patch.patterns);
                         if (actual_size >= overlap_size) {
-                            memcpy(buffer, buffer + actual_size, overlap_size);
+                            memcpy(buffer, buffer + READ_BUFFER_SIZE, overlap_size);
                             std::memset(buffer + overlap_size, 0, READ_BUFFER_SIZE);
                         } else {
-                            std::memset(buffer, 0, sizeof(buffer));
+                            const auto bytes_to_overlap = std::min<u64>(overlap_size, actual_size);
+                            memcpy(buffer, buffer + READ_BUFFER_SIZE + (actual_size - bytes_to_overlap), bytes_to_overlap);
+                            std::memset(buffer + bytes_to_overlap, 0, sizeof(buffer) - bytes_to_overlap);
                         }
                     }
                 }


meanwhile, i'm currently going over sys-patch and finalizing a 1.5.9 PR upstream
No problem I'll figure it out. I found when you create a linked account a json file gets stored on the switch and then read, I know where to find that in the code - (in module 010000000000001E). As for a games linked account flag, it's read from the control.nacp, "nn::ns::ApplicationControlProperty".

https://switchbrew.org/wiki/NACP
0x3213 0x1 RequiredNetworkServiceLicenseOnLaunchFlag

To save trying to find a game that needs a linked account, I've created a fake linked account NRO forwarder nsp, it will launch sdmc:/switch/test.nro. When you try to run it you will need a linked account or it will not run.
 

Attachments

Last edited by bombayjack,
No problem I'll figure it out. I found when you create a linked account a json file gets stored on the switch and then read, I know where to find that in the code - (in module 010000000000001E). As for a games linked account flag, it's read from the control.nacp, "nn::ns::ApplicationControlProperty".

https://switchbrew.org/wiki/NACP
0x3213 0x1 RequiredNetworkServiceLicenseOnLaunchFlag

To save trying to find a game that needs a linked account, I've created a fake linked account NRO forwarder nsp, it will launch sdmc:/switch/test.nro. When you try to run it you will need a linked account or it will not run.
unless you name an actual game which genuinly has that flag set, there isn't much point in me looking into this.

i'm not asking you to share the game files (nonsense you made up previously).

just the name of the game, and its titleid (use https://tinfoil.io/Title/ for reference)

the references for that function/call is embedded within the game(s) that has the flag set, it's just an unmarked function within NS.

https://switchbrew.org/wiki/Glue_services
0100000000000031
GetApplicationControlProperty is called from glue (control property is "inside" of nacp)
nacp loaded by ns from cnmt
cnmt loaded by NCM ("PackagedContentMeta")
 
Thanks a lot @impeeza and @bth for your work!
Any idea why the sys-patch-v1.5.9 available for download on GBAtemp and on Github are different?
he pushed a release without asking me, which was missing a commit, so i force pushed the github re-release, he said in dms he's gone until monday.

@bombayjack anyway. within NS 21.0.0

"HostAppPkgRead" is what uses the data for the 0x4000 segment of the nacp (though it also loads the value of something called ncd0)

ns-2100.jpg
 
E, pelo que vejo, o patch NO ERPT agora está ativado por padrão.

Is this release more up-to-date than the one on GitHub?
 
Thanks a lot @impeeza and @bth for your work!
Any idea why the sys-patch-v1.5.9 available for download on GBAtemp and on Github are different?

he pushed a release without asking me, which was missing a commit, so i force pushed the github re-release, he said in dms he's gone until monday.

@bombayjack anyway. within NS 21.0.0

"HostAppPkgRead" is what uses the data for the 0x4000 segment of the nacp (though it also loads the value of something called ncd0)

View attachment 547896

Now they should be equal. updated the download sections.
 
@bth

Thanks, I'll have a look at that during the week. I'm busy for the next few days so won't have any time to look at it.
https://github.com/Atmosphere-NX/At...urce/pgl/srv/pgl_srv_shell_host_utils.cpp#L24

but it says as much that it's in PGL as of 10.0.0
https://switchbrew.org/wiki/NS_services#ns:dev

https://github.com/Atmosphere-NX/At...tosphere/source/pgl/srv/pgl_srv_shell.hpp#L28
the function i've identified in NS is "HostAppPkgRead" (due to the string present), and atmosphere calls that "HostPackageRead"

atmosphere pretty much does all aspects of launching programs, AM, PM, PGL, Loader, NCM.



now all of this information is useless, as it's not the parts atmosphere controls that is calling NS to do that.

anyway adding this to system_settings.ini might disable the behaviour where "NA" stands for Nintendo Account.

Code:
[account]
na_license_verification_enabled  = u8!0x0
na_required_for_network_service  = u8!0x0


and the flag allegedly causing your problems is:
RequiredNetworkServiceLicenseOnLaunchFlag

(both of these values default to true)


if it does, patching that is as simple as patching OLSC. (i.e. just patching the BL 158ed0 mov w0, #0x1 for both of those to make them the same as what system_settings.ini would do)

account.jpg



find a real life example / testing enviroment with a real game requiring an account and launch it without a linked account, with those settings set in system-settings.ini

if it does, i'll make a pattern patching both, if it doesn't, then this pretty much a waste of time.
 
Last edited by bth,
  • Wow
Reactions: impeeza
https://github.com/Atmosphere-NX/At...urce/pgl/srv/pgl_srv_shell_host_utils.cpp#L24

but it says as much that it's in PGL as of 10.0.0
https://switchbrew.org/wiki/NS_services#ns:dev

https://github.com/Atmosphere-NX/At...tosphere/source/pgl/srv/pgl_srv_shell.hpp#L28
the function i've identified in NS is "HostAppPkgRead" (due to the string present), and atmosphere calls that "HostPackageRead"

atmosphere pretty much does all aspects of launching programs, AM, PM, PGL, Loader, NCM.



now all of this information is useless, as it's not the parts atmosphere controls that is calling NS to do that.

anyway adding this to system_settings.ini might disable the behaviour where "NA" stands for Nintendo Account.

Code:
[account]
na_license_verification_enabled  = u8!0x0
na_required_for_network_service  = u8!0x0


and the flag allegedly causing your problems is:
RequiredNetworkServiceLicenseOnLaunchFlag

(both of these values default to true)


if it does, patching that is as simple as patching OLSC. (i.e. just patching the BL 158ed0 mov w0, #0x1 for both of those to make them the same as what system_settings.ini would do)

View attachment 547938


find a real life example / testing enviroment with a real game requiring an account and launch it without a linked account, with those settings set in system-settings.ini

if it does, i'll make a pattern patching both, if it doesn't, then this pretty much a waste of time.


Mate, so adding those lines Linkalho is not needed anymore?
 
  • Like
Reactions: johw
Mate, so adding those lines Linkalho is not needed anymore?

find a real life example / testing enviroment with a real game requiring an account and launch it without a linked account, with those settings set in system-settings.ini

if it does, i'll make a pattern patching both, if it doesn't, then this pretty much a waste of time.

feel free to test, validate and find out.

if validated, that they do that, then i will make a patch for it in sys-patch, just like OLSC was.
 
  • Love
  • Like
Reactions: impeeza and johw
feel free to test, validate and find out.

if validated, that they do that, then i will make a patch for it in sys-patch, just like OLSC was.
Don't bother, I tested and they don't work. I'll have a look at the modules later (in a few days) when I get some time. I'm going to unpack every module and make a database with all the functions/strings from every module and then see what's what, then I'll cross referene them with stuff I find on switchbrew.
 
Don't bother, I tested and they don't work. I'll have a look at the modules later (in a few days) when I get some time. I'm going to unpack every module and make a database with all the functions/strings from every module and then see what's what, then I'll cross referene them with stuff I find on switchbrew.
You who cant name a real life example, of a game that exhibits this behaviour?

I don't think you qualify for the type of feedback required, as your homebrew/parentail control whatever dbi nonsense isn't the same function that is supposed to "fix"
 
Not same SHA256

bth: sha256:55453191e31d3ad3614f861d14ed877a3ebdd70f21a6a62f48ae6662a3ae70f6
impeeza: sha256:c4b97c4785efe843e3341f8ba1f388d9a3229d3211b2b6f20512e836792b422f
you're being silly.
https://github.com/impeeza/sys-patch/commit/f407d0d9d7925cff910bcc5816cc6d7099272c2b
https://github.com/impeeza/sys-patch/actions/runs/20542641744
https://github.com/borntohonk/sys-patch/commit/f407d0d9d7925cff910bcc5816cc6d7099272c2b
https://github.com/borntohonk/sys-patch/actions/runs/20542719761


https://github.com/impeeza/sys-patch/actions/runs/20542641744/job/59009075885#step:3:98
https://github.com/borntohonk/sys-patch/actions/runs/20542719761/job/59009253800#step:3:98


they are the exact same, but built at different seconds, of course the sha256 is going to be different, and that is because the makefile is the source of these two:

https://github.com/impeeza/sys-patch/blob/master/sysmod/src/main.cpp#L656-L658
https://github.com/impeeza/sys-patch/blob/master/Makefile#L34
https://github.com/impeeza/sys-patch/blob/master/Makefile#L23


the release(es) are auto-generated/auto-published by the github action, and later the description is edited. nothing has been changed.

the only real difference between the artifact and the "release", is that the artifact uses a different mechanic to make the .zip and the default name is "sys-patch-VERSION"
and the actual release uses just sys-patch.zip (from sys-patch generating it)

i.e. archives are never going to match sha256 with the artifact, as we are deploying a different .zip than the artifact, but its the exact same sha256 of the sys-patch sysmodule itself.

but a GH action from two different repositories embedding down to seconds in build date and putting it in binary, is not going to be a sha256 match.


(i will change it so that the sha256 of artifact and release matches, but can't address cross-repository of course, as the build-date will never match)


edit: due to how "upload-artifact" and "download-artifact" works, one cant really change the behaviour, and the artifact sha256 will never match the release sha256 lmao - because the download-artifact function extracts the archive)

the only change i'd make is this https://github.com/borntohonk/sys-patch/commit/907255fae88681eaeef3ae1790c2cba52844d902

which is cosmetic only, seeing as download-artifact will never do what i want, and using the gh api to fetch current running job to download current running job id's artifact, just to have the immutable internal archive with the same sha256, doesn't sound like fun

what i can do is print out sha256 of the release archive in the gh action so that one can see that it wasn't changed (lmao)
https://github.com/borntohonk/sys-patch/actions/runs/20573163829/job/59084392755#step:6:20

sha256.jpg
 
Last edited by bth,
Not same SHA256

bth: sha256:55453191e31d3ad3614f861d14ed877a3ebdd70f21a6a62f48ae6662a3ae70f6
impeeza: sha256:c4b97c4785efe843e3341f8ba1f388d9a3229d3211b2b6f20512e836792b422f
That's because actions build put the date and time of build Inside the binaries. So different binaries from the exact same source are generated even if build a second later
 
Last edited by impeeza,

the tl:dr is, he changed it so that whatever those two repositories are supposed to do, that they can no longer disable sys-patch, or at least, he made an attempt. disable as in, make it not run after rebooting again.

that is how i'm interpreting his intention.
 

Site & Scene News

Popular threads in this forum