diff --git a/.github/workflows/build-jobs.yaml b/.github/workflows/build-jobs.yaml new file mode 100644 index 0000000..dfd713e --- /dev/null +++ b/.github/workflows/build-jobs.yaml @@ -0,0 +1,52 @@ +name: Build jobs + +on: + workflow_call: + workflow_dispatch: + push: + +jobs: + build: + runs-on: ubuntu-latest + container: devkitpro/devkita64 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-tags: true + path: sys-patch + submodules: recursive + + - name: Build sys-patch + run: | + make -C sys-patch -j$(nproc) dist && \ + VERSION=$(grep 'export VERSION := ' sys-patch/Makefile | cut -c 19-) + TAGVERSION=$(curl -s https://api.github.com/repos/$GITHUB_REPOSITORY/releases/latest | grep "tag_name" | head -1 | cut -d '"' -f 4) + echo "VERSION=${VERSION}" >> $GITHUB_ENV + echo "TAGVERSION=${TAGVERSION}" >> $GITHUB_ENV + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + include-hidden-files: true + overwrite: true + name: sys-patch-${{ env.VERSION }} + path: sys-patch/out/ + + - name: Fetch git cli and upload release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ ${{ env.TAGVERSION }} = v${{ env.VERSION }} ]; + then echo "Tag version and makefile version are same, don't publish release, only artifact uploaded." + else + wget -q $(curl -s https://api.github.com/repos/cli/cli/releases/latest | grep "browser_download_url" | grep "linux_amd64.tar.gz" | head -1 | cut -d '"' -f 4) && \ + tar -xzf gh*.tar.gz && \ + chmod +x gh*/bin/gh && \ + chmod +x gh*/bin/gh && \ + cp gh*/bin/gh /bin/gh && \ + rm gh*.tar.gz && \ + rm -rf gh* + gh release create v${{ env.VERSION }} sys-patch/sys-patch.zip --title "Sys-patch version ${{ env.VERSION }}" --repo github.com/$GITHUB_REPOSITORY + fi diff --git a/.github/workflows/build_depoly.yml b/.github/workflows/build_depoly.yml deleted file mode 100644 index 9516f19..0000000 --- a/.github/workflows/build_depoly.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: build -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - container: devkitpro/devkita64:latest - - steps: - - name: Checkout 🛎️ - uses: actions/checkout@master - with: - submodules: recursive - - - name: Build - run: make dist -j2 - - - uses: actions/upload-artifact@master - with: - name: sys-patch - path: sys-patch.zip diff --git a/.gitmodules b/.gitmodules index 9b1605c..2088864 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "overlay/libtesla"] path = overlay/libtesla - url = https://github.com/ITotalJustice/libtesla.git - branch = tj + url = https://github.com/WerWolv/libtesla + branch = master diff --git a/Makefile b/Makefile index 3536911..f760ec7 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,13 @@ MAKEFILES := sysmod overlay TARGETS := $(foreach dir,$(MAKEFILES),$(CURDIR)/$(dir)) # the below was taken from atmosphere + switch-examples makefile -export VERSION := 1.3.0 +export VERSION := 1.5.9 + +ifneq ($(strip $(shell git symbolic-ref --short HEAD 2>/dev/null)),) export GIT_BRANCH := $(shell git symbolic-ref --short HEAD) +else +export GIT_BRANCH := notbranch +endif ifeq ($(strip $(shell git status --porcelain 2>/dev/null)),) export GIT_REVISION := $(GIT_BRANCH)-$(shell git rev-parse --short HEAD) @@ -41,6 +46,7 @@ $(TARGETS): clean: @rm -rf out + @rm -f sys-patch.zip @for i in $(TARGETS); do $(MAKE) -C $$i clean || exit 1; done; dist: all diff --git a/README.md b/README.md index 6d293de..f1940d8 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,32 @@ # sys-patch -A script-like system module that patches fs, es and ldr on boot. +A script-like system module that patches **fs**, **es**, **ldr**, **nifm** and **nim** on boot. --- ## Config -sys-patch features a simple config. This can be manually editied or updated using the overlay. +**sys-patch** features a simple config. This can be manually edited or updated using the overlay. -the config file can be found in `/config/sys-patch/config.ini`, if the file does not exist, the file will be created when sys-patch is run. +The configuration file can be found in `/config/sys-patch/config.ini`. The file is generated once the module is ran for the first time. ```ini [options] -patch_sysmmc=1 ; 1=(default) patch sysmmc, 0=don't patch sysmmc -patch_emummc=1 ; 1=(default) patch emummc, 0=don't patch emummc -logging=1 ; 1=(default) output /config/sys-patch/log.ini 0=no log -version_skip=1 ; 1=(default) skips out of date patterns, 0=search all patterns +patch_sysmmc=1 ; 1=(default) patch sysmmc, 0=don't patch sysmmc +patch_emummc=1 ; 1=(default) patch emummc, 0=don't patch emummc +enable_logging=1 ; 1=(default) output /config/sys-patch/log.ini 0=no log +version_skip=1 ; 1=(default) skips out of date patterns, 0=search all patterns ``` --- ## Overlay -the overlay can be used to change the config options and to see what patches are applied (if any). +The overlay can be used to change the config options and to see what patches are applied. - Unpatched means the patch wasn't applied (likely not found). - Patched (green) means it was patched by sys-patch. -- Patched (yellow) means it was already patched, likely by sigpatches or a custom atmosphere build. +- Patched (yellow) means it was already patched, likely by sigpatches or a custom Atmosphere build.
@@ -40,63 +40,55 @@ the overlay can be used to change the config options and to see what patches are
## Building
### prerequisites
-- install devkitpro
+- Install [devkitpro](https://devkitpro.org/wiki/Getting_Started)
+- Run the following:
+ ```sh
+ git clone --recurse-submodules https://github.com/ITotalJustice/sys-patch.git
+ cd ./sys-patch
+ make
+ ```
-```sh
-git clone --recurse-submodules https://github.com/ITotalJustice/sys-patch.git
-cd sys-patch
-make
-```
-
-the output of `out/` can be copied to your sd card. for the sysmodule to take effect, rebot your switch, or, use [sysmodules overlay](https://github.com/WerWolv/ovl-sysmodules/tree/master/source) to start it.
+The output of `out/` can be copied to your SD card.
+To activate the sys-module, reboot your switch, or, use [sysmodules overlay](https://github.com/WerWolv/ovl-sysmodules/releases/latest) with the accompanying overlay to activate it.
---
## What is being patched?
-Here's a quick run down of what's being patched
-
-- fs
-- es
-- ldr
+Here's a quick run down of what's being patched:
-fs and es need new patches after every new fw version.
+- **fs** and **es** need new patches after every new firmware version.
+- **ldr** needs new patches after every new [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere/) release.
+- **nifm** ctest patch allows the device to connect to a network without needing to make a connection to a server
+- **nim** patches to the ssl function call within nim that queries "https://api.hac.%.ctest.srv.nintendo.net/v1/time", and crashes the console if console ssl certificate is not intact. This patch instead makes the console not crash.
-ldr on the other hand needs new patches after every new atmosphere release. this is due to ldr service being reimplemented by atmosphere. in fw 10.0.0, a new check was added to ofw which we needed to patch out. As atmosphere closely follows what ofw does, it also added this check. This is why a new patch is needed per atmosphere update.
+The patches are applied on boot. Once done, the sys-module stops running.
+The memory footprint *(16kib)* and the binary size *(~50kib)* are both very small.
---
-## How does it work?
+## FAQ:
-it uses a collection of patterns to find the piece of code to patch. alternatively, it could just use offsets, however this would mean this tool would have to be updated after every new fw update, that's not ideal.
+### If I am using sigpatches already, is there any point in using this?
-the patches are applied at boot, then, the sysmod stops running. the memory footpint of the sysmod is very very small, only using 16kib in total. the size of the binary itself is only ~50kib! this doesnt really mean much, but im pretty proud of it :)
-
----
-
-## Does this mean i should stop downloading / using sigpatches?
-
-No, i would personally recommend continuing to use sigpatches. Reason being is that should this tool ever break, i likely wont be quick to fix it.
-
----
+Yes, in 3 situations.
-## If i am using sigpatches already, is there any point in using this as well?
+1. A new **ldr** patch needs to be created after every Atmosphere update. Sometimes, a new silent Atmosphere update is released. This tool will always patch **ldr** without having to update patches.
-Yes, in 2 niche cases.
+2. Building Atmosphere from src will require you to generate a new **ldr** patch for that custom built Atmosphere. This is easy enough due to the public scripts / tools that exist out there, however this will always be able to patch **ldr**.
-1. A new ldr patch needs to be created after every atmosphere update. Sometimes, a new silent atmosphere update is released. This tool will always patch ldr without having to update patches.
+3. If you forget to update your patches when you update your firmware / Atmosphere, this sys-module should be able to patch everything. So it can be used as a fall back.
-2. Building atmosphere from src will require you to generate a new ldr patch for that custom built atmosphere. This is easy enough due to the public scripts / tools that exist out there, however this will always be able to
+### Does this mean that I should stop downloading / using sigpatches?
-Also, if you forget to update your patches when you update fw / atmosphere, this sysmod should be able to patch everything just fine! so it's nice to have as a fallback.
+No, I would personally recommend continuing to use sigpatches. Reason being is that should this tool ever break, i likely wont be quick to fix it.
---
## Credits / Thanks
-software is built on the shoulders of giants. this tool wouldn't be possible wthout these people:
+Software is built on the shoulders of giants. This tool wouldn't be possible without these people:
-- DarkMatterCore
- MrDude
- BornToHonk (farni)
- TeJay
@@ -105,3 +97,5 @@ software is built on the shoulders of giants. this tool wouldn't be possible wth
- DevkitPro (toolchain)
- [minIni](https://github.com/compuphase/minIni)
- [libtesla](https://github.com/WerWolv/libtesla)
+- [Shoutout to the best switch cfw setup guide](https://rentry.org/SwitchHackingIsEasy)
+- N
diff --git a/configs/cliff.toml b/configs/cliff.toml
new file mode 100644
index 0000000..f976285
--- /dev/null
+++ b/configs/cliff.toml
@@ -0,0 +1,69 @@
+# git-cliff ~ configuration file
+# https://git-cliff.org/docs/configuration
+
+[changelog]
+# changelog header
+header = """
+# Changelog\n
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version -%}
+ ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
+{% else -%}
+ ## [Unreleased]
+{% endif -%}
+{% for group, commits in commits | group_by(attribute="group") %}
+ ### {{ group | upper_first }}
+ {% for commit in commits %}
+ - {{ commit.message | upper_first }}\
+ {% endfor %}
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+
+"""
+# remove the leading and trailing whitespace from the templates
+trim = true
+
+[git]
+# parse the commits based on https://www.conventionalcommits.org
+conventional_commits = true
+# filter out the commits that are not conventional
+filter_unconventional = false
+# process each line of a commit as an individual commit
+split_commits = false
+# regex for parsing and grouping commits
+commit_parsers = [
+ { message = "^feat", group = "Features" },
+ { message = "^fix", group = "Bug Fixes" },
+ { message = "^doc", group = "Documentation" },
+ { message = "^perf", group = "Performance" },
+ { message = "^refactor", group = "Refactor" },
+ { message = "^style", group = "Styling" },
+ { message = "^test", group = "Testing" },
+ { message = "^chore\\(release\\): prepare for", skip = true },
+ { message = "^chore", group = "Miscellaneous Tasks" },
+ { body = ".*security", group = "Security" },
+ { body = ".*", group = "Other (unconventional)" },
+]
+# protect breaking changes from being skipped due to matching a skipping commit_parser
+protect_breaking_commits = false
+# filter out the commits that are not matched by commit parsers
+filter_commits = true
+# regex for matching git tags
+tag_pattern = "[0-9]+.[0-9]+.[0-9]+"
+# regex for skipping tags
+skip_tags = "v0.1.0-beta.1"
+# regex for ignoring tags
+ignore_tags = ""
+# sort the tags topologically
+topo_order = false
+# sort the commits inside sections by oldest/newest order
+sort_commits = "oldest"
diff --git a/overlay/src/main.cpp b/overlay/src/main.cpp
index 402742c..eb44735 100644
--- a/overlay/src/main.cpp
+++ b/overlay/src/main.cpp
@@ -43,12 +43,10 @@ auto create_dir(const char* path) -> bool {
}
struct ConfigEntry {
- const char* const section;
- const char* const key;
- bool value;
-
ConfigEntry(const char* _section, const char* _key, bool default_value) :
- section{_section}, key{_key}, value{default_value} {}
+ section{_section}, key{_key}, value{default_value} {
+ this->load_value_from_ini();
+ }
void load_value_from_ini() {
this->value = ini_getbool(this->section, this->key, this->value, CONFIG_PATH);
@@ -62,23 +60,17 @@ struct ConfigEntry {
});
return item;
}
+
+ const char* const section;
+ const char* const key;
+ bool value;
};
-class GuiMain final : public tsl::Gui {
+class GuiOptions final : public tsl::Gui {
public:
- GuiMain() { }
+ GuiOptions() { }
- // Called when this Gui gets loaded to create the UI
- // Allocate all elements on the heap. libtesla will make sure to clean them up when not needed anymore
tsl::elm::Element* createUI() override {
- create_dir("/config/");
- create_dir("/config/sys-patch/");
-
- config_patch_sysmmc.load_value_from_ini();
- config_patch_emummc.load_value_from_ini();
- config_logging.load_value_from_ini();
- config_version_skip.load_value_from_ini();
-
auto frame = new tsl::elm::OverlayFrame("sys-patch", VERSION_WITH_HASH);
auto list = new tsl::elm::List();
@@ -88,6 +80,98 @@ class GuiMain final : public tsl::Gui {
list->addItem(config_logging.create_list_item("Logging"));
list->addItem(config_version_skip.create_list_item("Version skip"));
+ frame->setContent(list);
+ return frame;
+ }
+
+ ConfigEntry config_patch_sysmmc{"options", "patch_sysmmc", true};
+ ConfigEntry config_patch_emummc{"options", "patch_emummc", true};
+ ConfigEntry config_logging{"options", "enable_logging", true};
+ ConfigEntry config_version_skip{"options", "version_skip", true};
+};
+
+class GuiToggle final : public tsl::Gui {
+public:
+ GuiToggle() { }
+
+ tsl::elm::Element* createUI() override {
+ auto frame = new tsl::elm::OverlayFrame("sys-patch", VERSION_WITH_HASH);
+ auto list = new tsl::elm::List();
+
+ list->addItem(new tsl::elm::CategoryHeader("FS - 0100000000000000"));
+ list->addItem(config_noacidsigchk1.create_list_item("noacidsigchk_1.0.0-9.2.0"));
+ list->addItem(config_noacidsigchk2.create_list_item("noacidsigchk_1.0.0-9.2.0"));
+ list->addItem(config_noncasigchk1.create_list_item("noncasigchk_10.0.0-16.1.0"));
+ list->addItem(config_noncasigchk2.create_list_item("noncasigchk_17.0.0+"));
+ list->addItem(config_nocntchk1.create_list_item("nocntchk_10.0.0-18.1.0"));
+ list->addItem(config_nocntchk2.create_list_item("nocntchk_19.0.0-20.5.0"));
+ list->addItem(config_nocntchk3.create_list_item("nocntchk_21.0.0+"));
+
+ list->addItem(new tsl::elm::CategoryHeader("LDR - 0100000000000001"));
+ list->addItem(config_noacidsigchk3.create_list_item("noacidsigchk_10.0.0+"));
+
+ list->addItem(new tsl::elm::CategoryHeader("ERPT - 010000000000002B"));
+ list->addItem(config_no_erpt.create_list_item("no_erpt"));
+
+ list->addItem(new tsl::elm::CategoryHeader("ES - 0100000000000033"));
+ list->addItem(config_es1.create_list_item("es_1.0.0-8.1.1"));
+ list->addItem(config_es2.create_list_item("es_9.0.0-11.0.1"));
+ list->addItem(config_es3.create_list_item("es_12.0.0-18.1.0"));
+ list->addItem(config_es4.create_list_item("es_19.0.0+"));
+
+ list->addItem(new tsl::elm::CategoryHeader("OLSC - 010000000000003E"));
+ list->addItem(config_olsc1.create_list_item("olsc_6.0.0-14.1.2"));
+ list->addItem(config_olsc2.create_list_item("olsc_15.0.0-18.1.0"));
+ list->addItem(config_olsc3.create_list_item("olsc_19.0.0+"));
+
+ list->addItem(new tsl::elm::CategoryHeader("NIFM - 010000000000000F"));
+ list->addItem(config_ctest1.create_list_item("ctest_1.0.0-19.0.1"));
+ list->addItem(config_ctest2.create_list_item("ctest_20.0.0+"));
+
+ list->addItem(new tsl::elm::CategoryHeader("NIM - 0100000000000025"));
+ list->addItem(config_nim1.create_list_item("blankcal0crashfix_17.0.0+"));
+ list->addItem(config_nim_fw1.create_list_item("blockfirmwareupdates_1.0.0-5.1.0"));
+ list->addItem(config_nim_fw2.create_list_item("blockfirmwareupdates_6.0.0-6.2.0"));
+ list->addItem(config_nim_fw3.create_list_item("blockfirmwareupdates_7.0.0-11.0.1"));
+ list->addItem(config_nim_fw4.create_list_item("blockfirmwareupdates_12.0.0+"));
+
+ frame->setContent(list);
+ return frame;
+ }
+
+ ConfigEntry config_noacidsigchk1{"fs", "noacidsigchk_1.0.0-9.2.0", true};
+ ConfigEntry config_noacidsigchk2{"fs", "noacidsigchk_1.0.0-9.2.0", true};
+ ConfigEntry config_noncasigchk1{"fs", "noncasigchk_10.0.0-16.1.0", true};
+ ConfigEntry config_noncasigchk2{"fs", "noncasigchk_17.0.0+", true};
+ ConfigEntry config_nocntchk1{"fs", "nocntchk_10.0.0-18.1.0", true};
+ ConfigEntry config_nocntchk2{"fs", "nocntchk_19.0.0-20.5.0", true};
+ ConfigEntry config_nocntchk3{"fs", "nocntchk_21.0.0+", true};
+ ConfigEntry config_noacidsigchk3{"ldr", "noacidsigchk_10.0.0+", true};
+ ConfigEntry config_no_erpt{"erpt", "no_erpt", true};
+ ConfigEntry config_es1{"es", "es_1.0.0-8.1.1", true};
+ ConfigEntry config_es2{"es", "es_9.0.0-11.0.1", true};
+ ConfigEntry config_es3{"es", "es_12.0.0-18.1.0", true};
+ ConfigEntry config_es4{"es", "es_19.0.0+", true};
+ ConfigEntry config_olsc1{"olsc", "olsc_6.0.0-14.1.2", true};
+ ConfigEntry config_olsc2{"olsc", "olsc_15.0.0-18.1.0", true};
+ ConfigEntry config_olsc3{"olsc", "olsc_19.0.0+", true};
+ ConfigEntry config_ctest1{"nifm", "ctest_1.0.0-19.0.1", true};
+ ConfigEntry config_ctest2{"nifm", "ctest_20.0.0+", true};
+ ConfigEntry config_nim1{"nim", "blankcal0crashfix_17.0.0+", true};
+ ConfigEntry config_nim_fw1{"nim", "blockfirmwareupdates_1.0.0-5.1.0", true};
+ ConfigEntry config_nim_fw2{"nim", "blockfirmwareupdates_6.0.0-6.2.0", true};
+ ConfigEntry config_nim_fw3{"nim", "blockfirmwareupdates_7.0.0-11.0.1", true};
+ ConfigEntry config_nim_fw4{"nim", "blockfirmwareupdates_12.0.0+", true};
+};
+
+class GuiLog final : public tsl::Gui {
+public:
+ GuiLog() { }
+
+ tsl::elm::Element* createUI() override {
+ auto frame = new tsl::elm::OverlayFrame("sys-patch", VERSION_WITH_HASH);
+ auto list = new tsl::elm::List();
+
if (does_file_exist(LOG_PATH)) {
struct CallbackUser {
tsl::elm::List* list;
@@ -119,7 +203,7 @@ class GuiMain final : public tsl::Gui {
} else {
user->list->addItem(new tsl::elm::ListItem(Key, "Patched", colour_file));
}
- } else if (value.starts_with("Unpatched")) {
+ } else if (value.starts_with("Unpatched") || value.starts_with("Disabled")) {
user->list->addItem(new tsl::elm::ListItem(Key, Value, colour_unpatched));
} else if (user->last_section == "stats") {
user->list->addItem(new tsl::elm::ListItem(Key, Value, tsl::style::color::ColorDescription));
@@ -130,17 +214,58 @@ class GuiMain final : public tsl::Gui {
return 1;
}, &callback_userdata, LOG_PATH);
} else {
-
+ list->addItem(new tsl::elm::ListItem("No log found!"));
}
frame->setContent(list);
return frame;
}
+};
- ConfigEntry config_patch_sysmmc{"options", "patch_sysmmc", true};
- ConfigEntry config_patch_emummc{"options", "patch_emummc", true};
- ConfigEntry config_logging{"options", "patch_logging", true};
- ConfigEntry config_version_skip{"options", "version_skip", true};
+class GuiMain final : public tsl::Gui {
+public:
+ GuiMain() { }
+
+ tsl::elm::Element* createUI() override {
+ auto frame = new tsl::elm::OverlayFrame("sys-patch", VERSION_WITH_HASH);
+ auto list = new tsl::elm::List();
+
+ auto options = new tsl::elm::ListItem("Options");
+ auto toggle = new tsl::elm::ListItem("Toggle patches");
+ auto log = new tsl::elm::ListItem("Log");
+
+ options->setClickListener([](u64 keys) -> bool {
+ if (keys & HidNpadButton_A) {
+ tsl::changeTo