add more logging, pattern version skipping, min/max fs pattern versions

This commit is contained in:
TotalJustice 2023-05-25 17:05:10 +01:00
parent 7d2a332bdd
commit 8a40559685
6 changed files with 192 additions and 30 deletions

View File

@ -1,6 +1,34 @@
MAKEFILES := sysmod overlay
TARGETS := $(foreach dir,$(MAKEFILES),$(CURDIR)/$(dir))
# the below was taken from atmosphere + switch-examples makefile
export VERSION := 1.3.0
export GIT_BRANCH := $(shell git symbolic-ref --short HEAD)
ifeq ($(strip $(shell git status --porcelain 2>/dev/null)),)
export GIT_REVISION := $(GIT_BRANCH)-$(shell git rev-parse --short HEAD)
export VERSION_DIRTY := $(VERSION)
export VERSION_WITH_HASH := $(VERSION)-$(shell git rev-parse --short HEAD)
else
export GIT_REVISION := $(GIT_BRANCH)-$(shell git rev-parse --short HEAD)-dirty
export VERSION_DIRTY := $(VERSION)-dirty
export VERSION_WITH_HASH := $(VERSION)-$(shell git rev-parse --short HEAD)-dirty
endif
export BUILD_DATE := -DDATE_YEAR=\"$(shell date +%Y)\" \
-DDATE_MONTH=\"$(shell date +%m)\" \
-DDATE_DAY=\"$(shell date +%d)\" \
-DDATE_HOUR=\"$(shell date +%H)\" \
-DDATE_MIN=\"$(shell date +%M)\" \
-DDATE_SEC=\"$(shell date +%S)\" \
export CUSTOM_DEFINES := -DVERSION=\"v$(VERSION)\" \
-DGIT_BRANCH=\"$(GIT_BRANCH)\" \
-DGIT_REVISION=\"$(GIT_REVISION)\" \
-DVERSION_DIRTY=\"$(VERSION_DIRTY)\" \
-DVERSION_WITH_HASH=\"$(VERSION_WITH_HASH)\" \
$(BUILD_DATE)
all: $(TARGETS)
@mkdir -p out/
@cp -R sysmod/out/* out/

View File

@ -15,6 +15,7 @@ the config file can be found in `/config/sys-patch/config.ini`, if the file does
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.inim 0=no log
version_skip=1 ; 1=(default) skips out of date patterns, 0=search all patterns
```
---

View File

@ -39,7 +39,7 @@ include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
APP_TITLE := sys-patch
APP_AUTHOR := TotalJustice
APP_VERSION := 1.2.0
APP_VERSION := $(VERSION_DIRTY)
TARGET := sys-patch-overlay
BUILD := build
@ -55,7 +55,7 @@ NO_ICON := 1
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
$(ARCH) $(DEFINES) $(CUSTOM_DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__

View File

@ -1,4 +1,5 @@
#define TESLA_INIT_IMPL // If you have more than one file using the tesla header, only define this in the main one
#define STBTT_STATIC
#include <tesla.hpp> // The Tesla Header
#include <string_view>
#include "minIni/minIni.h"
@ -76,14 +77,16 @@ public:
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", "v1.2.0");
auto frame = new tsl::elm::OverlayFrame("sys-patch", VERSION_WITH_HASH);
auto list = new tsl::elm::List();
list->addItem(new tsl::elm::CategoryHeader("Options"));
list->addItem(config_patch_sysmmc.create_list_item("Patch SysMMC"));
list->addItem(config_patch_emummc.create_list_item("Patch EmuMMC"));
list->addItem(config_patch_sysmmc.create_list_item("Patch sysMMC"));
list->addItem(config_patch_emummc.create_list_item("Patch emuMMC"));
list->addItem(config_logging.create_list_item("Logging"));
list->addItem(config_version_skip.create_list_item("Version skip"));
if (does_file_exist(LOG_PATH)) {
struct CallbackUser {
@ -93,7 +96,9 @@ public:
ini_browse([](const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData){
auto user = (CallbackUser*)UserData;
if (!std::strcmp("Skipped", Value)) {
std::string_view value{Value};
if (value == "Skipped") {
return 1;
}
@ -108,7 +113,6 @@ public:
constexpr tsl::Color colour_unpatched{F(250), F(90), F(58), F(255)};
#undef F
std::string_view value{Value};
if (value.starts_with("Patched")) {
if (value.ends_with("(sys-patch)")) {
user->list->addItem(new tsl::elm::ListItem(Key, "Patched", colour_syspatch));
@ -117,6 +121,10 @@ public:
}
} else if (value.starts_with("Unpatched")) {
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));
} else {
user->list->addItem(new tsl::elm::ListItem(Key, Value, tsl::style::color::ColorText));
}
return 1;
@ -132,6 +140,7 @@ public:
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};
};
// libtesla already initialized fs, hid, pl, pmdmnt, hid:sys and set:sys

View File

@ -51,7 +51,7 @@ INCLUDES := include ../common
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
$(ARCH) $(DEFINES) $(CUSTOM_DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__

View File

@ -1,20 +1,24 @@
#include <cstring>
#include <span>
#include <algorithm> // for min
#include <bit> // for byteswap
#include <algorithm> // for std::min
#include <bit> // for std::byteswap
#include <utility> // std::unreachable
#include <switch.h>
#include "minIni/minIni.h"
namespace {
constexpr u64 INNER_HEAP_SIZE = 0x4000; // Size of the inner heap (adjust as necessary).
constexpr u64 READ_BUFFER_SIZE = 0x1000; // size of buffer which memory is read into
constexpr u64 INNER_HEAP_SIZE = 0x1000; // Size of the inner heap (adjust as necessary).
constexpr u64 READ_BUFFER_SIZE = 0x1000; // size of static buffer which memory is read into
constexpr u32 FW_VER_ANY = 0x0;
constexpr u16 REGEX_SKIP = 0x100;
u32 FW_VERSION{}; // set on startup
u32 AMS_VERSION{}; // set on startup
u32 AMS_TARGET_VERSION{}; // set on startup
u8 AMS_KEYGEN{}; // set on startup
u64 AMS_HASH{}; // set on startup
bool VERSION_SKIP{}; // set on startup
struct DebugEventInfo {
u32 event_type;
@ -201,12 +205,12 @@ constexpr auto mov0_applied(u32 inst) -> bool {
}
constinit Patterns fs_patterns[] = {
{ "noacidsigchk1", "0xC8FE4739", -24, 0, bl_cond, ret0_patch, ret0_applied },
{ "noacidsigchk2", "0x0210911F000072", -5, 0, bl_cond, ret0_patch, ret0_applied },
{ "noncasigchk_old", "0x1E42B9", -5, 0, tbz_cond, nop_patch, nop_applied },
{ "noncasigchk_new", "0x3E4479", -5, 0, tbz_cond, nop_patch, nop_applied },
{ "nocntchk_old", "0x081C00121F05007181000054", -4, 0, bl_cond, ret0_patch, ret0_applied },
{ "nocntchk_new", "0x081C00121F05007141010054", -4, 0, bl_cond, ret0_patch, ret0_applied },
{ "noacidsigchk1", "0xC8FE4739", -24, 0, bl_cond, ret0_patch, ret0_applied, FW_VER_ANY, MAKEHOSVERSION(9,2,0) },
{ "noacidsigchk2", "0x0210911F000072", -5, 0, bl_cond, ret0_patch, ret0_applied, FW_VER_ANY, MAKEHOSVERSION(9,2,0) },
{ "noncasigchk_old", "0x1E42B9", -5, 0, tbz_cond, nop_patch, nop_applied, MAKEHOSVERSION(10,0,0), MAKEHOSVERSION(14,2,1) },
{ "noncasigchk_new", "0x3E4479", -5, 0, tbz_cond, nop_patch, nop_applied, MAKEHOSVERSION(15,0,0) },
{ "nocntchk_old", "0x081C00121F05007181000054", -4, 0, bl_cond, ret0_patch, ret0_applied, MAKEHOSVERSION(10,0,0), MAKEHOSVERSION(14,2,1) },
{ "nocntchk_new", "0x081C00121F05007141010054", -4, 0, bl_cond, ret0_patch, ret0_applied, MAKEHOSVERSION(15,0,0) },
};
constinit Patterns ldr_patterns[] = {
@ -251,13 +255,14 @@ auto is_emummc() -> bool {
return (paths.unk[0] != '\0') || (paths.nintendo[0] != '\0');
}
auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patterns> patterns) -> bool {
void patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patterns> patterns) {
for (auto& p : patterns) {
// skip if version isn't valid
if ((p.min_fw_ver && p.min_fw_ver > FW_VERSION) ||
if (VERSION_SKIP &&
((p.min_fw_ver && p.min_fw_ver > FW_VERSION) ||
(p.max_fw_ver && p.max_fw_ver < FW_VERSION) ||
(p.min_ams_ver && p.min_ams_ver > AMS_VERSION) ||
(p.max_ams_ver && p.max_ams_ver < AMS_VERSION)) {
(p.max_ams_ver && p.max_ams_ver < AMS_VERSION))) {
p.result = PatchedResult::SKIPPED;
continue;
}
@ -267,10 +272,6 @@ auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patter
continue;
}
if (p.byte_pattern.size >= data.size()) {
continue;
}
for (u32 i = 0; i < data.size(); i++) {
if (i + p.byte_pattern.size >= data.size()) {
break;
@ -314,8 +315,6 @@ auto patcher(Handle handle, std::span<const u8> data, u64 addr, std::span<Patter
}
}
}
return false;
}
auto apply_patch(PatchEntry& patch) -> bool {
@ -327,8 +326,9 @@ auto apply_patch(PatchEntry& patch) -> bool {
static u8 buffer[READ_BUFFER_SIZE];
// skip if version isn't valid
if ((patch.min_fw_ver && patch.min_fw_ver > FW_VERSION) ||
(patch.max_fw_ver && patch.max_fw_ver < FW_VERSION)) {
if (VERSION_SKIP &&
((patch.min_fw_ver && patch.min_fw_ver > FW_VERSION) ||
(patch.max_fw_ver && patch.max_fw_ver < FW_VERSION))) {
for (auto& p : patch.patterns) {
p.result = PatchedResult::SKIPPED;
}
@ -422,6 +422,81 @@ auto patch_result_to_str(PatchedResult result) -> const char* {
std::unreachable();
}
void num_2_str(char*& s, u16 num) {
u16 max_v = 1000;
if (num > 9) {
while (max_v >= 10) {
if (num >= max_v) {
while (max_v != 1) {
*s++ = '0' + (num / max_v);
num -= (num / max_v) * max_v;
max_v /= 10;
}
} else {
max_v /= 10;
}
}
}
*s++ = '0' + (num); // always add 0 or 1's
}
void ms_2_str(char* s, u32 num) {
u32 max_v = 100;
*s++ = '0' + (num / 1000); // add seconds
num -= (num / 1000) * 1000;
*s++ = '.';
while (max_v >= 10) {
if (num >= max_v) {
while (max_v != 1) {
*s++ = '0' + (num / max_v);
num -= (num / max_v) * max_v;
max_v /= 10;
}
}
else {
*s++ = '0'; // append 0
max_v /= 10;
}
}
*s++ = '0' + (num); // always add 0 or 1's
*s++ = 's'; // in seconds
}
// eg, 852481 -> 13.2.1
void version_to_str(char* s, u32 ver) {
for (int i = 0; i < 3; i++) {
num_2_str(s, (ver >> 16) & 0xFF);
if (i != 2) {
*s++ = '.';
}
ver <<= 8;
}
}
// eg, 0xAF66FF99 -> AF66FF99
void hash_to_str(char* s, u32 hash) {
for (int i = 0; i < 4; i++) {
const auto num = (hash >> 24) & 0xFF;
const auto top = (num >> 4) & 0xF;
const auto bottom = (num >> 0) & 0xF;
constexpr auto a = [](u8 nib) -> char {
if (nib >= 0 && nib <= 9) { return '0' + nib; }
return 'a' + nib - 10;
};
*s++ = a(top);
*s++ = a(bottom);
hash <<= 8;
}
}
void keygen_to_str(char* s, u8 keygen) {
num_2_str(s, keygen);
}
} // namespace
int main(int argc, char* argv[]) {
@ -435,6 +510,7 @@ int main(int argc, char* argv[]) {
const auto patch_sysmmc = ini_load_or_write_default("options", "patch_sysmmc", 1, ini_path);
const auto patch_emummc = ini_load_or_write_default("options", "patch_emummc", 1, ini_path);
const auto enable_logging = ini_load_or_write_default("options", "enable_logging", 1, ini_path);
VERSION_SKIP = ini_load_or_write_default("options", "version_skip", 1, ini_path);
const auto emummc = is_emummc();
bool enable_patching = true;
@ -448,12 +524,18 @@ int main(int argc, char* argv[]) {
enable_patching = false;
}
// speedtest
const auto ticks_start = armGetSystemTick();
if (enable_patching) {
for (auto& patch : patches) {
apply_patch(patch);
}
}
const auto ticks_end = armGetSystemTick();
const auto diff_ns = armTicksToNs(ticks_end) - armTicksToNs(ticks_start);
if (enable_logging) {
for (auto& patch : patches) {
for (auto& p : patch.patterns) {
@ -463,6 +545,41 @@ int main(int argc, char* argv[]) {
ini_puts(patch.name, p.patch_name, patch_result_to_str(p.result), log_path);
}
}
// fw of the system
char fw_version[12]{};
// atmosphere version
char ams_version[12]{};
// lowest fw supported by atmosphere
char ams_target_version[12]{};
// ???
char ams_keygen[3]{};
// git commit hash
char ams_hash[9]{};
// how long it took to patch
char patch_time[20]{};
version_to_str(fw_version, FW_VERSION);
version_to_str(ams_version, AMS_VERSION);
version_to_str(ams_target_version, AMS_TARGET_VERSION);
keygen_to_str(ams_keygen, AMS_KEYGEN);
hash_to_str(ams_hash, AMS_HASH >> 32);
ms_2_str(patch_time, diff_ns/1000ULL/1000ULL);
// defined in the Makefile
#define DATE (DATE_DAY "." DATE_MONTH "." DATE_YEAR " " DATE_HOUR ":" DATE_MIN ":" DATE_SEC)
ini_puts("stats", "version", VERSION_WITH_HASH, log_path);
ini_puts("stats", "build_date", DATE, log_path);
ini_puts("stats", "fw_version", fw_version, log_path);
ini_puts("stats", "ams_version", ams_version, log_path);
ini_puts("stats", "ams_target_version", ams_target_version, log_path);
ini_puts("stats", "ams_keygen", ams_keygen, log_path);
ini_puts("stats", "ams_hash", ams_hash, log_path);
ini_putl("stats", "is_emummc", emummc, log_path);
ini_putl("stats", "heap_size", INNER_HEAP_SIZE, log_path);
ini_putl("stats", "buffer_size", READ_BUFFER_SIZE, log_path);
ini_puts("stats", "patch_time", patch_time, log_path);
}
// note: sysmod exits here.
@ -511,9 +628,16 @@ void __appInit(void) {
// get ams version
if (R_SUCCEEDED(rc = splInitialize())) {
u64 v{};
u64 hash{};
if (R_SUCCEEDED(rc = splGetConfig((SplConfigItem)65000, &v))) {
AMS_VERSION = (v >> 16) & 0xFFFFFF;
AMS_VERSION = (v >> 40) & 0xFFFFFF;
AMS_KEYGEN = (v >> 32) & 0xFF;
AMS_TARGET_VERSION = v & 0xFFFFFF;
}
if (R_SUCCEEDED(rc = splGetConfig((SplConfigItem)65003, &hash))) {
AMS_HASH = hash;
}
splExit();
}