diff --git a/docs/docs/usage/scripts.md b/docs/docs/usage/scripts.md new file mode 100644 index 00000000..15d0a343 --- /dev/null +++ b/docs/docs/usage/scripts.md @@ -0,0 +1,27 @@ +--- +::sidebar_position: 1 +id: scripts +title: Usage on scripts +hide_title: true +--- +## Scripts + +This folder contains sample scripts demonstrating how to use `gsudo` to elevate privileges on a Windows machine. The provided scripts include: + +1. **Script Self-Elevation:** A technique to ensure that the current script is running elevated, by detecting when it is not, and elevating itself. More details can be found in the [gsudo documentation on script self-elevation](https://gerardog.github.io/gsudo/docs/tips/script-self-elevation). + + - [`self-elevate.cmd`](./self-elevate.cmd): Batch script version + - [`self-elevate-one-liner.cmd`](./self-elevate-one-liner.cmd): A one-liner version of the batch script. + - [`self-elevate.ps1`](./self-elevate.ps1): PowerShell version. + - [`self-elevate-without-gsudo.cmd`](./self-elevate-without-gsudo.cmd): Example without using `gsudo`. + +2. **Many Elevations Using gsudo Cache:** + + - [`many-elevations-using-gsudo-cache.cmd`](./many-elevations-using-gsudo-cache.cmd): Batch script version + - [`many-elevations-using-gsudo-cache.ps1`](./many-elevations-using-gsudo-cache.ps1): PowerShell version + +3. **Don't show an UAC pop-up:** Perform an elevated admin task if and only if it can be done without an interactive UAC pop-up. (i.e. when already elevated or gsudo cache is active) + - [`silent-elevation-one-liner.cmd`](./silent-elevation-one-liner.cmd): A one-liner version. + - [`silent-elevation.cmd`](./silent-elevation.cmd): Verbose version . + +These scripts are examples and should be used with caution. Always review and understand the code you are executing on your system. diff --git a/src/gsudo/Commands/CtrlCCommand.cs b/src/gsudo/Commands/CtrlCCommand.cs index 718d8ea0..13dd9510 100644 --- a/src/gsudo/Commands/CtrlCCommand.cs +++ b/src/gsudo/Commands/CtrlCCommand.cs @@ -2,6 +2,7 @@ using System; using System.Globalization; using System.Threading.Tasks; +using Windows.Win32; using static gsudo.Native.ConsoleApi; namespace gsudo.Commands @@ -9,22 +10,22 @@ namespace gsudo.Commands // Required for sending Ctrl-C / Ctrl-Break to the elevated process on VT & piped Mode. class CtrlCCommand : ICommand { - public int Pid { get; set; } + public uint Pid { get; set; } public bool SendSigBreak { get; set; } public Task Execute() { - FreeConsole(); + PInvoke.FreeConsole(); - if (AttachConsole(Pid)) + if (PInvoke.AttachConsole(Pid)) { if (SendSigBreak) - GenerateConsoleCtrlEvent(CtrlTypes.CTRL_BREAK_EVENT, 0); + PInvoke.GenerateConsoleCtrlEvent((uint)CtrlTypes.CTRL_BREAK_EVENT, 0); else - GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); + PInvoke.GenerateConsoleCtrlEvent((uint)CtrlTypes.CTRL_C_EVENT, 0); - FreeConsole(); + PInvoke.FreeConsole(); } else { diff --git a/src/gsudo/Commands/RunCommand.cs b/src/gsudo/Commands/RunCommand.cs index a58af99e..9e0e2511 100644 --- a/src/gsudo/Commands/RunCommand.cs +++ b/src/gsudo/Commands/RunCommand.cs @@ -9,7 +9,8 @@ using System.Linq; using System.Security.Principal; using System.Threading.Tasks; - +using Windows.Win32; + namespace gsudo.Commands { public class RunCommand : ICommand @@ -62,7 +63,7 @@ public async Task Execute() NewWindow = InputArguments.NewWindow, Wait = (!commandBuilder.IsWindowsApp && !InputArguments.NewWindow) || InputArguments.Wait, Mode = elevationMode, - ConsoleProcessId = Process.GetCurrentProcess().Id, + ConsoleProcessId = (uint) Process.GetCurrentProcess().Id, IntegrityLevel = InputArguments.GetIntegrityLevel(), ConsoleWidth = consoleWidth, ConsoleHeight = consoleHeight, @@ -154,7 +155,7 @@ private static int RunWithoutService(ElevationRequest elevationRequest) { var sameIntegrity = (int)InputArguments.GetIntegrityLevel() == SecurityHelper.GetCurrentIntegrityLevel(); // No need to escalate. Run in-process - Native.ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); ConsoleHelper.SetPrompt(elevationRequest); diff --git a/src/gsudo/ElevationRequest.cs b/src/gsudo/ElevationRequest.cs index 37fc55ed..6e2a163e 100644 --- a/src/gsudo/ElevationRequest.cs +++ b/src/gsudo/ElevationRequest.cs @@ -15,7 +15,7 @@ class ElevationRequest public int ConsoleWidth { get; set; } public int ConsoleHeight { get; set; } public ConsoleMode Mode { get; set; } - public int ConsoleProcessId { get; set; } + public uint ConsoleProcessId { get; set; } public int TargetProcessId { get; set; } public bool KillCache { get; set; } public IntegrityLevel IntegrityLevel { get; set; } diff --git a/src/gsudo/Helpers/ArgumentsHelper.cs b/src/gsudo/Helpers/ArgumentsHelper.cs index 52a8e971..6bc10baf 100644 --- a/src/gsudo/Helpers/ArgumentsHelper.cs +++ b/src/gsudo/Helpers/ArgumentsHelper.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using Windows.Win32; namespace gsudo.Helpers { @@ -40,8 +41,7 @@ public static IList SplitArgs(string args) internal static string GetRealCommandLine() { - System.IntPtr ptr = ConsoleApi.GetCommandLine(); - string commandLine = Marshal.PtrToStringAuto(ptr).TrimStart(); + string commandLine = PInvoke.GetCommandLine().ToString().TrimStart(); if (commandLine[0] == '"') return commandLine.Substring(commandLine.IndexOf('"', 1) + 1).TrimStart(' '); diff --git a/src/gsudo/Helpers/CommandLineParser.cs b/src/gsudo/Helpers/CommandLineParser.cs index cb405d2f..26a1be71 100644 --- a/src/gsudo/Helpers/CommandLineParser.cs +++ b/src/gsudo/Helpers/CommandLineParser.cs @@ -207,7 +207,7 @@ private ICommand ParseVerb() if (arg.In("gsudoctrlc")) return new CtrlCCommand() { - Pid = int.Parse(DeQueueArg(), CultureInfo.InvariantCulture), + Pid = uint.Parse(DeQueueArg(), CultureInfo.InvariantCulture), SendSigBreak = bool.Parse(DeQueueArg()) }; diff --git a/src/gsudo/Helpers/ConsoleHelper.cs b/src/gsudo/Helpers/ConsoleHelper.cs index a583c42b..2f92ea62 100644 --- a/src/gsudo/Helpers/ConsoleHelper.cs +++ b/src/gsudo/Helpers/ConsoleHelper.cs @@ -4,27 +4,34 @@ using System.Runtime.InteropServices; using System.Security; using static gsudo.Native.ConsoleApi; - +using Windows.Win32; +using Windows.Win32.System.Console; +using Microsoft.Win32.SafeHandles; +using Windows.Win32.Foundation; + namespace gsudo.Helpers { class ConsoleHelper - { + { + const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF; + static ConsoleHelper() { IgnoreConsoleCancelKeyPress += IgnoreConsoleCancelKeyPressMethod; // ensure no garbage collection } - public static bool EnableVT() + public static unsafe bool EnableVT() { - var hStdOut = Native.ConsoleApi.GetStdHandle(Native.ConsoleApi.STD_OUTPUT_HANDLE); - if (!Native.ConsoleApi.GetConsoleMode(hStdOut, out uint outConsoleMode)) + var hStdOut = PInvoke.GetStdHandle(STD_HANDLE.STD_OUTPUT_HANDLE); + CONSOLE_MODE outConsoleMode; + if (!PInvoke.GetConsoleMode(hStdOut, &outConsoleMode)) { Logger.Instance.Log("Could not get console mode", LogLevel.Debug); return false; } - outConsoleMode |= Native.ConsoleApi.ENABLE_VIRTUAL_TERMINAL_PROCESSING;// | Native.ConsoleApi.DISABLE_NEWLINE_AUTO_RETURN; - if (!Native.ConsoleApi.SetConsoleMode(hStdOut, outConsoleMode)) + outConsoleMode |= CONSOLE_MODE.ENABLE_VIRTUAL_TERMINAL_PROCESSING;// | CONSOLE_MODE.DISABLE_NEWLINE_AUTO_RETURN; + if (!PInvoke.SetConsoleMode(hStdOut, outConsoleMode)) { Logger.Instance.Log("Could not enable virtual terminal processing", LogLevel.Error); return false; @@ -34,11 +41,11 @@ public static bool EnableVT() return true; } - internal static SetConsoleCtrlEventHandler IgnoreConsoleCancelKeyPress; + internal static PHANDLER_ROUTINE IgnoreConsoleCancelKeyPress; - private static bool IgnoreConsoleCancelKeyPressMethod(CtrlTypes ctrlType) + private static BOOL IgnoreConsoleCancelKeyPressMethod(uint ctrlType) { - if (ctrlType.In(CtrlTypes.CTRL_C_EVENT, CtrlTypes.CTRL_BREAK_EVENT)) + if (ctrlType == (uint)CtrlTypes.CTRL_C_EVENT || ctrlType == (uint)CtrlTypes.CTRL_BREAK_EVENT) return true; return false; @@ -46,38 +53,40 @@ private static bool IgnoreConsoleCancelKeyPressMethod(CtrlTypes ctrlType) public static uint[] GetConsoleAttachedPids() { - var processIds = new uint[1]; - var num = ConsoleApi.GetConsoleProcessList(processIds, 1); + var processIds = new uint[1].AsSpan(); + var num = PInvoke.GetConsoleProcessList(processIds); if (num == 0) throw new System.ComponentModel.Win32Exception(); - processIds = new uint[num]; + processIds = new uint[num].AsSpan(); - num = ConsoleApi.GetConsoleProcessList(processIds, num); + num = PInvoke.GetConsoleProcessList(processIds); if (num == 0) throw new System.ComponentModel.Win32Exception(); //** weird workaround for .net 7.0 NativeAOT + git-bash ** if (processIds[0] == 0) - num = ConsoleApi.GetConsoleProcessList(processIds, num); + num = PInvoke.GetConsoleProcessList(processIds); if (processIds[0] == 0) - num = ConsoleApi.GetConsoleProcessList(processIds, num); + num = PInvoke.GetConsoleProcessList(processIds); //************************************************** - return processIds; + return processIds.ToArray(); } public static void GetConsoleInfo(out int width, out int height, out int cursorLeftPos, out int cursorTopPos) { if (Console.IsOutputRedirected && Console.IsErrorRedirected) { - var hConsole = Native.FileApi.CreateFile("CONOUT$", - FileApi.GENERIC_READ, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); + var hConsole = PInvoke.CreateFile("CONOUT$", FileApi.GENERIC_READ, + Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_NONE, null, + Windows.Win32.Storage.FileSystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING, + 0, null); - if (hConsole == Native.FileApi.INVALID_HANDLE_VALUE) + if (hConsole.IsInvalid) throw new System.ComponentModel.Win32Exception(); - var consoleScreenBufferInfoEx = new CONSOLE_SCREEN_BUFFER_INFO_EX(); - consoleScreenBufferInfoEx.cbSize = Marshal.SizeOf(); + var consoleScreenBufferInfoEx = new CONSOLE_SCREEN_BUFFER_INFOEX(); + consoleScreenBufferInfoEx.cbSize = (uint)Marshal.SizeOf(); - if (!GetConsoleScreenBufferInfoEx(hConsole, ref consoleScreenBufferInfoEx)) + if (!PInvoke.GetConsoleScreenBufferInfoEx(hConsole, ref consoleScreenBufferInfoEx)) throw new System.ComponentModel.Win32Exception(); width = consoleScreenBufferInfoEx.srWindow.Right - consoleScreenBufferInfoEx.srWindow.Left + 1; @@ -85,7 +94,7 @@ public static void GetConsoleInfo(out int width, out int height, out int cursorL cursorLeftPos = consoleScreenBufferInfoEx.dwCursorPosition.X; cursorTopPos = consoleScreenBufferInfoEx.dwCursorPosition.Y; - FileApi.CloseHandle(hConsole); + hConsole.Close(); } else { diff --git a/src/gsudo/Helpers/ProcessFactory.cs b/src/gsudo/Helpers/ProcessFactory.cs index ebb10e47..7532fea8 100644 --- a/src/gsudo/Helpers/ProcessFactory.cs +++ b/src/gsudo/Helpers/ProcessFactory.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security; +using Windows.Win32; +using Windows.Win32.System.Console; using static gsudo.Native.ProcessApi; using static gsudo.Native.TokensApi; @@ -319,9 +321,9 @@ private static SafeProcessHandle CreateProcessWithToken(IntPtr newToken, string if (Console.IsErrorRedirected | Console.IsInputRedirected | Console.IsOutputRedirected) { startupInfo.dwFlags |= STARTF_USESTDHANDLES; - startupInfo.hStdOutput = ConsoleApi.GetStdHandle(ConsoleApi.STD_OUTPUT_HANDLE); - startupInfo.hStdInput = ConsoleApi.GetStdHandle(ConsoleApi.STD_INPUT_HANDLE); - startupInfo.hStdError = ConsoleApi.GetStdHandle(ConsoleApi.STD_ERROR_HANDLE); + startupInfo.hStdOutput = PInvoke.GetStdHandle(STD_HANDLE.STD_OUTPUT_HANDLE); + startupInfo.hStdInput = PInvoke.GetStdHandle(STD_HANDLE.STD_INPUT_HANDLE); + startupInfo.hStdError = PInvoke.GetStdHandle(STD_HANDLE.STD_ERROR_HANDLE); } PROCESS_INFORMATION processInformation; @@ -360,7 +362,7 @@ internal static void CreateProcessForTokenReplacement(string lpApplicationName, Logger.Instance.Log($"Creating target process: {lpApplicationName} {args}", LogLevel.Debug); if (!ProcessApi.CreateProcess(null, command, ref pSec, ref tSec, false, dwCreationFlags, IntPtr.Zero, null, ref sInfoEx, out pInfo)) { - throw new Win32Exception((int)ConsoleApi.GetLastError()); + throw new Win32Exception(); } var currentProcessHandle = ProcessApi.GetCurrentProcess(); diff --git a/src/gsudo/Helpers/ProcessHelper.cs b/src/gsudo/Helpers/ProcessHelper.cs index f6bdf084..6beef2c9 100644 --- a/src/gsudo/Helpers/ProcessHelper.cs +++ b/src/gsudo/Helpers/ProcessHelper.cs @@ -227,7 +227,7 @@ public static AutoResetEvent GetProcessWaitHandle(IntPtr processHandle) => SafeWaitHandle = new SafeWaitHandle(processHandle, ownsHandle: false) }; - public static SafeProcessHandle GetSafeProcessHandle(this Process p) => new SafeProcessHandle(p.Handle, true); + public static SafeProcessHandle GetSafeProcessHandle(this Process p) => p.SafeHandle; public static AutoResetEvent GetProcessWaitHandle(this SafeProcessHandle processHandle) => new AutoResetEvent(false) diff --git a/src/gsudo/Helpers/SymbolicLinkSupport.cs b/src/gsudo/Helpers/SymbolicLinkSupport.cs index b4d24bc6..d7f79ad3 100644 --- a/src/gsudo/Helpers/SymbolicLinkSupport.cs +++ b/src/gsudo/Helpers/SymbolicLinkSupport.cs @@ -5,7 +5,8 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Text; - +using Windows.Win32; + namespace gsudo.Helpers { static class SymbolicLinkSupport @@ -48,33 +49,35 @@ public static string ResolveSymbolicLink(string symLinkFullPath) } private static string GetFinalPathName(string path) { - var h = Native.FileApi.CreateFile(path, + using (var h = PInvoke.CreateFile(path, Native.FileApi.FILE_READ_EA, - FileShare.ReadWrite | FileShare.Delete, - IntPtr.Zero, - FileMode.Open, - Native.FileApi.FILE_FLAG_BACKUP_SEMANTICS, - IntPtr.Zero); + Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_READ | Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_WRITE | Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_DELETE, + null, + Windows.Win32.Storage.FileSystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING, + Windows.Win32.Storage.FileSystem.FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_BACKUP_SEMANTICS, + null)) + { + if (h.IsInvalid) + return path; - if (h == Native.FileApi.INVALID_HANDLE_VALUE) - return path; + uint res; - try - { - var sb = new StringBuilder(1024); - var res = Native.FileApi.GetFinalPathNameByHandle(h, sb, 1024, 0); + Span text = stackalloc char[1024]; // value gotten from GetWindowTextLength + unsafe + { + fixed (char* pText = text) + { + res = PInvoke.GetFinalPathNameByHandle(h, pText, 1024, 0); + } - if (res == 0) - { - Logger.Instance.Log($"{nameof(SymbolicLinkSupport)}.{nameof(GetFinalPathName)} failed with: {new Win32Exception()}", LogLevel.Debug); - return path; // Sad workaround: do not resolve the symlink. - } + if (res == 0) + { + Logger.Instance.Log($"{nameof(SymbolicLinkSupport)}.{nameof(GetFinalPathName)} failed with: {new Win32Exception()}", LogLevel.Debug); + return path; // Sad workaround: do not resolve the symlink. + } - return sb.ToString(); - } - finally - { - Native.FileApi.CloseHandle(h); + return text.Slice(0, (int)res).ToString(); + } } } } diff --git a/src/gsudo/Native/ConsoleApi.cs b/src/gsudo/Native/ConsoleApi.cs index 32874e10..ea9449d9 100644 --- a/src/gsudo/Native/ConsoleApi.cs +++ b/src/gsudo/Native/ConsoleApi.cs @@ -10,24 +10,6 @@ namespace gsudo.Native /// static class ConsoleApi { - internal const int STD_INPUT_HANDLE = -10; - internal const int STD_OUTPUT_HANDLE = -11; - internal const int STD_ERROR_HANDLE = -12; - - internal const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; - internal const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008; - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern IntPtr GetStdHandle(int nStdHandle); - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint mode); - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool GetConsoleMode(IntPtr handle, out uint mode); - - internal delegate bool ConsoleEventDelegate(CtrlTypes ctrlType); - internal enum CtrlTypes : uint { CTRL_C_EVENT = 0, @@ -36,113 +18,5 @@ internal enum CtrlTypes : uint CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } - - internal delegate bool SetConsoleCtrlEventHandler(CtrlTypes sig); - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool SetConsoleCtrlHandler(SetConsoleCtrlEventHandler callback, bool add); - - [DllImport("kernel32.dll")] - public static extern uint GetLastError(); - - [DllImport("kernel32.dll")] - internal static extern bool SetConsoleCursorPosition(IntPtr hConsoleOutput, PseudoConsoleApi.COORD CursorPosition); - - - // send ctrl-c - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool AttachConsole(int dwProcessId); - - [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] - internal static extern bool FreeConsole(); - [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] - internal static extern bool AllocConsole(); - - // Enumerated type for the control messages sent to the handler routine - - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - public static extern System.IntPtr GetCommandLine(); - - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern uint GetConsoleProcessList(uint[] processList, uint processCount); - - /// - /// Retrieves a handle to the Shell's desktop window. - /// - /// Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633512%28v=vs.85%29.aspx for more - /// information - /// - /// - /// - /// C++ ( Type: HWND )
The return value is the handle of the Shell's desktop window. If no Shell process is - /// present, the return value is NULL. - ///
- [DllImport("user32.dll")] - internal static extern IntPtr GetShellWindow(); - - [DllImport("user32.dll", SetLastError = true)] - internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool GetConsoleScreenBufferInfoEx( - IntPtr hConsoleOutput, - ref CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfo - ); - - [StructLayout(LayoutKind.Sequential)] - public struct CONSOLE_SCREEN_BUFFER_INFO_EX - { - public int cbSize; - public COORD dwSize; - public COORD dwCursorPosition; - public short wAttributes; - public SMALL_RECT srWindow; - public COORD dwMaximumWindowSize; - - public ushort wPopupAttributes; - public bool bFullscreenSupported; - - internal COLORREF black; - internal COLORREF darkBlue; - internal COLORREF darkGreen; - internal COLORREF darkCyan; - internal COLORREF darkRed; - internal COLORREF darkMagenta; - internal COLORREF darkYellow; - internal COLORREF gray; - internal COLORREF darkGray; - internal COLORREF blue; - internal COLORREF green; - internal COLORREF cyan; - internal COLORREF red; - internal COLORREF magenta; - internal COLORREF yellow; - internal COLORREF white; - - // has been a while since I did this, test before use - // but should be something like: - // - // [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] - // public COLORREF[] ColorTable; - } - - [StructLayout(LayoutKind.Sequential)] - public struct COLORREF - { - public uint ColorDWORD; - } - public struct SMALL_RECT - { - - public short Left; - public short Top; - public short Right; - public short Bottom; - - } } } diff --git a/src/gsudo/Native/FileApi.cs b/src/gsudo/Native/FileApi.cs index 7bcaba01..2a69ed58 100644 --- a/src/gsudo/Native/FileApi.cs +++ b/src/gsudo/Native/FileApi.cs @@ -7,31 +7,12 @@ namespace gsudo.Native { static class FileApi { - internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); - internal const uint FILE_READ_EA = 0x0008; internal const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000; public const uint GENERIC_READ = (0x80000000); public const uint GENERIC_WRITE = (0x40000000); - [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern uint GetFinalPathNameByHandle(IntPtr hFile, StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CloseHandle(IntPtr hObject); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - internal static extern IntPtr CreateFile( - [MarshalAs(UnmanagedType.LPWStr)] string filename, - [MarshalAs(UnmanagedType.U4)] uint access, - [MarshalAs(UnmanagedType.U4)] FileShare share, - IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero - [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, - [MarshalAs(UnmanagedType.U4)] uint flagsAndAttributes, - IntPtr templateFile); - #region IsWindowsApp Win32 Api [DllImport("shell32.dll", CharSet = CharSet.Unicode)] internal static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); diff --git a/src/gsudo/Native/NativeMethods.cs b/src/gsudo/Native/NativeMethods.cs index 2f0c4018..4fa57fb0 100644 --- a/src/gsudo/Native/NativeMethods.cs +++ b/src/gsudo/Native/NativeMethods.cs @@ -43,32 +43,6 @@ internal static partial class NativeMethods TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - internal static extern IntPtr GetCurrentProcess(); - - [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool OpenProcessToken(IntPtr processHandle, - uint desiredAccesss, - out IntPtr tokenHandle); - - [DllImport("Advapi32.dll", SetLastError = true)] - internal static extern bool OpenThreadToken(IntPtr ThreadToken, TokenAccessLevels DesiredAccess, bool OpenAsSelf, out SafeTokenHandle TokenHandle); - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern IntPtr GetCurrentThread(); - - [DllImport("Advapi32.dll", SetLastError = true)] - public static extern bool SetThreadToken(IntPtr Thread, SafeTokenHandle Token); - - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CloseHandle(IntPtr hObject); - - [DllImport("advapi32.dll", SetLastError = true)] - internal static extern bool GetKernelObjectSecurity(IntPtr Handle, uint securityInformation, IntPtr pSecurityDescriptor, uint nLength, out uint lpnLengthNeeded); - [DllImport("advapi32.dll", SetLastError = true)] internal static extern bool SetKernelObjectSecurity(IntPtr Handle, uint securityInformation, IntPtr pSecurityDescriptor); diff --git a/src/gsudo/NativeMethods.txt b/src/gsudo/NativeMethods.txt new file mode 100644 index 00000000..922886b0 --- /dev/null +++ b/src/gsudo/NativeMethods.txt @@ -0,0 +1,23 @@ +// Console +GetStdHandle +SetConsoleMode +GetConsoleMode + +AttachConsole +FreeConsole +AllocConsole + +// Ctr-C Handling +SetConsoleCtrlHandler +GenerateConsoleCtrlEvent + +GetCommandLine +GetConsoleProcessList +GetConsoleScreenBufferInfoEx + +GetShellWindow +GetWindowThreadProcessId + +CreateFile +GetFinalPathNameByHandle +GetWindowText \ No newline at end of file diff --git a/src/gsudo/ProcessHosts/AttachedConsoleHost.cs b/src/gsudo/ProcessHosts/AttachedConsoleHost.cs index d18b02aa..fe6dbb07 100644 --- a/src/gsudo/ProcessHosts/AttachedConsoleHost.cs +++ b/src/gsudo/ProcessHosts/AttachedConsoleHost.cs @@ -1,9 +1,10 @@ using System; -using System.Security.Principal; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using gsudo.Helpers; using gsudo.Rpc; +using Windows.Win32; using static gsudo.Native.ConsoleApi; namespace gsudo.ProcessHosts @@ -26,23 +27,23 @@ public async Task Start(Connection connection, ElevationRequest elevationRequest try { - Native.ConsoleApi.FreeConsole(); - int pid = elevationRequest.ConsoleProcessId; - if (Native.ConsoleApi.AttachConsole(pid)) + PInvoke.FreeConsole(); + uint pid = elevationRequest.ConsoleProcessId; + if (PInvoke.AttachConsole(pid)) { - Native.ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); try { - try - { - System.Environment.CurrentDirectory = elevationRequest.StartFolder; + try + { + System.Environment.CurrentDirectory = elevationRequest.StartFolder; } catch (UnauthorizedAccessException ex) - { + { throw new ApplicationException($"User \"{WindowsIdentity.GetCurrent().Name}\" can not access current directory \"{elevationRequest.StartFolder}\""); - } - + } + var process = Helpers.ProcessFactory.StartAttached(elevationRequest.FileName, elevationRequest.Arguments); WaitHandle.WaitAny(new WaitHandle[] { process.GetProcessWaitHandle(), connection.DisconnectedWaitHandle }); @@ -79,8 +80,8 @@ public async Task Start(Connection connection, ElevationRequest elevationRequest } finally { - Native.ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); - Native.ConsoleApi.FreeConsole(); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); + PInvoke.FreeConsole(); await connection.FlushAndCloseAll().ConfigureAwait(false); } } diff --git a/src/gsudo/ProcessHosts/PipedProcessHost.cs b/src/gsudo/ProcessHosts/PipedProcessHost.cs index 818b98b4..028e78bf 100644 --- a/src/gsudo/ProcessHosts/PipedProcessHost.cs +++ b/src/gsudo/ProcessHosts/PipedProcessHost.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Windows.Win32; using static gsudo.Native.ConsoleApi; namespace gsudo.ProcessHosts @@ -27,7 +28,7 @@ class PipedProcessHost : IProcessHost public async Task Start(Connection connection, ElevationRequest request) { - Native.ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); _connection = connection; _request = request; @@ -68,7 +69,7 @@ public async Task Start(Connection connection, ElevationRequest request) } finally { - Native.ConsoleApi.SetConsoleCtrlHandler(HandleConsoleCancelKeyPress, false); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); if (process != null && !process.HasExited) { process?.Terminate(); @@ -77,14 +78,6 @@ public async Task Start(Connection connection, ElevationRequest request) } } - private static bool HandleConsoleCancelKeyPress(CtrlTypes ctrlType) - { - if (ctrlType.In(CtrlTypes.CTRL_C_EVENT, CtrlTypes.CTRL_BREAK_EVENT)) - return true; - - return false; - } - private bool ShouldWait(StreamReader streamReader) { try diff --git a/src/gsudo/ProcessHosts/TokenSwitchHost.cs b/src/gsudo/ProcessHosts/TokenSwitchHost.cs index c1bdc0c6..9e1fda51 100644 --- a/src/gsudo/ProcessHosts/TokenSwitchHost.cs +++ b/src/gsudo/ProcessHosts/TokenSwitchHost.cs @@ -35,7 +35,7 @@ await connection.ControlStream } finally { - Native.ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); + Windows.Win32.PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); await connection.FlushAndCloseAll().ConfigureAwait(false); } } diff --git a/src/gsudo/ProcessHosts/VTProcessHost.cs b/src/gsudo/ProcessHosts/VTProcessHost.cs index d1db5743..42dfdb2b 100644 --- a/src/gsudo/ProcessHosts/VTProcessHost.cs +++ b/src/gsudo/ProcessHosts/VTProcessHost.cs @@ -174,9 +174,9 @@ private async Task CopyPipeToOutput(SafeFileHandle outputReadSide) /// private static void OnClose(Action handler) { - Native.ConsoleApi.SetConsoleCtrlHandler(eventType => + Windows.Win32.PInvoke.SetConsoleCtrlHandler(eventType => { - if (eventType == Native.ConsoleApi.CtrlTypes.CTRL_CLOSE_EVENT) + if (eventType == (uint) Native.ConsoleApi.CtrlTypes.CTRL_CLOSE_EVENT) { handler(); } diff --git a/src/gsudo/ProcessRenderers/TokenSwitchRenderer.cs b/src/gsudo/ProcessRenderers/TokenSwitchRenderer.cs index 8a6214dd..5792ecb4 100644 --- a/src/gsudo/ProcessRenderers/TokenSwitchRenderer.cs +++ b/src/gsudo/ProcessRenderers/TokenSwitchRenderer.cs @@ -10,7 +10,8 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; - +using Windows.Win32; + namespace gsudo.ProcessRenderers { /// @@ -61,7 +62,7 @@ internal TokenSwitchRenderer(Connection connection, ElevationRequest elevationRe elevationRequest.TargetProcessId = processId; if (!elevationRequest.NewWindow) - ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); } public Task Start() @@ -109,7 +110,7 @@ public Task Start() { _processHandle?.Close(); _threadHandle?.Close(); - ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); + PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); } } diff --git a/src/gsudo/PseudoConsole/PseudoConsole.cs b/src/gsudo/PseudoConsole/PseudoConsole.cs index 46b15265..2107c535 100644 --- a/src/gsudo/PseudoConsole/PseudoConsole.cs +++ b/src/gsudo/PseudoConsole/PseudoConsole.cs @@ -18,11 +18,6 @@ private PseudoConsole(IntPtr handle) this.Handle = handle; } - public bool SetCursorPosition(int X, int Y) - { - return Native.ConsoleApi.SetConsoleCursorPosition(Handle, new COORD { X = (short)X, Y = (short)Y }); - } - internal static PseudoConsole Create(SafeFileHandle inputReadSide, SafeFileHandle outputWriteSide, int width, int height) { bool InheritCursor = true; diff --git a/src/gsudo/Tokens/TokenProvider.cs b/src/gsudo/Tokens/TokenProvider.cs index 55bad5f9..98626184 100644 --- a/src/gsudo/Tokens/TokenProvider.cs +++ b/src/gsudo/Tokens/TokenProvider.cs @@ -8,7 +8,8 @@ using System.Linq; using System.Security.Principal; using gsudo.Helpers; - +using Windows.Win32; + namespace gsudo.Tokens { internal class TokenProvider : IDisposable @@ -204,7 +205,7 @@ public TokenProvider GetLinkedToken(uint desiredAccess = MAXIMUM_ALLOWED) return this; } - internal static TokenProvider CreateUnelevated(IntegrityLevel level) + internal static unsafe TokenProvider CreateUnelevated(IntegrityLevel level) { if (SecurityHelper.IsAdministrator()) { @@ -231,8 +232,9 @@ internal static TokenProvider CreateUnelevated(IntegrityLevel level) } else { - IntPtr hwnd = ConsoleApi.GetShellWindow(); - _ = ConsoleApi.GetWindowThreadProcessId(hwnd, out uint pid); + var hwnd = PInvoke.GetShellWindow(); + uint pid; + _ = PInvoke.GetWindowThreadProcessId(hwnd, &pid); return TokenProvider.CreateFromProcessToken((int) pid); } } @@ -356,9 +358,6 @@ public TokenProvider EnablePrivilege(Privilege securityEntity, bool throwOnFailu if (throwOnFailure) throw new Win32Exception(); - if (throwOnFailure && ConsoleApi.GetLastError() != 0) - throw new Win32Exception(); //throw new Exception("The token does not have the specified privilege. \n"); - return this; } diff --git a/src/gsudo/gsudo.csproj b/src/gsudo/gsudo.csproj index a8c08df3..36a9ecae 100644 --- a/src/gsudo/gsudo.csproj +++ b/src/gsudo/gsudo.csproj @@ -24,6 +24,7 @@ 1.0.0.0 1.0.0.0 1701;1702;CA1303;CA1707;CA1028;CA1001;CA1031;CA1416 + 9 False @@ -56,6 +57,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + all +