diff --git a/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.cpp b/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.cpp index ebec97e4237..416ab567ab9 100644 --- a/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.cpp +++ b/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.cpp @@ -103,6 +103,7 @@ std::vector find_processes_recursive(const std::vectorsecond.begin(), it->second.end()) }); } @@ -111,50 +112,6 @@ std::vector find_processes_recursive(const std::vector 0) - { - std::vector token_buffer(token_size); - GetTokenInformation(token, TokenUser, token_buffer.data(), token_size, &token_size); - TOKEN_USER* user_ptr = (TOKEN_USER*)token_buffer.data(); - PSID psid = user_ptr->User.Sid; - DWORD user_size = 0; - DWORD domain_size = 0; - SID_NAME_USE sid_name; - LookupAccountSidW(NULL, psid, NULL, &user_size, NULL, &domain_size, &sid_name); - user.resize(user_size + 1); - domain.resize(domain_size + 1); - LookupAccountSidW(NULL, psid, user.data(), &user_size, domain.data(), &domain_size, &sid_name); - user[user_size] = L'\0'; - domain[domain_size] = L'\0'; - } - - CloseHandle(token); - } - - CloseHandle(process); - - return user; -} - constexpr size_t LongMaxPathSize = 65536; std::wstring pid_to_full_path(DWORD pid) diff --git a/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.h b/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.h index ee959bc7442..47012c3f896 100644 --- a/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.h +++ b/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmith.h @@ -6,14 +6,12 @@ struct ProcessResult { std::wstring name; DWORD pid; + std::wstring user; std::vector files; }; // Second version, checks handles towards files and all subfiles and folders of given dirs, if any. std::vector find_processes_recursive(const std::vector& paths); -// Gives the user name of the account running this process -std::wstring pid_to_user(DWORD pid); - // Gives the full path of the executable, given the process id std::wstring pid_to_full_path(DWORD pid); diff --git a/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmithLibInterop.vcxproj b/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmithLibInterop.vcxproj index b0c9affc8ec..b568c9219c2 100644 --- a/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmithLibInterop.vcxproj +++ b/src/modules/FileLocksmith/FileLocksmithLibInterop/FileLocksmithLibInterop.vcxproj @@ -128,46 +128,6 @@ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileLocksmith\ PowerToys.FileLocksmithLib.Interop - - - Level3 - true - WIN32;_DEBUG;FILELOCKSMITHLIBINTEROP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - NetCore - stdcpp17 - MultiThreadedDebugDLL - /Zc:twoPhase- - - - Windows - true - false - - - - - Level3 - true - true - true - WIN32;NDEBUG;FILELOCKSMITHLIBINTEROP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - NetCore - stdcpp17 - /Zc:twoPhase- - MultiThreadedDLL - - - Windows - true - true - true - false - - Level3 diff --git a/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.cpp b/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.cpp index 17d2ec25b86..7bab7749222 100644 --- a/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.cpp +++ b/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.cpp @@ -238,6 +238,57 @@ std::vector NtdllExtensions::handles() noexcept // Returns the list of all processes. // On failure, returns an empty vector. +std::wstring NtdllExtensions::pid_to_user(DWORD pid) +{ + HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + std::wstring user; + std::wstring domain; + + if (process == nullptr) + { + return user; + } + + HANDLE token = nullptr; + + if (!OpenProcessToken(process, TOKEN_QUERY, &token)) + { + return user; + } + + DWORD token_size = 0; + GetTokenInformation(token, TokenUser, nullptr, 0, &token_size); + + if (token_size < 0) + { + return user; + } + + std::vector token_buffer(token_size); + GetTokenInformation(token, TokenUser, token_buffer.data(), token_size, &token_size); + TOKEN_USER* user_ptr = (TOKEN_USER*)token_buffer.data(); + PSID psid = user_ptr->User.Sid; + DWORD user_buf_size = 0; + DWORD domain_buf_size = 0; + SID_NAME_USE sid_name; + LookupAccountSidW(nullptr, psid, nullptr, &user_buf_size, nullptr, &domain_buf_size, &sid_name); + if (!user_buf_size || !domain_buf_size) + { + return user; + } + + user.resize(user_buf_size); + domain.resize(domain_buf_size); + LookupAccountSidW(nullptr, psid, user.data(), &user_buf_size, domain.data(), &domain_buf_size, &sid_name); + user.resize(user.size() - 1); + domain.resize(domain.size() - 1); + CloseHandle(token); + CloseHandle(process); + + return user; +} + + std::vector NtdllExtensions::processes() noexcept { auto get_info_result = NtQuerySystemInformationMemoryLoop(SystemProcessInformation); @@ -258,6 +309,7 @@ std::vector NtdllExtensions::processes() noexcept item.name = unicode_to_str(info_ptr->ImageName); item.pid = (DWORD)(uintptr_t)info_ptr->UniqueProcessId; item.modules = process_modules(item.pid); + item.user = pid_to_user(item.pid); result.push_back(item); } diff --git a/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.h b/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.h index 1d465161dcd..57227ac37da 100644 --- a/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.h +++ b/src/modules/FileLocksmith/FileLocksmithLibInterop/NtdllExtensions.h @@ -29,6 +29,7 @@ class NtdllExtensions : protected Ntdll { DWORD pid; std::wstring name; + std::wstring user; std::vector modules; }; @@ -44,6 +45,9 @@ class NtdllExtensions : protected Ntdll std::wstring path_to_kernel_name(LPCWSTR path); + // Gives the user name of the account running this process + std::wstring pid_to_user(DWORD pid); + std::vector handles() noexcept; // Returns the list of all processes. diff --git a/src/modules/FileLocksmith/FileLocksmithLibInterop/interop.cpp b/src/modules/FileLocksmith/FileLocksmithLibInterop/interop.cpp index 6d3eb6de275..f4406b84068 100644 --- a/src/modules/FileLocksmith/FileLocksmithLibInterop/interop.cpp +++ b/src/modules/FileLocksmith/FileLocksmithLibInterop/interop.cpp @@ -10,6 +10,7 @@ namespace FileLocksmith::Interop { System::String^ name; System::UInt32 pid; + System::String^ user; array^ files; }; @@ -69,6 +70,7 @@ namespace FileLocksmith::Interop item->name = from_wstring_view(result_cpp[i].name); item->pid = result_cpp[i].pid; + item->user = from_wstring_view(result_cpp[i].user); const int n_files = static_cast(result_cpp[i].files.size()); item->files = gcnew array(n_files); @@ -83,12 +85,6 @@ namespace FileLocksmith::Interop return result; } - static System::String^ PidToUser(System::UInt32 pid) - { - auto user_cpp = pid_to_user(pid); - return from_wstring_view(user_cpp); - } - static System::String^ PidToFullPath(System::UInt32 pid) { auto path_cpp = pid_to_full_path(pid); @@ -180,5 +176,72 @@ namespace FileLocksmith::Interop return false; } + + /* Adapted from "https://learn.microsoft.com/en-us/windows/win32/secauthz/enabling-and-disabling-privileges-in-c--" */ + static System::Boolean SetDebugPrivilege() + { + HANDLE hToken; + TOKEN_PRIVILEGES tp; + LUID luid; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != 0) + { + if (!LookupPrivilegeValue( + NULL, // lookup privilege on local system + SE_DEBUG_NAME, // privilege to lookup + &luid)) // receives LUID of privilege + { + CloseHandle(hToken); + return false; + } + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges( + hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + (PTOKEN_PRIVILEGES)NULL, + (PDWORD)NULL)) + { + CloseHandle(hToken); + return false; + } + + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) + { + CloseHandle(hToken); + return false; + } + + CloseHandle(hToken); + return true; + } + return false; + } + + // adapted from common/utils/elevation.h. No need to bring all dependencies to this project, though. + // TODO: Make elevation.h lighter so that this function can be used without bringing dependencies like spdlog in. + static System::Boolean IsProcessElevated() + { + HANDLE token = nullptr; + bool elevated = false; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) + { + TOKEN_ELEVATION elevation; + DWORD size; + if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) + { + elevated = (elevation.TokenIsElevated != 0); + } + } + if (token) + { + CloseHandle(token); + } + return elevated; + } }; } diff --git a/src/modules/FileLocksmith/FileLocksmithUI/App.xaml.cs b/src/modules/FileLocksmith/FileLocksmithUI/App.xaml.cs index 6ad1997a913..a55714470a3 100644 --- a/src/modules/FileLocksmith/FileLocksmithUI/App.xaml.cs +++ b/src/modules/FileLocksmith/FileLocksmithUI/App.xaml.cs @@ -40,7 +40,17 @@ protected override void OnLaunched(LaunchActivatedEventArgs args) return; } - _window = new MainWindow(Environment.GetCommandLineArgs().Contains("--elevated")); + bool isElevated = FileLocksmith.Interop.NativeMethods.IsProcessElevated(); + + if (isElevated) + { + if (!FileLocksmith.Interop.NativeMethods.SetDebugPrivilege()) + { + Logger.LogWarning("Couldn't set debug privileges to see system processes."); + } + } + + _window = new MainWindow(isElevated); _window.Activate(); } diff --git a/src/modules/FileLocksmith/FileLocksmithUI/Converters/PidToUserConverter.cs b/src/modules/FileLocksmith/FileLocksmithUI/Converters/UserToSystemWarningVisibilityConverter.cs similarity index 51% rename from src/modules/FileLocksmith/FileLocksmithUI/Converters/PidToUserConverter.cs rename to src/modules/FileLocksmith/FileLocksmithUI/Converters/UserToSystemWarningVisibilityConverter.cs index 181035325d6..a4ea8199ef6 100644 --- a/src/modules/FileLocksmith/FileLocksmithUI/Converters/PidToUserConverter.cs +++ b/src/modules/FileLocksmith/FileLocksmithUI/Converters/UserToSystemWarningVisibilityConverter.cs @@ -5,19 +5,29 @@ namespace PowerToys.FileLocksmithUI.Converters { using System; + using System.Globalization; using FileLocksmith.Interop; + using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Data; - public sealed class PidToUserConverter : IValueConverter + public sealed class UserToSystemWarningVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { - return NativeMethods.PidToUser((uint)value); + string user = ((string)value).ToUpperInvariant().Trim(); + if (user.Equals("SYSTEM", StringComparison.Ordinal) || user.Equals("LOCALSYSTEM", StringComparison.Ordinal)) + { + return Visibility.Visible; + } + else + { + return Visibility.Collapsed; + } } public object ConvertBack(object value, Type targetType, object parameter, string language) { - return value; + throw new NotSupportedException(); } } } diff --git a/src/modules/FileLocksmith/FileLocksmithUI/Strings/en-us/Resources.resw b/src/modules/FileLocksmith/FileLocksmithUI/Strings/en-us/Resources.resw index 44efbce38e8..77646068ffd 100644 --- a/src/modules/FileLocksmith/FileLocksmithUI/Strings/en-us/Resources.resw +++ b/src/modules/FileLocksmith/FileLocksmithUI/Strings/en-us/Resources.resw @@ -136,6 +136,9 @@ Click to see the entire list of paths. Paths as in file paths that were selected for the utility to check. + + The process belongs to a system user. Closing it may cause the system to malfunction. + Selected file paths Paths as in file paths that were selected for the utility to check. diff --git a/src/modules/FileLocksmith/FileLocksmithUI/Views/MainPage.xaml b/src/modules/FileLocksmith/FileLocksmithUI/Views/MainPage.xaml index 07c12f27d50..427792a8c42 100644 --- a/src/modules/FileLocksmith/FileLocksmithUI/Views/MainPage.xaml +++ b/src/modules/FileLocksmith/FileLocksmithUI/Views/MainPage.xaml @@ -25,7 +25,7 @@ TrueValue="Collapsed" /> - + @@ -116,6 +116,17 @@ + + + + + + + @@ -137,7 +149,7 @@ + Text="{x:Bind user}" /> @@ -199,7 +211,7 @@ x:Uid="SelectedFilesListDialog" > - +