From ce851f8ef27c6e3397216fe413eea8ab374f1191 Mon Sep 17 00:00:00 2001 From: Dis_Bro Date: Tue, 10 Mar 2026 10:30:07 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=97=D0=B0=D1=89=D0=B8=D1=82=D0=BD=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0=20+=20TXT=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2. Периферия/🔒Защита от Кости (Лицензирование).md | 455 +++++++++++------- .../Встраиваемые/Assets/StreamingAssets/README.txt | 20 + .../Встраиваемые/Assets/StreamingAssets/Вызов.txt | 6 + .../Встраиваемые/Assets/StreamingAssets/Защитник.txt | 304 ++++++++++++ 4 files changed, 607 insertions(+), 178 deletions(-) create mode 100644 Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/README.txt create mode 100644 Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Вызов.txt create mode 100644 Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Защитник.txt diff --git a/GreatGamedevVault/Библиотека скриптов/2. Периферия/🔒Защита от Кости (Лицензирование).md b/GreatGamedevVault/Библиотека скриптов/2. Периферия/🔒Защита от Кости (Лицензирование).md index 6d5cb94..77290f1 100644 --- a/GreatGamedevVault/Библиотека скриптов/2. Периферия/🔒Защита от Кости (Лицензирование).md +++ b/GreatGamedevVault/Библиотека скриптов/2. Периферия/🔒Защита от Кости (Лицензирование).md @@ -10,211 +10,310 @@ by:kotovskij393 Вот этот функционал скопировать. Где то в точке старта будем вызывать (Отдельным файлом): ##### Код ```cs -    #region DEFENCE +    #region DEFENCE + [StructLayout(LayoutKind.Sequential)] + private struct PROCESS_INFORMATION + { + public IntPtr hProcess; + public IntPtr hThread; + public int dwProcessId; + public int dwThreadId; + } -    [StructLayout(LayoutKind.Sequential)] -    private struct PROCESS_INFORMATION + [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; + } -    { -        public IntPtr hProcess; -        public IntPtr hThread; -        public int dwProcessId; -        public int dwThreadId; -    } + [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); -    [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)] + private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); -    [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 bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode); -    [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); -    [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 const uint WAIT_TIMEOUT = 0x00000102; -    private const uint WAIT_OBJECT_0 = 0x00000000; + private System.Collections.IEnumerator CheckLicenseCoroutine() + { + // Ждём один кадр, чтобы Unity завершил инициализацию + yield return null; -    private System.Collections.IEnumerator CheckLicenseCoroutine() -    { -        // Ждём один кадр, чтобы Unity завершил инициализацию -        yield return null; - -        bool licenseValid = false; -        bool checkCompleted = false; -        //bool licenseValid = true; -        //bool checkCompleted = true; -        string errorMessage = ""; + bool licenseValid = false; + bool checkCompleted = false; + //bool licenseValid = true; + //bool checkCompleted = true; + string errorMessage = ""; -        // Запускаем проверку в отдельном потоке (совместимо с IL2CPP) -        System.Threading.Thread thread = new System.Threading.Thread(() => -        { -            try -            { -                licenseValid = CheckLicense(); -            } -            catch (Exception ex) -            { -                errorMessage = ex.Message; -            } -            finally -            { -                checkCompleted = true; -            } -        }); + // Запускаем проверку в отдельном потоке (совместимо с 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(); + thread.IsBackground = true; + thread.Start(); -        float timerest = 30f; -        -        while (!checkCompleted && timerest > 0) -        { -            timerest -= Time.deltaTime; -            yield return null; -        } + float timerest = 30f; + while (!checkCompleted && timerest > 0) + { + timerest -= Time.deltaTime; + yield return null; + } -        if (!checkCompleted) licenseValid = false; + if (!checkCompleted) licenseValid = false; + + if (!licenseValid) + { + yield return new WaitForSeconds(3f); -        if (!licenseValid) -        { -            yield return new WaitForSeconds(3f); #if UNITY_EDITOR -            EditorApplication.isPlaying = false; + EditorApplication.isPlaying = false; #else -            Application.Quit(); + Application.Quit(); #endif -        } -    } + } + else + { + //exclusive + Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen; + Screen.SetResolution(1920, 1080, true); + ClickCenter(); + } + } -    /// -    /// Проверяет лицензию через внешний лаунчер RRLauncher.exe. -    /// Возвращает true, если проверка пройдена, иначе false. -    /// -    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; + private bool CheckLicense() + { + try + { + string launcherName = "RRLauncher.exe"; + string launcherPath = null; -                string workingDir = Path.GetDirectoryName(launcherPath); + // Поиск лаунчера рядом с исполняемым файлом + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + string pathInBase = Path.Combine(baseDirectory, launcherName); -                bool success = CreateProcess( -                    launcherPath, -                    null, -                    IntPtr.Zero, -                    IntPtr.Zero, -                    false, -                    0, -                    IntPtr.Zero, -                    workingDir, -                    ref si, -                    out pi); + if (File.Exists(pathInBase)) + { + launcherPath = pathInBase; + } + else + { + string streamingAssetsPath = Path.Combine(Application.streamingAssetsPath, launcherName); + if (File.Exists(streamingAssetsPath)) + { + launcherPath = streamingAssetsPath; + } + else + { + return false; + } + } -                if (!success) return false; + try + { + STARTUPINFO si = new STARTUPINFO(); + si.cb = Marshal.SizeOf(si); + PROCESS_INFORMATION pi; -                uint waitResult = WaitForSingleObject(pi.hProcess, 30000); + string workingDir = Path.GetDirectoryName(launcherPath); -                if (waitResult == WAIT_TIMEOUT) -                { -                    CloseHandle(pi.hProcess); -                    CloseHandle(pi.hThread); -                    return false; -                } + bool success = CreateProcess( + launcherPath, + null, + IntPtr.Zero, + IntPtr.Zero, + false, + 0, + IntPtr.Zero, + workingDir, + ref si, + out pi); -                // Получение кода возврата -                uint exitCode; -                -                if (!GetExitCodeProcess(pi.hProcess, out exitCode)) -                { -                    CloseHandle(pi.hProcess); -                    CloseHandle(pi.hThread); -                    return false; -                } + if (!success) return false; + uint waitResult = WaitForSingleObject(pi.hProcess, 30000); -                CloseHandle(pi.hProcess); -                CloseHandle(pi.hThread); + if (waitResult == WAIT_TIMEOUT) + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return false; + } -                if (exitCode == 0) return true; + // Получение кода возврата + uint exitCode; + if (!GetExitCodeProcess(pi.hProcess, out exitCode)) + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return false; + } -                return false; -            } -            catch -            { -                return false; -            } -        } -        catch (Exception outerEx) -        { -            UnityEngine.Debug.LogError($"[License] CRITICAL ERROR in CheckLicense: {outerEx.Message}"); -            UnityEngine.Debug.LogError($"[License] Stack trace: {outerEx.StackTrace}"); -            return false; -        } -    } -    #endregion + 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 + #endregion ``` ##### Привязка к игре diff --git a/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/README.txt b/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/README.txt new file mode 100644 index 0000000..91277f7 --- /dev/null +++ b/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/README.txt @@ -0,0 +1,20 @@ +1. Поместить RRLauncher.exe в папку Assets\StreamingAssets\ +2. Добавить в какой либо скрипт содержимое файла Защитник.txt. + В идеале в bootstrap-script если он реализован +3. Запустить корутину с защитой (пример в файле Вызов.txt) + + +ВНИМАНИЕ!!! +В алгоритме есть такой костыль, может мешать работе если другое разрешение или несколько мониторов. +Можно пробовать запустить без костыля и дай бог всё будет хорошо +На фишке до какой то поры всё было хорошо, потом сломалось. + +else +{ + Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen; + Screen.SetResolution(1920, 1080, true); + ClickCenter(); +} + + +Лицензирование производится отдельной программой, которую можно попросить у Бори или Тимура \ No newline at end of file diff --git a/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Вызов.txt b/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Вызов.txt new file mode 100644 index 0000000..2721e78 --- /dev/null +++ b/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Вызов.txt @@ -0,0 +1,6 @@ +private void Awake() +{ + #if !UNITY_EDITOR + StartCoroutine(CheckLicenseCoroutine()); + #endif +} \ No newline at end of file diff --git a/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Защитник.txt b/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Защитник.txt new file mode 100644 index 0000000..3e3355c --- /dev/null +++ b/Библиотека/Периферия/Встраиваемые/Assets/StreamingAssets/Защитник.txt @@ -0,0 +1,304 @@ + #region DEFENCE + [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 System.Collections.IEnumerator CheckLicenseCoroutine() + { + // Ждём один кадр, чтобы Unity завершил инициализацию + yield return null; + + bool licenseValid = false; + bool checkCompleted = false; + //bool licenseValid = true; + //bool checkCompleted = true; + string errorMessage = ""; + + // Запускаем проверку в отдельном потоке (совместимо с 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(); + + float timerest = 30f; + while (!checkCompleted && timerest > 0) + { + timerest -= Time.deltaTime; + yield return null; + } + + if (!checkCompleted) licenseValid = false; + + if (!licenseValid) + { + yield return new WaitForSeconds(3f); + +#if UNITY_EDITOR + EditorApplication.isPlaying = false; +#else + Application.Quit(); +#endif + } + else + { + //exclusive + Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen; + Screen.SetResolution(1920, 1080, true); + ClickCenter(); + } + } + + + 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 + #endregion \ No newline at end of file