From f62d3e7fb6fb1a725e0209df3457608054c3c972 Mon Sep 17 00:00:00 2001 From: SaSukiTB Date: Tue, 4 Feb 2025 18:57:51 +0100 Subject: [PATCH 1/3] Automate seed data cleanup on exit Implemented std::atexit() to automatically delete seed-related files and registry entries when the program exits, preventing the accumulation of unused seed data over time. --- auth.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/auth.cpp b/auth.cpp index abedaef..a2ff6fe 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 seed; +void cleanUpSeedData(const std::string& seed); std::string signature; std::string signatureTimestamp; bool initialized; @@ -82,8 +83,8 @@ bool KeyAuth::api::debug = false; void KeyAuth::api::init() { CreateThread(0, 0, (LPTHREAD_START_ROUTINE)runChecks, 0, 0, 0); - std::string random_num = generate_random_number(); - seed = random_num; + seed = generate_random_number(); + std::atexit([]() { cleanUpSeedData(seed); }); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)modify, 0, 0, 0); if (ownerid.length() != 10) @@ -2081,3 +2082,17 @@ void modify() Sleep(50); } } + +// Clean up seed data (file and registry key) +void cleanUpSeedData(const std::string& seed) { + + // Clean up the seed file + std::string file_path = "C:\\ProgramData\\" + seed; + if (std::filesystem::exists(file_path)) { + std::filesystem::remove(file_path); + } + + // Clean up the seed registry entry + std::string regPath = "Software\\" + seed; + RegDeleteKeyA(HKEY_CURRENT_USER, regPath.c_str()); +} From e13dbdc8aaad2af2fae335ab21b84ff0221d5e25 Mon Sep 17 00:00:00 2001 From: SaSukiTB Date: Tue, 4 Feb 2025 21:36:12 +0100 Subject: [PATCH 2/3] Fix registry check loop and ensure periodic checking Moved the Sleep interval inside the loop in checkRegistry() to ensure the registry key is checked periodically. Previously, the Sleep call was outside the loop, causing the check to run only once. Now, the function checks the registry at regular intervals and exits if the key is not found. --- auth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth.cpp b/auth.cpp index a2ff6fe..5605fe9 100644 --- a/auth.cpp +++ b/auth.cpp @@ -1846,8 +1846,8 @@ void checkRegistry() { LI_FN(__fastfail)(0); } LI_FN(RegCloseKey)(hKey); + Sleep(1500); // thread interval } - Sleep(1500); // thread interval } std::string checksum() From 6f334176dd428675849f478da542f57124944943 Mon Sep 17 00:00:00 2001 From: SaSukiTB Date: Wed, 5 Feb 2025 14:58:43 +0100 Subject: [PATCH 3/3] Refactor threads for concurrent execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the init() function, you create a thread, which runs runChecks this function, in turn, calls checkAtoms, checkFiles, and checkRegistry in sequence. so checkAtoms, checkFiles, and checkRegistry are called from both init() (within runChecks) and license (as individual threads). now you will get Multiple threads running the same functions, you are calling the same functions (checkAtoms, checkFiles, and checkRegistry) twice in parallel once from runChecks (which is called in init()) and once from license(), this leads to multiple threads working on the same task, potentially doing redundant work and introducing unnecessary complexity and overhead. it will consume more system resources (CPU, memory) than necessary. One more thing when you call runChecks from the init() function, it first calls checkAtoms, then checkFiles, and finally checkRegistry. the key point here is that runChecks doesn't return until checkAtoms finishes its work, since checkAtoms has an infinite loop (while(true)) it will never return control to runChecks, you are checking only for GlobalFindAtomA, which mean GetFileAttributesA and RegOpenKeyExA will never be called until you return from checkAtoms. One solution would be to move each of the checkAtoms, checkFiles, and checkRegistry functions into separate threads so they run concurrently, instead of running one after the other in runChecks, and no need to call them again in License() function since they gonna keep working till the program exit I Added a simple mechanism to interrupt the sleep if the user logs in before the 45 seconds have passed, the function waits in a loop, checking every second if the user has logged in, if the user logs in before the 45s timeout, the loop breaks, and the checks begin. if the user hasn’t logged in by the time the 45s pass, it simply proceeds with the checks. --- auth.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/auth.cpp b/auth.cpp index 5605fe9..f47567f 100644 --- a/auth.cpp +++ b/auth.cpp @@ -79,10 +79,11 @@ std::string signatureTimestamp; bool initialized; std::string API_PUBLIC_KEY = "5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b"; bool KeyAuth::api::debug = false; +std::atomic LoggedIn(false); void KeyAuth::api::init() { - CreateThread(0, 0, (LPTHREAD_START_ROUTINE)runChecks, 0, 0, 0); + std::thread(runChecks).detach(); seed = generate_random_number(); std::atexit([]() { cleanUpSeedData(seed); }); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)modify, 0, 0, 0); @@ -294,6 +295,7 @@ void KeyAuth::api::login(std::string username, std::string password, std::string } LI_FN(GlobalAddAtomA)(ownerid.c_str()); + LoggedIn.store(true); } else { LI_FN(exit)(12); @@ -742,6 +744,7 @@ void KeyAuth::api::web_login() } LI_FN(GlobalAddAtomA)(ownerid.c_str()); + LoggedIn.store(true); } else { LI_FN(exit)(12); @@ -990,6 +993,7 @@ void KeyAuth::api::regstr(std::string username, std::string password, std::strin } LI_FN(GlobalAddAtomA)(ownerid.c_str()); + LoggedIn.store(true); } else { LI_FN(exit)(12); @@ -1062,11 +1066,6 @@ std::string generate_random_number() { } void KeyAuth::api::license(std::string key, std::string code) { - // Call threads to start in 15 seconds.. - CreateThread(0, 0, (LPTHREAD_START_ROUTINE)checkAtoms, 0, 0, 0); - CreateThread(0, 0, (LPTHREAD_START_ROUTINE)checkFiles, 0, 0, 0); - CreateThread(0, 0, (LPTHREAD_START_ROUTINE)checkRegistry, 0, 0, 0); - checkInit(); std::string hwid = utils::get_hwid(); @@ -1120,6 +1119,7 @@ void KeyAuth::api::license(std::string key, std::string code) { } LI_FN(GlobalAddAtomA)(ownerid.c_str()); + LoggedIn.store(true); } else { LI_FN(exit)(12); @@ -1801,15 +1801,25 @@ auto check_section_integrity( const char *section_name, bool fix = false ) -> bo } void runChecks() { - Sleep(45000); // give people 1 minute to login. (because the functions we call already wait 15 seconds) - - checkAtoms(); - checkFiles(); - checkRegistry(); + // Wait before starting checks + int waitTime = 45000; + while (waitTime > 0) { + + if (LoggedIn.load()) { + // If the user is logged in, proceed with the checks immediately + break; + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + waitTime -= 1000; + } + + // Create separate threads for each check + std::thread(checkAtoms).detach(); + std::thread(checkFiles).detach(); + std::thread(checkRegistry).detach(); } void checkAtoms() { - Sleep(15000); // enough time for API response, even on slower connections while (true) { if (LI_FN(GlobalFindAtomA)(seed.c_str()) == 0) { @@ -1821,7 +1831,6 @@ void checkAtoms() { } void checkFiles() { - Sleep(15000); // enough time for API response, even on slower connections while (true) { std::string file_path = XorStr("C:\\ProgramData\\").c_str() + seed; @@ -1835,8 +1844,7 @@ void checkFiles() { } void checkRegistry() { - Sleep(15000); // enough time for API response, even on slower connections - + while (true) { std::string regPath = XorStr("Software\\").c_str() + seed; HKEY hKey;