From 917870a19db65d1c319dd67708b48d1e74e347fc Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sat, 10 Jun 2017 20:23:24 +0200
Subject: [PATCH 01/10] [Cache] Re-enable .to domain

---
 src/Utils/Cache.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Utils/Cache.cpp b/src/Utils/Cache.cpp
index efeeb8d7..8b51d856 100644
--- a/src/Utils/Cache.cpp
+++ b/src/Utils/Cache.cpp
@@ -18,7 +18,7 @@ namespace Utils
 
 		// Dead
 		//"https://iw4xcachep26muba.onion.link",
-		//"https://iw4xcachep26muba.onion.to",
+		"https://iw4xcachep26muba.onion.to",
 
 		// Not registered yet
 		//"https://iw4xcachejnetuln.onion.to",

From 7a0261ccbd599b23c73e2eeac1d0ed744c8744a7 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sat, 10 Jun 2017 20:24:42 +0200
Subject: [PATCH 02/10] [AntiCheat] Prevent dll injection

- Hook native LdrLoadDll to prevent injection
- Hook native LdrpLoadDll to prevent injection
- Hook NtCreateThreadEx to log threads created by this process
  and kill remote threads
---
 src/Components/Modules/AntiCheat.cpp | 204 +++++++++++++++++++++++++--
 src/Components/Modules/AntiCheat.hpp |  14 +-
 src/Main.cpp                         |  10 ++
 src/Utils/Utils.cpp                  |  31 ++++
 src/Utils/Utils.hpp                  |   8 +-
 5 files changed, 256 insertions(+), 11 deletions(-)

diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp
index 76195560..a8228db2 100644
--- a/src/Components/Modules/AntiCheat.cpp
+++ b/src/Components/Modules/AntiCheat.cpp
@@ -4,10 +4,15 @@ namespace Components
 {
 	Utils::Time::Interval AntiCheat::LastCheck;
 	std::string AntiCheat::Hash;
-	Utils::Hook AntiCheat::LoadLibHook[4];
+	Utils::Hook AntiCheat::CreateThreadHook;
+	Utils::Hook AntiCheat::LoadLibHook[6];
 	Utils::Hook AntiCheat::VirtualProtectHook[2];
 	unsigned long AntiCheat::Flags = NO_FLAG;
 
+	std::mutex AntiCheat::ThreadMutex;
+	std::vector<DWORD> AntiCheat::OwnThreadIds;
+	std::map<DWORD, std::shared_ptr<Utils::Hook>> AntiCheat::ThreadHookMap;
+
 	// This function does nothing, it only adds the two passed variables and returns the value
 	// The only important thing it does is to clean the first parameter, and then return
 	// By returning, the crash procedure will be called, as it hasn't been cleaned from the stack
@@ -70,9 +75,9 @@ namespace Components
 
 	void AntiCheat::InitLoadLibHook()
 	{
-		static uint8_t kernel32Str[] = {0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93}; // KerNel32.dll
-		static uint8_t loadLibAStr[] = {0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE}; // LoadLibraryA
-		static uint8_t loadLibWStr[] = {0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8}; // LoadLibraryW
+		static uint8_t kernel32Str[] = { 0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93 }; // KerNel32.dll
+		static uint8_t loadLibAStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE }; // LoadLibraryA
+		static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW
 
 		HMODULE kernel32 = GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(kernel32Str), sizeof kernel32Str), -1).data());
 		if (kernel32)
@@ -109,6 +114,26 @@ namespace Components
 #endif
 			}
 		}
+
+		static uint8_t ldrLoadDllStub[] = { 0x33, 0xC0, 0xC2, 0x10, 0x00 };
+		static uint8_t ldrLoadDll[] = { 0xB3, 0x9B, 0x8D, 0xB3, 0x90, 0x9E, 0x9B, 0xBB, 0x93, 0x93 }; // LdrLoadDll
+
+		HMODULE ntdll = Utils::GetNTDLL();
+		AntiCheat::LoadLibHook[4].initialize(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ldrLoadDll), sizeof ldrLoadDll), -1).data()), ldrLoadDllStub, HOOK_JUMP);
+
+		// Patch LdrpLoadDll
+		Utils::Hook::Signature::Container container;
+		container.signature = "\x8B\xFF\x55\x8B\xEC\x83\xE4\xF8\x81\xEC\x00\x00\x00\x00\xA1\x00\x00\x00\x00\x33\xC4\x89\x84\x24\x00\x00\x00\x00\x53\x8B\x5D\x10\x56\x57";
+		container.mask = "xxxxxxxxxx????x????xxxxx????xxxxxx";
+		container.callback = [](char* addr)
+		{
+			static uint8_t ldrpLoadDllStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 };
+			AntiCheat::LoadLibHook[5].initialize(addr, ldrpLoadDllStub, HOOK_JUMP);
+		};
+
+		Utils::Hook::Signature signature(ntdll, Utils::GetModuleSize(ntdll));
+		signature.add(container);
+		signature.process();
 	}
 
 	void AntiCheat::ReadIntegrityCheck()
@@ -254,10 +279,10 @@ namespace Components
 
 	void AntiCheat::InstallLibHook()
 	{
-		AntiCheat::LoadLibHook[0].install();
-		AntiCheat::LoadLibHook[1].install();
-		AntiCheat::LoadLibHook[2].install();
-		AntiCheat::LoadLibHook[3].install();
+		for(int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
+		{
+			AntiCheat::LoadLibHook[i].install();
+		}
 	}
 
 	void AntiCheat::PatchWinAPI()
@@ -389,7 +414,7 @@ namespace Components
 
 	BOOL WINAPI AntiCheat::VirtualProtectExStub(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
 	{
-		if (GetCurrentProcess() == hProcess && !AntiCheat::IsPageChangeAllowed(_ReturnAddress(), lpAddress, dwSize)) return FALSE;
+		if (GetCurrentProcessId() == GetProcessId(hProcess) && !AntiCheat::IsPageChangeAllowed(_ReturnAddress(), lpAddress, dwSize)) return FALSE;
 
 		AntiCheat::VirtualProtectHook[1].uninstall(false);
 		BOOL result = VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
@@ -562,6 +587,164 @@ namespace Components
 		AntiCheat::VirtualProtectHook[0].initialize(vp, AntiCheat::VirtualProtectStub, HOOK_JUMP)->install(true, true);
 	}
 
+	NTSTATUS NTAPI AntiCheat::NtCreateThreadExStub(PHANDLE phThread,ACCESS_MASK desiredAccess,LPVOID objectAttributes,HANDLE processHandle,LPTHREAD_START_ROUTINE startAddress,LPVOID parameter,BOOL createSuspended,DWORD stackZeroBits,DWORD sizeOfStackCommit,DWORD sizeOfStackReserve,LPVOID bytesBuffer)
+	{
+		HANDLE hThread = nullptr;
+		std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
+
+		AntiCheat::CreateThreadHook.uninstall();
+		NTSTATUS result = NtCreateThreadEx_t(AntiCheat::CreateThreadHook.getAddress())(&hThread, desiredAccess, objectAttributes, processHandle, startAddress, parameter, createSuspended, stackZeroBits, sizeOfStackCommit, sizeOfStackReserve, bytesBuffer);
+		AntiCheat::CreateThreadHook.install();
+
+		if (phThread) *phThread = hThread;
+
+		if (GetProcessId(processHandle) == GetCurrentProcessId())
+		{
+			AntiCheat::OwnThreadIds.push_back(GetThreadId(hThread));
+		}
+
+		return result;
+	}
+
+	void AntiCheat::PatchThreadCreation()
+	{
+		HMODULE ntdll = Utils::GetNTDLL();
+		if (ntdll)
+		{
+			static uint8_t ntCreateThreadEx[] = { 0xB1, 0x8B, 0xBC, 0x8D, 0x9A, 0x9E, 0x8B, 0x9A, 0xAB, 0x97, 0x8D, 0x9A, 0x9E, 0x9B, 0xBA, 0x87 }; // NtCreateThreadEx
+			FARPROC createThread = GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ntCreateThreadEx), sizeof ntCreateThreadEx), -1).data());
+			if (createThread)
+			{
+				AntiCheat::CreateThreadHook.initialize(createThread, AntiCheat::NtCreateThreadExStub, HOOK_JUMP)->install();
+			}
+		}
+	}
+
+	int AntiCheat::ValidateThreadTermination(void* addr)
+	{
+		{
+			std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
+
+			DWORD id = GetCurrentThreadId();
+			auto threadHook = AntiCheat::ThreadHookMap.find(id);
+			if (threadHook != AntiCheat::ThreadHookMap.end())
+			{
+				threadHook->second->uninstall(false);
+				AntiCheat::ThreadHookMap.erase(threadHook); // Uninstall and delete the hook
+				return 1; // Kill
+			}
+		}
+
+		while(true)
+		{
+			std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
+
+			// It would be better to wait for the thread
+			// but we don't know if there are multiple hooks at the same address
+			bool found = false;
+			for (auto threadHook : AntiCheat::ThreadHookMap)
+			{
+				if (threadHook.second->getAddress() == addr)
+				{
+					found = true;
+					break;
+				}
+			}
+
+			if (!found) break;
+			std::this_thread::sleep_for(10ms);
+		}
+
+		return 0; // Don't kill
+	}
+
+	__declspec(naked) void AntiCheat::ThreadEntryPointStub()
+	{
+		__asm
+		{
+			push eax
+			push eax
+			pushad
+
+			// Reinitialize the return address
+			mov eax, [esp + 28h]
+			sub eax, 5
+			mov [esp + 28h], eax
+
+			push eax
+			call AntiCheat::ValidateThreadTermination
+			add esp, 4h
+
+			mov [esp + 20h], eax
+
+			popad
+
+			pop eax
+
+			test eax, eax
+			jz dontKill
+
+			pop eax
+			add esp, 4h // Remove return address (simulate a jump hook)
+			retn
+
+		dontKill:
+			pop eax
+			retn
+		}
+	}
+
+	void AntiCheat::VerifyThreadIntegrity()
+	{
+		bool kill = true;
+		{
+			std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
+
+			auto threadHook = std::find(AntiCheat::OwnThreadIds.begin(), AntiCheat::OwnThreadIds.end(), GetCurrentThreadId());
+			if (threadHook != AntiCheat::OwnThreadIds.end())
+			{
+				AntiCheat::OwnThreadIds.erase(threadHook);
+				kill = false;
+			}
+		}
+
+		if (kill)
+		{
+			static bool first = true;
+			if (first) first = false; // We can't control the main thread, as it's spawned externally
+			else 
+			{
+				std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
+
+				HMODULE ntdll = Utils::GetNTDLL(), targetModule;
+				if (!ntdll) return; // :(
+
+				void* address = Utils::GetThreadStartAddress(GetCurrentThread());
+				if (address)
+				{
+					GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(address), &targetModule);
+					if (targetModule == ntdll) return; // Better not kill kernel threads
+
+					DWORD id = GetCurrentThreadId();
+					{
+						auto threadHook = AntiCheat::ThreadHookMap.find(id);
+						if (threadHook != AntiCheat::ThreadHookMap.end())
+						{
+							threadHook->second->uninstall(false);
+							AntiCheat::ThreadHookMap.erase(threadHook);
+						}
+					}
+
+					std::shared_ptr<Utils::Hook> hook = std::make_shared<Utils::Hook>();
+					AntiCheat::ThreadHookMap[id] = hook;
+
+					// Hook the entry point of the thread to properly terminate it
+					hook->initialize(address, AntiCheat::ThreadEntryPointStub, HOOK_CALL)->install(true, true);
+				}
+			}
+		}
+	}
+
 	AntiCheat::AntiCheat()
 	{
 		time(nullptr);
@@ -611,6 +794,9 @@ namespace Components
 		AntiCheat::Flags = NO_FLAG;
 		AntiCheat::Hash.clear();
 
+		AntiCheat::OwnThreadIds.clear();
+		AntiCheat::ThreadHookMap.clear();
+
 		for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
 		{
 			AntiCheat::LoadLibHook[i].uninstall();
diff --git a/src/Components/Modules/AntiCheat.hpp b/src/Components/Modules/AntiCheat.hpp
index 82149cc2..ce82edc3 100644
--- a/src/Components/Modules/AntiCheat.hpp
+++ b/src/Components/Modules/AntiCheat.hpp
@@ -27,6 +27,9 @@ namespace Components
 		static unsigned long ProtectProcess();
 
 		static void PatchVirtualProtect(void* vp, void* vpex);
+		static void PatchThreadCreation();
+
+		static void VerifyThreadIntegrity();
 
 	private:
 		enum IntergrityFlag
@@ -79,7 +82,16 @@ namespace Components
 
 		static void AcquireDebugPriviledge(HANDLE hToken);
 
-		static Utils::Hook LoadLibHook[4];
+		static NTSTATUS NTAPI NtCreateThreadExStub(PHANDLE hThread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPTHREAD_START_ROUTINE startAddress, LPVOID parameter, BOOL createSuspended, DWORD stackZeroBits, DWORD sizeOfStackCommit, DWORD sizeOfStackReserve, LPVOID bytesBuffer);
+		static int ValidateThreadTermination(void* addr);
+		static void ThreadEntryPointStub();
+
+		static std::mutex ThreadMutex;
+		static std::vector<DWORD> OwnThreadIds;
+		static std::map<DWORD, std::shared_ptr<Utils::Hook>> ThreadHookMap;
+
+		static Utils::Hook CreateThreadHook;
+		static Utils::Hook LoadLibHook[6];
 		static Utils::Hook VirtualProtectHook[2];
 	};
 }
diff --git a/src/Main.cpp b/src/Main.cpp
index f0c535f2..899dc4c5 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -72,6 +72,7 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD  ul_reason_for_call, LPVOID /*l
 		[]()
 		{
 			Components::AntiCheat::ProtectProcess();
+			Components::AntiCheat::PatchThreadCreation();
 		}();
 #endif
 
@@ -87,6 +88,15 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD  ul_reason_for_call, LPVOID /*l
 	{
 		Main::Uninitialize();
 	}
+	else if(ul_reason_for_call == DLL_THREAD_ATTACH)
+	{
+#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
+		[]()
+		{
+			Components::AntiCheat::VerifyThreadIntegrity();
+		}();
+#endif
+	}
 
 	return TRUE;
 }
diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp
index c0cf82e3..6601ee8e 100644
--- a/src/Utils/Utils.cpp
+++ b/src/Utils/Utils.cpp
@@ -79,6 +79,37 @@ namespace Utils
 		return ntHeader->OptionalHeader.SizeOfImage;
 	}
 
+	void* GetThreadStartAddress(HANDLE hThread)
+	{
+		HMODULE ntdll = Utils::GetNTDLL();
+		if (!ntdll) return nullptr;
+
+
+		static uint8_t ntQueryInformationThread[] = { 0xB1, 0x8B, 0xAE, 0x8A, 0x9A, 0x8D, 0x86, 0xB6, 0x91, 0x99, 0x90, 0x8D, 0x92, 0x9E, 0x8B, 0x96, 0x90, 0x91, 0xAB, 0x97, 0x8D, 0x9A, 0x9E, 0x9B }; // NtQueryInformationThread
+		NtQueryInformationThread_t NtQueryInformationThread = NtQueryInformationThread_t(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ntQueryInformationThread), sizeof ntQueryInformationThread), -1).data()));
+		if (!NtQueryInformationThread) return nullptr;
+
+		HANDLE dupHandle, currentProcess = GetCurrentProcess();
+		if (!DuplicateHandle(currentProcess, hThread, currentProcess, &dupHandle, THREAD_QUERY_INFORMATION, FALSE, 0))
+		{
+			SetLastError(ERROR_ACCESS_DENIED);
+			return nullptr;
+		}
+
+		void* address = nullptr;
+		NTSTATUS status = NtQueryInformationThread(dupHandle, ThreadQuerySetWin32StartAddress, &address, sizeof(address), nullptr);
+		CloseHandle(dupHandle);
+
+		if (status != 0) return nullptr;
+		return address;
+	}
+
+	HMODULE GetNTDLL()
+	{
+		static uint8_t ntdll[] = { 0x91, 0x8B, 0x9B, 0x93, 0x93, 0xD1, 0x9B, 0x93, 0x93 }; // ntdll.dll
+		return GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(ntdll), sizeof ntdll), -1).data());
+	}
+
 	bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2)
 	{
 		return !(base1 + len1 <= base2 || base2 + len2 <= base1);
diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp
index 6c0bcbe4..7ae60034 100644
--- a/src/Utils/Utils.hpp
+++ b/src/Utils/Utils.hpp
@@ -1,5 +1,10 @@
 #pragma once
 
+typedef LONG NTSTATUS;
+typedef NTSTATUS(NTAPI *NtCreateThreadEx_t)(PHANDLE hThread, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD StackZeroBits, DWORD SizeOfStackCommit, DWORD SizeOfStackReserve, LPVOID lpBytesBuffer);
+typedef NTSTATUS(NTAPI* NtQueryInformationThread_t)(HANDLE ThreadHandle, LONG ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
+#define ThreadQuerySetWin32StartAddress 9
+
 namespace Utils
 {
 	std::string GetMimeType(std::string url);
@@ -10,8 +15,9 @@ namespace Utils
 	bool IsWineEnvironment();
 
 	unsigned long GetParentProcessId();
-
 	size_t GetModuleSize(HMODULE module);
+	void* GetThreadStartAddress(HANDLE hThread);
+	HMODULE GetNTDLL();
 
 	bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2);
 

From 29ef5d63793ae76d2c7c4217548375e73efa6e52 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sun, 11 Jun 2017 21:24:32 +0200
Subject: [PATCH 03/10] [AntiCheat] Add redundant code scanners

---
 src/Components/Modules/AntiCheat.cpp | 40 ++++++++++++++++++++++++++++
 src/Components/Modules/AntiCheat.hpp |  4 +++
 src/Components/Modules/Changelog.cpp |  4 +++
 src/Components/Modules/Menus.cpp     |  4 +++
 4 files changed, 52 insertions(+)

diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp
index a8228db2..4c23ae0d 100644
--- a/src/Components/Modules/AntiCheat.cpp
+++ b/src/Components/Modules/AntiCheat.cpp
@@ -229,6 +229,46 @@ namespace Components
 		AntiCheat::Flags |= AntiCheat::IntergrityFlag::MEMORY_SCAN;
 	}
 
+	void AntiCheat::QuickCodeScanner_1()
+	{
+		static Utils::Time::Interval interval;
+		static Utils::Value<std::string> hashVal;
+
+		if (!interval.elapsed(11s)) return;
+		interval.update();
+
+		// Hash .text segment
+		// Add 1 to each value, so searching in memory doesn't reveal anything
+		size_t textSize = 0x2D5FFF;
+		uint8_t* textBase = reinterpret_cast<uint8_t*>(0x400FFF);
+		std::string hash = Utils::Cryptography::SHA256::Compute(textBase + 1, textSize + 1, false);
+
+		if (hashVal.isValid() && hash != hashVal.get())
+		{
+			Utils::Hook::Set<BYTE>(0x42A667, 0x90); // Crash
+		}
+
+		hashVal.set(hash);
+	}
+
+	void AntiCheat::QuickCodeScanner_2()
+	{
+		static Utils::Time::Interval interval;
+		static Utils::Value<std::string> hashVal;
+
+		if (!interval.elapsed(12s)) return;
+		interval.update();
+
+		// Hash .text segment
+		std::string hash = Utils::Cryptography::SHA1::Compute(reinterpret_cast<uint8_t*>(0x401000), 0x2D6000, false);
+		if (hashVal.isValid() && hash != hashVal.get())
+		{
+			Utils::Hook::Set<BYTE>(0x40797C, 0x90); // Crash
+		}
+
+		hashVal.set(hash);
+	}
+
 #ifdef DEBUG_LOAD_LIBRARY
 	HANDLE AntiCheat::LoadLibary(std::wstring library, HANDLE file, DWORD flags, void* callee)
 	{
diff --git a/src/Components/Modules/AntiCheat.hpp b/src/Components/Modules/AntiCheat.hpp
index ce82edc3..5c0b5279 100644
--- a/src/Components/Modules/AntiCheat.hpp
+++ b/src/Components/Modules/AntiCheat.hpp
@@ -31,6 +31,10 @@ namespace Components
 
 		static void VerifyThreadIntegrity();
 
+		static void QuickCodeScanner_1();
+		static void QuickCodeScanner_2();
+		static void QuickCodeScanner_3();
+
 	private:
 		enum IntergrityFlag
 		{
diff --git a/src/Components/Modules/Changelog.cpp b/src/Components/Modules/Changelog.cpp
index 6dc2d719..e45e937f 100644
--- a/src/Components/Modules/Changelog.cpp
+++ b/src/Components/Modules/Changelog.cpp
@@ -55,6 +55,10 @@ namespace Components
 
 		// Changelog
 		UIFeeder::Add(62.0f, Changelog::GetChangelogCount, Changelog::GetChangelogText, Changelog::SelectChangelog);
+
+#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
+		Scheduler::OnFrame(AntiCheat::QuickCodeScanner_1);
+#endif
 	}
 
 	Changelog::~Changelog()
diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp
index 68ba3277..2d8d8ad9 100644
--- a/src/Components/Modules/Menus.cpp
+++ b/src/Components/Modules/Menus.cpp
@@ -766,6 +766,10 @@ namespace Components
 			}
 		});
 
+#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
+		Scheduler::OnFrame(AntiCheat::QuickCodeScanner_2);
+#endif
+
 		Command::Add("mp_QuickMessage", [] (Command::Params*)
 		{
 			Command::Execute("openmenu quickmessage");

From a327915008e72491861ed0e459241da783afd117 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sun, 11 Jun 2017 21:25:00 +0200
Subject: [PATCH 04/10] [Command] Don't crash on shell execute

---
 src/Components/Modules/Command.cpp | 2 +-
 src/Components/Modules/News.cpp    | 4 ++--
 src/Utils/Utils.cpp                | 9 +++++++++
 src/Utils/Utils.hpp                | 2 ++
 4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp
index 90806c69..b4e770c8 100644
--- a/src/Components/Modules/Command.cpp
+++ b/src/Components/Modules/Command.cpp
@@ -257,7 +257,7 @@ namespace Components
 		{
 			if (params->length() > 1)
 			{
-				ShellExecuteA(nullptr, "open", params->get(1), nullptr, nullptr, SW_SHOWNORMAL);
+				Utils::OpenUrl(params->get(1));
 			}
 		});
 	}
diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp
index 44af50d8..aca4484b 100644
--- a/src/Components/Modules/News.cpp
+++ b/src/Components/Modules/News.cpp
@@ -201,12 +201,12 @@ namespace Components
 
 		UIScript::Add("visitWebsite", [](UIScript::Token)
 		{
-			ShellExecuteA(nullptr, "open", Utils::Cache::GetStaticUrl("").data(), nullptr, nullptr, SW_SHOWNORMAL);
+			Utils::OpenUrl(Utils::Cache::GetStaticUrl(""));
 		});
 
 		UIScript::Add("visitWiki", [](UIScript::Token)
 		{
-			ShellExecuteA(nullptr, "open", Utils::Cache::GetStaticUrl("/wiki/").data(), nullptr, nullptr, SW_SHOWNORMAL);
+			Utils::OpenUrl(Utils::Cache::GetStaticUrl("/wiki/"));
 		});
 
 		Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp
index 6601ee8e..2bca4d44 100644
--- a/src/Utils/Utils.cpp
+++ b/src/Utils/Utils.cpp
@@ -110,6 +110,15 @@ namespace Utils
 		return GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(ntdll), sizeof ntdll), -1).data());
 	}
 
+	void OpenUrl(std::string url)
+	{
+		try
+		{
+			ShellExecuteA(nullptr, "open", url.data(), nullptr, nullptr, SW_SHOWNORMAL);
+		}
+		catch (...) {}
+	}
+
 	bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2)
 	{
 		return !(base1 + len1 <= base2 || base2 + len2 <= base1);
diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp
index 7ae60034..31fe5019 100644
--- a/src/Utils/Utils.hpp
+++ b/src/Utils/Utils.hpp
@@ -19,6 +19,8 @@ namespace Utils
 	void* GetThreadStartAddress(HANDLE hThread);
 	HMODULE GetNTDLL();
 
+	void OpenUrl(std::string url);
+
 	bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2);
 
 	template <typename T> inline void RotLeft(T& object, size_t bits)

From a46daef6f1057d6bbc9326cbc6d2f6a74b9e60e7 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sun, 11 Jun 2017 21:25:18 +0200
Subject: [PATCH 05/10] [Window] Use better loading cursor

---
 src/Components/Modules/Window.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Components/Modules/Window.cpp b/src/Components/Modules/Window.cpp
index adde2efc..5d7c404d 100644
--- a/src/Components/Modules/Window.cpp
+++ b/src/Components/Modules/Window.cpp
@@ -127,7 +127,7 @@ namespace Components
 	void Window::ApplyCursor()
 	{
 		bool isLoading = !FastFiles::Ready();
-		SetCursor(LoadCursor(nullptr, isLoading ? IDC_WAIT : IDC_ARROW));
+		SetCursor(LoadCursor(nullptr, isLoading ? IDC_APPSTARTING : IDC_ARROW));
 	}
 
 	BOOL WINAPI Window::MessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)

From 2a158632300d128212ffdf5fe03cbeab3e62ded9 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sun, 11 Jun 2017 21:25:31 +0200
Subject: [PATCH 06/10] [QuickPatch] Block upnp spam

---
 src/Components/Modules/QuickPatch.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp
index 0017f9d9..5788f56e 100644
--- a/src/Components/Modules/QuickPatch.cpp
+++ b/src/Components/Modules/QuickPatch.cpp
@@ -256,6 +256,7 @@ namespace Components
 		// dont run UPNP stuff on main thread
 		Utils::Hook::Set<BYTE>(0x48A135, 0xC3);
 		Utils::Hook::Set<BYTE>(0x48A151, 0xC3);
+		Utils::Hook::Nop(0x684080, 5); // Don't spam the console
 
 		// spawn upnp thread when UPNP_init returns
 		Utils::Hook::Hook(0x47982B, []()

From de48b1c694110f50274fa97d61660cafa8e81627 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sun, 11 Jun 2017 21:25:41 +0200
Subject: [PATCH 07/10] [Submodules] Update libtomcrypt

---
 deps/libtomcrypt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/deps/libtomcrypt b/deps/libtomcrypt
index 2816da42..39228680 160000
--- a/deps/libtomcrypt
+++ b/deps/libtomcrypt
@@ -1 +1 @@
-Subproject commit 2816da42af88aa1ed4d2d0b958d81021956a6c7e
+Subproject commit 39228680827980b0da9a4d38070bb590d2eff983

From 74a39c6e7badd7132301dae3c4311af7c44db056 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Sun, 11 Jun 2017 22:36:28 +0200
Subject: [PATCH 08/10] [AntiCheat] Disable VirtualProtect patch

---
 src/Components/Modules/AntiCheat.hpp    |  1 -
 src/Components/Modules/Localization.cpp | 12 ++++++------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/Components/Modules/AntiCheat.hpp b/src/Components/Modules/AntiCheat.hpp
index 5c0b5279..1285dab3 100644
--- a/src/Components/Modules/AntiCheat.hpp
+++ b/src/Components/Modules/AntiCheat.hpp
@@ -33,7 +33,6 @@ namespace Components
 
 		static void QuickCodeScanner_1();
 		static void QuickCodeScanner_2();
-		static void QuickCodeScanner_3();
 
 	private:
 		enum IntergrityFlag
diff --git a/src/Components/Modules/Localization.cpp b/src/Components/Modules/Localization.cpp
index 6c18412a..14b6dbc9 100644
--- a/src/Components/Modules/Localization.cpp
+++ b/src/Components/Modules/Localization.cpp
@@ -286,12 +286,12 @@ namespace Components
 			}
 		});
 
-#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
-		if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::PerformingUnitTests())
-		{
-			AntiCheat::PatchVirtualProtect(VirtualProtect, VirtualProtectEx);
-		}
-#endif
+// #if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
+// 		if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::PerformingUnitTests())
+// 		{
+// 			AntiCheat::PatchVirtualProtect(VirtualProtect, VirtualProtectEx);
+// 		}
+// #endif
 	}
 
 	Localization::~Localization()

From 8b38b3990ca9a2b0cd695dcbbf2e04efff9ffd2d Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Mon, 12 Jun 2017 19:54:11 +0200
Subject: [PATCH 09/10] [Main] Directly jump to the initialization routine

---
 src/Components/Loader.cpp | 2 +-
 src/Main.cpp              | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp
index f4dd91e8..767e2e23 100644
--- a/src/Components/Loader.cpp
+++ b/src/Components/Loader.cpp
@@ -190,7 +190,7 @@ namespace Components
 	{
 		if (component)
 		{
-#ifdef DEBUG
+#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
 			if(!Loader::PerformingUnitTests())
 			{
 				Logger::Print("Component registered: %s\n", component->getName().data());
diff --git a/src/Main.cpp b/src/Main.cpp
index 899dc4c5..c65b5333 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -49,7 +49,7 @@ namespace Main
 			call Main::Initialize
 			popad
 
-			push 6BAC14h // Continue init routine
+			push 6BAA2Fh // Continue init routine
 			push 6CA062h // ___security_init_cookie
 			retn
 		}

From 8b7aca48d370e7bb4aa5a3d1e9d774d85186f740 Mon Sep 17 00:00:00 2001
From: momo5502 <mauriceheumann@gmail.com>
Date: Mon, 12 Jun 2017 19:54:20 +0200
Subject: [PATCH 10/10] [Submodules] Update libtomcrypt

---
 deps/libtomcrypt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/deps/libtomcrypt b/deps/libtomcrypt
index 39228680..a4671110 160000
--- a/deps/libtomcrypt
+++ b/deps/libtomcrypt
@@ -1 +1 @@
-Subproject commit 39228680827980b0da9a4d38070bb590d2eff983
+Subproject commit a4671110d5b988161d029eb5001d1516301606dd