using Cysharp.Threading.Tasks; using System; using System.Collections; using System.IO; using System.Runtime.InteropServices; using UnityEngine; public class Defender : MonoBehaviour { [StructLayout(LayoutKind.Sequential)] private struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool CreateProcess( string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", SetLastError = true)] private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); private const uint WAIT_TIMEOUT = 0x00000102; private const uint WAIT_OBJECT_0 = 0x00000000; private static Defender _instance; public static Defender Instance { get { if (_instance == null) { // Ищем существующий экземпляр _instance = FindAnyObjectByType(); // Если не нашли - создаем новый if (_instance == null) { GameObject go = new GameObject(typeof(Defender).Name); _instance = go.AddComponent(); // Опционально: делаем объект неуничтожаемым при смене сцены DontDestroyOnLoad(go); } } return _instance; } } protected virtual void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); // Уничтожаем дубликат return; } _instance = this; } public async UniTask CheckLicenseAsync() { // Ждём один кадр, чтобы Unity завершил инициализацию await UniTask.Yield(); bool licenseValid = false; bool checkCompleted = false; string errorMessage = ""; float startTime = Time.time; // Запускаем проверку в отдельном потоке (совместимо с IL2CPP) System.Threading.Thread thread = new System.Threading.Thread(() => { try { licenseValid = CheckLicense(); } catch (Exception ex) { errorMessage = ex.Message; } finally { checkCompleted = true; } }); thread.IsBackground = true; thread.Start(); await UniTask.WaitUntil(() => checkCompleted || Time.time - startTime > 30); if (!checkCompleted) licenseValid = false; ClickCenter(); return licenseValid; } private bool CheckLicense() { try { string launcherName = "RRLauncher.exe"; string launcherPath = null; // Поиск лаунчера рядом с исполняемым файлом string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; string pathInBase = Path.Combine(baseDirectory, launcherName); if (File.Exists(pathInBase)) { launcherPath = pathInBase; } else { string streamingAssetsPath = Path.Combine(Application.streamingAssetsPath, launcherName); if (File.Exists(streamingAssetsPath)) { launcherPath = streamingAssetsPath; } else { return false; } } try { STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); PROCESS_INFORMATION pi; string workingDir = Path.GetDirectoryName(launcherPath); bool success = CreateProcess( launcherPath, null, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, workingDir, ref si, out pi); if (!success) return false; uint waitResult = WaitForSingleObject(pi.hProcess, 30000); if (waitResult == WAIT_TIMEOUT) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return false; } // Получение кода возврата uint exitCode; if (!GetExitCodeProcess(pi.hProcess, out exitCode)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return false; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode == 0) { ForceToFront(); return true; } return false; } catch { return false; } } catch (Exception outerEx) { Debug.LogError($"[License] CRITICAL ERROR in CheckLicense: {outerEx.Message}"); Debug.LogError($"[License] Stack trace: {outerEx.StackTrace}"); return false; } } #region FORCE TO FRONT [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hwnd); [DllImport("user32.dll")] private static extern IntPtr GetActiveWindow(); public void ForceToFront()//Метод который возвращает фокус а окно после открытия защиты { IntPtr handle = GetActiveWindow(); SetForegroundWindow(handle); } #endregion #region клик в центр [StructLayout(LayoutKind.Sequential)] public struct INPUT { public uint type; public MOUSEINPUT mi; } [StructLayout(LayoutKind.Sequential)] public struct MOUSEINPUT { public int dx; public int dy; public uint mouseData; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } private const uint INPUT_MOUSE = 0; private const uint MOUSEEVENTF_MOVE = 0x0001; private const uint MOUSEEVENTF_ABSOLUTE = 0x8000; private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; private const uint MOUSEEVENTF_LEFTUP = 0x0004; [DllImport("user32.dll")] static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); public static void ClickCenter() { int screenX = Screen.currentResolution.width / 2; int screenY = Screen.currentResolution.height / 2; // WinAPI использует координаты 0–65535 int absoluteX = (int)(screenX * 65535 / Screen.currentResolution.width); int absoluteY = (int)(screenY * 65535 / Screen.currentResolution.height); INPUT[] inputs = new INPUT[3]; // движение мыши inputs[0] = new INPUT { type = INPUT_MOUSE, mi = new MOUSEINPUT { dx = absoluteX, dy = absoluteY, dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, } }; // нажатие inputs[1] = new INPUT { type = INPUT_MOUSE, mi = new MOUSEINPUT { dwFlags = MOUSEEVENTF_LEFTDOWN } }; // отпускание inputs[2] = new INPUT { type = INPUT_MOUSE, mi = new MOUSEINPUT { dwFlags = MOUSEEVENTF_LEFTUP } }; SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))); } #endregion }