diff --git a/src/UniGetUI.Core.Tools/DWMThreadHelper.cs b/src/UniGetUI.Core.Tools/DWMThreadHelper.cs index 63a593edd..9c88557fd 100644 --- a/src/UniGetUI.Core.Tools/DWMThreadHelper.cs +++ b/src/UniGetUI.Core.Tools/DWMThreadHelper.cs @@ -33,100 +33,136 @@ private enum ThreadAccess : uint private static bool DWM_IsSuspended; private static bool XAML_IsSuspended; + private static int? DWMThreadId; + private static IntPtr? DWMThreadAdress; + private static int? XAMLThreadId; + private static IntPtr? XAMLThreadAdress; + public static void ChangeState_DWM(bool suspend) { if (DWM_IsSuspended && suspend) { - Logger.Warn("DWM Thread was already suspended"); return; + Logger.Debug("DWM Thread was already suspended"); return; } else if (!DWM_IsSuspended && !suspend) { - Logger.Warn("DWM Thread was already running"); return; + Logger.Debug("DWM Thread was already running"); return; } - IntPtr adress = GetTargetFunctionAddress("dwmcorei.dll", 0x54F70); - if (adress == IntPtr.Zero) + DWMThreadAdress ??= GetTargetFunctionAddress("dwmcorei.dll", 0x54F70); + if (DWMThreadAdress is null) { Logger.Error("Failed to resolve thread start adress."); return; } - ChangeState(suspend, adress, ref DWM_IsSuspended, "DWM"); + ChangeState(suspend, (IntPtr)DWMThreadAdress, ref DWM_IsSuspended, ref DWMThreadId, "DWM"); } public static void ChangeState_XAML(bool suspend) { if (XAML_IsSuspended && suspend) { - Logger.Warn("XAML Thread was already suspended"); return; + Logger.Debug("XAML Thread was already suspended"); return; } else if (!XAML_IsSuspended && !suspend) { - Logger.Warn("XAML Thread was already running"); return; + Logger.Debug("XAML Thread was already running"); return; } // The reported offset on ProcessExplorer seems to be missing 0x6280 somehow // 0x54F70 + 0x6280 = 0x5B1F0 - IntPtr adress = GetTargetFunctionAddress("Microsoft.UI.Xaml.dll", 0x5B1F0); - if (adress == IntPtr.Zero) + XAMLThreadAdress ??= GetTargetFunctionAddress("Microsoft.UI.Xaml.dll", 0x5B1F0); + if (XAMLThreadAdress is null) { Logger.Error("Failed to resolve thread start adress."); return; } - ChangeState(suspend, adress, ref XAML_IsSuspended, "XAML"); + ChangeState(suspend, (IntPtr)XAMLThreadAdress, ref XAML_IsSuspended, ref XAMLThreadId, "XAML"); } - private static void ChangeState(bool suspend, IntPtr threadAdress, ref bool IsSuspended, string loggerName) + private static IntPtr GetThreadStartAdress(int threadId) { - foreach (ProcessThread thread in Process.GetCurrentProcess().Threads) - { - IntPtr hThread = OpenThread(ThreadAccess.QUERY_INFORMATION | ThreadAccess.SUSPEND_RESUME, false, - (uint)thread.Id); - if (hThread == IntPtr.Zero) - continue; - - IntPtr adress = 0x00; - int status = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, ref adress, Marshal.SizeOf(typeof(IntPtr)), out _); + IntPtr hThread = OpenThread(ThreadAccess.QUERY_INFORMATION | ThreadAccess.SUSPEND_RESUME, false, (uint)threadId); + if (hThread == IntPtr.Zero) return IntPtr.Zero; + + IntPtr adress = 0x00; + int status = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, ref adress, Marshal.SizeOf(typeof(IntPtr)), out _); + if(status != 0) Logger.Warn($"NtQueryInformationThread returned non-zero status code 0x{(uint)status:X}"); + CloseHandle(hThread); + return adress; + } - if (status == 0 && adress == threadAdress) + private static void ChangeState(bool suspend, IntPtr threadAdress, ref bool IsSuspended, ref int? threadId, + string loggerName, bool canRetry = true) + { + if (threadId is null) + { + foreach (ProcessThread thread in Process.GetCurrentProcess().Threads) { - if (suspend) - { - uint res = SuspendThread(hThread); - if (res == 0) - { - IsSuspended = true; - Logger.Warn($"{loggerName} Thread was suspended successfully"); - CloseHandle(hThread); - return; - } - else - { - Logger.Error($"Could not suspend {loggerName} Thread with NTSTATUS = 0x{res:X}"); - } - } - else + if (GetThreadStartAdress(thread.Id) == threadAdress) { - int res = (int)ResumeThread(hThread); - if (res >= 0) - { - IsSuspended = false; - Logger.Warn($"{loggerName} Thread was resumed successfully"); - CloseHandle(hThread); - return; - } - else - { - Logger.Error($"Could not resume {loggerName} Thread with NTSTATUS = 0x{res:X}"); - } + threadId = thread.Id; + Logger.Info($"Thread with Id {threadId} was assigned as {loggerName} thread"); } } + } - CloseHandle(hThread); + if (threadId is null) + { + Logger.Error($"No thread matching {loggerName} with start adress {threadAdress:X} was found"); + return; } - Logger.Error($"No thread matching {loggerName} was found"); + + IntPtr hThread = OpenThread(ThreadAccess.QUERY_INFORMATION | ThreadAccess.SUSPEND_RESUME, false, (uint)threadId); + if (hThread == IntPtr.Zero) + { // When the thread cannot be opened + if (canRetry) + { + threadId = null; // On first try, reset argument threadId so it does get loaded again. + ChangeState(suspend, threadAdress, ref IsSuspended, ref threadId, loggerName, false); + return; + } + // The threadId was already reloaded + Logger.Warn($"Thread with id={threadId} and assigned as {loggerName} exists but could not be opened!"); + return; + } + + + if (suspend) + { + uint res = SuspendThread(hThread); + if (res == 0) + { + IsSuspended = true; + Logger.Info($"{loggerName} Thread was suspended successfully"); + CloseHandle(hThread); + return; + } + else + { + Logger.Warn($"Could not suspend {loggerName} Thread with NTSTATUS = 0x{res:X}"); + } + } + else + { + int res = (int)ResumeThread(hThread); + if (res >= 0) + { + IsSuspended = false; + Logger.Info($"{loggerName} Thread was resumed successfully"); + CloseHandle(hThread); + return; + } + else + { + Logger.Error($"Could not resume {loggerName} Thread with NTSTATUS = 0x{res:X}"); + } + } + + CloseHandle(hThread); } - private static IntPtr GetTargetFunctionAddress(string moduleName, int offset) + private static IntPtr? GetTargetFunctionAddress(string moduleName, int offset) { foreach (ProcessModule module in Process.GetCurrentProcess().Modules) { @@ -135,6 +171,6 @@ private static IntPtr GetTargetFunctionAddress(string moduleName, int offset) return module.BaseAddress + offset; } } - return IntPtr.Zero; + return null; } }