From f3da3fa850f611bfad987443aea052d20c748e0e Mon Sep 17 00:00:00 2001 From: ELF-Nigel Date: Sat, 28 Feb 2026 18:34:47 -0500 Subject: [PATCH 1/5] Harden parsing and curl escaping --- auth.cpp | 39 ++++++++++++++++++++++++++++++++------- auth.hpp | 4 ++-- utils.cpp | 8 +++++--- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/auth.cpp b/auth.cpp index 90fd644..10b123a 100644 --- a/auth.cpp +++ b/auth.cpp @@ -72,6 +72,7 @@ void checkFiles(); void checkRegistry(); void error(std::string message); std::string generate_random_number(); +std::string curl_escape(CURL* curl, const std::string& input); std::string seed; void cleanUpSeedData(const std::string& seed); std::string signature; @@ -100,7 +101,7 @@ void KeyAuth::api::init() XorStr("type=init") + XorStr("&ver=") + version + XorStr("&hash=") + hash + - XorStr("&name=") + curl_easy_escape(curl, name.c_str(), 0) + + XorStr("&name=") + curl_escape(curl, name) + XorStr("&ownerid=") + ownerid; // to ensure people removed secret from main.cpp (some people will forget to) @@ -1421,8 +1422,8 @@ std::string KeyAuth::api::webhook(std::string id, std::string params, std::strin auto data = XorStr("type=webhook") + XorStr("&webid=") + id + - XorStr("¶ms=") + curl_easy_escape(curl, params.c_str(), 0) + - XorStr("&body=") + curl_easy_escape(curl, body.c_str(), 0) + + XorStr("¶ms=") + curl_escape(curl, params) + + XorStr("&body=") + curl_escape(curl, body) + XorStr("&conttype=") + contenttype + XorStr("&sessionid=") + sessionid + XorStr("&name=") + name + @@ -1601,7 +1602,15 @@ void KeyAuth::api::logout() { int VerifyPayload(std::string signature, std::string timestamp, std::string body) { - long long unix_timestamp = std::stoll(timestamp); + long long unix_timestamp = 0; + try { + unix_timestamp = std::stoll(timestamp); + } + catch (...) { + std::cerr << "[ERROR] Invalid timestamp format\n"; + MessageBoxA(0, "Signature verification failed (invalid timestamp)", "KeyAuth", MB_ICONERROR); + exit(2); + } auto current_time = std::chrono::system_clock::now(); long long current_unix_time = std::chrono::duration_cast( @@ -1678,14 +1687,30 @@ std::string get_str_between_two_str(const std::string& s, const std::string& start_delim, const std::string& stop_delim) { - unsigned first_delim_pos = s.find(start_delim); - unsigned end_pos_of_first_delim = first_delim_pos + start_delim.length(); - unsigned last_delim_pos = s.find(stop_delim); + const auto first_delim_pos = s.find(start_delim); + if (first_delim_pos == std::string::npos) + return {}; + const auto end_pos_of_first_delim = first_delim_pos + start_delim.length(); + const auto last_delim_pos = s.find(stop_delim, end_pos_of_first_delim); + if (last_delim_pos == std::string::npos || last_delim_pos < end_pos_of_first_delim) + return {}; return s.substr(end_pos_of_first_delim, last_delim_pos - end_pos_of_first_delim); } +std::string curl_escape(CURL* curl, const std::string& input) +{ + if (!curl) + return input; + char* escaped = curl_easy_escape(curl, input.c_str(), 0); + if (!escaped) + return {}; + std::string out(escaped); + curl_free(escaped); + return out; +} + void KeyAuth::api::setDebug(bool value) { KeyAuth::api::debug = value; } diff --git a/auth.hpp b/auth.hpp index f229460..df3abe4 100644 --- a/auth.hpp +++ b/auth.hpp @@ -124,7 +124,7 @@ namespace KeyAuth { api::user_data.createdate = data[XorStr("createdate")]; api::user_data.lastlogin = data[XorStr("lastlogin")]; - for (int i = 0; i < data[XorStr("subscriptions")].size(); i++) { // Prompto#7895 & stars#2297 was here + for (size_t i = 0; i < data[XorStr("subscriptions")].size(); i++) { // Prompto#7895 & stars#2297 was here subscriptions_class subscriptions; subscriptions.name = data[XorStr("subscriptions")][i][XorStr("subscription")]; subscriptions.expiry = data[XorStr("subscriptions")][i][XorStr("expiry")]; @@ -153,7 +153,7 @@ namespace KeyAuth { api::response.success = data["success"]; // intentional. Possibly trick a reverse engineer into thinking this string is for login function api::response.message = data["message"]; api::response.channeldata.clear(); //If you do not delete the data before pushing it, the data will be repeated. github.com/TTakaTit - for (const auto sub : data["messages"]) { + for (const auto& sub : data["messages"]) { std::string authoroutput = sub[XorStr("author")]; std::string messageoutput = sub["message"]; diff --git a/utils.cpp b/utils.cpp index 0b09151..221e5cc 100644 --- a/utils.cpp +++ b/utils.cpp @@ -12,9 +12,11 @@ std::string utils::get_hwid() { } std::time_t utils::string_to_timet(std::string timestamp) { - auto cv = strtol(timestamp.c_str(), NULL, 10); - - return (time_t)cv; + char* end = nullptr; + auto cv = strtol(timestamp.c_str(), &end, 10); + if (end == timestamp.c_str()) + return 0; + return static_cast(cv); } std::tm utils::timet_to_tm(time_t timestamp) { From 74bf34af9dec8608794887556119b71415581025 Mon Sep 17 00:00:00 2001 From: ELF-Nigel Date: Sat, 28 Feb 2026 18:40:05 -0500 Subject: [PATCH 2/5] Add periodic integrity check --- auth.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/auth.cpp b/auth.cpp index 10b123a..da2b4e3 100644 --- a/auth.cpp +++ b/auth.cpp @@ -73,6 +73,7 @@ void checkRegistry(); void error(std::string message); std::string generate_random_number(); std::string curl_escape(CURL* curl, const std::string& input); +auto check_section_integrity( const char *section_name, bool fix ) -> bool; std::string seed; void cleanUpSeedData(const std::string& seed); std::string signature; @@ -81,6 +82,7 @@ bool initialized; std::string API_PUBLIC_KEY = "5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b"; bool KeyAuth::api::debug = false; std::atomic LoggedIn(false); +std::atomic last_integrity_check{ 0 }; void KeyAuth::api::init() { @@ -2084,6 +2086,15 @@ void checkInit() { if (!initialized) { error(XorStr("You need to run the KeyAuthApp.init(); function before any other KeyAuth functions")); } + const auto now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); + const auto last = last_integrity_check.load(); + if (now - last > 30) { + last_integrity_check.store(now); + if (check_section_integrity(XorStr(".text").c_str(), false)) { + error(XorStr("check_section_integrity() failed, don't tamper with the program.")); + } + } } // code submitted in pull request from https://github.com/BINM7MD BOOL bDataCompare(const BYTE* pData, const BYTE* bMask, const char* szMask) From aea56e35dbe3c5a79499d6200cdbec2edf9f940c Mon Sep 17 00:00:00 2001 From: ELF-Nigel Date: Sat, 28 Feb 2026 18:44:49 -0500 Subject: [PATCH 3/5] Add redundant integrity checks --- auth.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/auth.cpp b/auth.cpp index da2b4e3..054086b 100644 --- a/auth.cpp +++ b/auth.cpp @@ -74,6 +74,8 @@ void error(std::string message); std::string generate_random_number(); std::string curl_escape(CURL* curl, const std::string& input); auto check_section_integrity( const char *section_name, bool fix ) -> bool; +void integrity_check(); +void integrity_watchdog(); std::string seed; void cleanUpSeedData(const std::string& seed); std::string signature; @@ -87,6 +89,7 @@ std::atomic last_integrity_check{ 0 }; void KeyAuth::api::init() { std::thread(runChecks).detach(); + std::thread(integrity_watchdog).detach(); seed = generate_random_number(); std::atexit([]() { cleanUpSeedData(seed); }); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)modify, 0, 0, 0); @@ -1604,6 +1607,7 @@ void KeyAuth::api::logout() { int VerifyPayload(std::string signature, std::string timestamp, std::string body) { + integrity_check(); long long unix_timestamp = 0; try { unix_timestamp = std::stoll(timestamp); @@ -1720,6 +1724,7 @@ void KeyAuth::api::setDebug(bool value) { std::string KeyAuth::api::req(const std::string& data, const std::string& url) { signature.clear(); signatureTimestamp.clear(); + integrity_check(); CURL* curl = curl_easy_init(); if (!curl) { @@ -2086,6 +2091,10 @@ void checkInit() { if (!initialized) { error(XorStr("You need to run the KeyAuthApp.init(); function before any other KeyAuth functions")); } + integrity_check(); +} + +void integrity_check() { const auto now = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); const auto last = last_integrity_check.load(); @@ -2096,6 +2105,18 @@ void checkInit() { } } } + +void integrity_watchdog() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution sleep_seconds(20, 50); + while (true) { + Sleep(static_cast(sleep_seconds(gen) * 1000)); + if (check_section_integrity(XorStr(".text").c_str(), false)) { + error(XorStr("check_section_integrity() failed, don't tamper with the program.")); + } + } +} // code submitted in pull request from https://github.com/BINM7MD BOOL bDataCompare(const BYTE* pData, const BYTE* bMask, const char* szMask) { From ca78ab7381619c282b7e5be18ff812846ad7cabd Mon Sep 17 00:00:00 2001 From: ELF-Nigel Date: Sat, 28 Feb 2026 18:45:05 -0500 Subject: [PATCH 4/5] Harden integrity watchdog --- auth.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/auth.cpp b/auth.cpp index 054086b..1a708b2 100644 --- a/auth.cpp +++ b/auth.cpp @@ -85,6 +85,7 @@ std::string API_PUBLIC_KEY = "5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d bool KeyAuth::api::debug = false; std::atomic LoggedIn(false); std::atomic last_integrity_check{ 0 }; +std::atomic integrity_fail_streak{ 0 }; void KeyAuth::api::init() { @@ -2112,8 +2113,15 @@ void integrity_watchdog() { std::uniform_int_distribution sleep_seconds(20, 50); while (true) { Sleep(static_cast(sleep_seconds(gen) * 1000)); + if (!initialized || !LoggedIn.load()) + continue; if (check_section_integrity(XorStr(".text").c_str(), false)) { - error(XorStr("check_section_integrity() failed, don't tamper with the program.")); + const int streak = integrity_fail_streak.fetch_add(1) + 1; + if (streak >= 2) { + error(XorStr("check_section_integrity() failed, don't tamper with the program.")); + } + } else { + integrity_fail_streak.store(0); } } } From 0a349d27b37bb6fd4bcd1801684b3af8014f3c6e Mon Sep 17 00:00:00 2001 From: ELF-Nigel Date: Sat, 28 Feb 2026 18:48:11 -0500 Subject: [PATCH 5/5] Cleanups and safety hardening --- auth.cpp | 8 +++++++- auth.hpp | 3 +++ killEmulator.hpp | 3 ++- utils.hpp | 4 +++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/auth.cpp b/auth.cpp index 1a708b2..e1aaf62 100644 --- a/auth.cpp +++ b/auth.cpp @@ -109,6 +109,9 @@ void KeyAuth::api::init() XorStr("&hash=") + hash + XorStr("&name=") + curl_escape(curl, name) + XorStr("&ownerid=") + ownerid; + if (curl) { + curl_easy_cleanup(curl); // avoid leak from escape helper. -nigel + } // to ensure people removed secret from main.cpp (some people will forget to) if (path.find("https") != std::string::npos) { @@ -1404,7 +1407,7 @@ std::vector KeyAuth::api::download(std::string fileid) { XorStr("&fileid=") + fileid + XorStr("&sessionid=") + sessionid + XorStr("&name=") + name + - XorStr("&ownerid=").c_str() + ownerid; + XorStr("&ownerid=") + ownerid; auto response = req(data, url); auto json = response_decoder.parse(response); @@ -1761,6 +1764,9 @@ std::string KeyAuth::api::req(const std::string& data, const std::string& url) { } void error(std::string message) { + for (char& c : message) { + if (c == '&' || c == '|' || c == '\"') c = ' '; // minimize cmd injection surface. -nigel + } system((XorStr("start cmd /C \"color b && title Error && echo ").c_str() + message + XorStr(" && timeout /t 5\"")).c_str()); LI_FN(__fastfail)(0); } diff --git a/auth.hpp b/auth.hpp index df3abe4..31e0920 100644 --- a/auth.hpp +++ b/auth.hpp @@ -153,6 +153,9 @@ namespace KeyAuth { api::response.success = data["success"]; // intentional. Possibly trick a reverse engineer into thinking this string is for login function api::response.message = data["message"]; api::response.channeldata.clear(); //If you do not delete the data before pushing it, the data will be repeated. github.com/TTakaTit + if (!data.contains("messages") || !data["messages"].is_array()) { + return; // avoid invalid server payload crash. -nigel + } for (const auto& sub : data["messages"]) { std::string authoroutput = sub[XorStr("author")]; diff --git a/killEmulator.hpp b/killEmulator.hpp index 50c2ddf..d1cdcd3 100644 --- a/killEmulator.hpp +++ b/killEmulator.hpp @@ -1,3 +1,4 @@ +#pragma once #include #include #include @@ -20,7 +21,7 @@ namespace protection MODULEINFO info; // place holder for the information // use this function in order to get the module information. - bool result = GetModuleInformation(reinterpret_cast(-1), + bool result = GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(info)); if (result) { diff --git a/utils.hpp b/utils.hpp index a2e0343..c0cbf91 100644 --- a/utils.hpp +++ b/utils.hpp @@ -1,10 +1,12 @@ #pragma once #include +#include #include +#include namespace utils { std::string get_hwid(); std::time_t string_to_timet(std::string timestamp); std::tm timet_to_tm(time_t timestamp); -} \ No newline at end of file +}