Move native interop code to new project.

This commit is contained in:
Jared Goodwin 2023-05-04 11:14:57 -07:00
parent cd42d6ac77
commit da79bc74e2
17 changed files with 28 additions and 2640 deletions

View File

@ -40,6 +40,7 @@
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\submodules\Immense.RemoteControl\Immense.RemoteControl.Desktop.Native\Immense.RemoteControl.Desktop.Native.csproj" />
</ItemGroup>

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.SignalR.Client;
using Immense.RemoteControl.Desktop.Native.Windows;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Remotely.Agent.Extensions;
@ -6,8 +7,6 @@ using Remotely.Agent.Interfaces;
using Remotely.Shared.Enums;
using Remotely.Shared.Models;
using Remotely.Shared.Services;
using Remotely.Shared.Utilities;
using Remotely.Shared.Win32;
using System;
using System.Collections.Generic;
using System.IO;

View File

@ -2,12 +2,8 @@ using Microsoft.Extensions.Logging;
using Remotely.Agent.Interfaces;
using Remotely.Shared.Models;
using Remotely.Shared.Services;
using Remotely.Shared.Utilities;
using Remotely.Shared.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Remotely.Agent.Services.MacOS

View File

@ -1,9 +1,9 @@
using Microsoft.AspNetCore.SignalR.Client;
using Immense.RemoteControl.Desktop.Native.Windows;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;
using Remotely.Agent.Interfaces;
using Remotely.Shared.Models;
using Remotely.Shared.Utilities;
using Remotely.Shared.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -42,7 +42,7 @@ namespace Remotely.Agent.Services.Windows
await hubConnection.SendAsync("DisplayMessage", $"Starting chat service.", "Starting chat service.", "bg-success", userConnectionId);
if (WindowsIdentity.GetCurrent().IsSystem)
{
var result = Win32Interop.OpenInteractiveProcess(
var result = Win32Interop.CreateInteractiveSystemProcess(
_rcBinaryPath +
$" --mode Chat" +
$" --host \"{_connectionInfo.Host}\"" +
@ -114,7 +114,7 @@ namespace Remotely.Agent.Services.Windows
userConnectionId);
if (WindowsIdentity.GetCurrent().IsSystem)
{
var result = Win32Interop.OpenInteractiveProcess(
var result = Win32Interop.CreateInteractiveSystemProcess(
_rcBinaryPath +
$" --mode Unattended" +
$" --host {_connectionInfo.Host}" +
@ -170,7 +170,7 @@ namespace Remotely.Agent.Services.Windows
// Give a little time for session changing, etc.
await Task.Delay(1000);
var result = Win32Interop.OpenInteractiveProcess(_rcBinaryPath +
var result = Win32Interop.CreateInteractiveSystemProcess(_rcBinaryPath +
$" --mode Unattended" +
$" --relaunch true" +
$" --host {_connectionInfo.Host}" +

View File

@ -1,12 +1,9 @@
using Microsoft.Extensions.Logging;
using Immense.RemoteControl.Desktop.Native.Windows;
using Microsoft.Extensions.Logging;
using Remotely.Agent.Interfaces;
using Remotely.Shared.Models;
using Remotely.Shared.Utilities;
using Remotely.Shared.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Remotely.Agent.Services.Windows

View File

@ -73,6 +73,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Immense.RemoteControl.Share
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Immense.RemoteControl.Desktop", "submodules\Immense.RemoteControl\Immense.RemoteControl.Desktop\Immense.RemoteControl.Desktop.csproj", "{034984DC-4B47-42E9-8648-F258C40C7926}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Immense.RemoteControl.Desktop.Native", "submodules\Immense.RemoteControl\Immense.RemoteControl.Desktop.Native\Immense.RemoteControl.Desktop.Native.csproj", "{7A8378BC-8169-4A33-93C6-47C699C5E74D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -275,6 +277,18 @@ Global
{034984DC-4B47-42E9-8648-F258C40C7926}.Release|x64.Build.0 = Release|Any CPU
{034984DC-4B47-42E9-8648-F258C40C7926}.Release|x86.ActiveCfg = Release|Any CPU
{034984DC-4B47-42E9-8648-F258C40C7926}.Release|x86.Build.0 = Release|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Debug|x64.ActiveCfg = Debug|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Debug|x64.Build.0 = Debug|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Debug|x86.ActiveCfg = Debug|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Debug|x86.Build.0 = Debug|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Release|Any CPU.Build.0 = Release|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Release|x64.ActiveCfg = Release|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Release|x64.Build.0 = Release|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Release|x86.ActiveCfg = Release|Any CPU
{7A8378BC-8169-4A33-93C6-47C699C5E74D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -290,6 +304,7 @@ Global
{8CBED18D-64A8-44C0-8433-EE14E93B472A} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{FEF0D431-EB2F-4C08-A125-8DF59AFDA525} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{034984DC-4B47-42E9-8648-F258C40C7926} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{7A8378BC-8169-4A33-93C6-47C699C5E74D} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EAE10B28-119B-437C-9E68-06F0EE3F968A}

View File

@ -1,4 +1,5 @@
using Remotely.Shared.Enums;
using Immense.RemoteControl.Desktop.Native.DataStructures;
using Remotely.Shared.Enums;
using System.Collections.Generic;
using System.Runtime.Serialization;

View File

@ -1,24 +0,0 @@
using System.Runtime.Serialization;
namespace Remotely.Shared.Models
{
[DataContract]
public enum SessionType
{
Console = 0,
RDP = 1
}
[DataContract]
public class WindowsSession
{
[DataMember(Name = "ID")]
public uint ID { get; set; }
[DataMember(Name = "Name")]
public string Name { get; set; }
[DataMember(Name = "Type")]
public SessionType Type { get; set; }
[DataMember(Name = "Username")]
public string Username { get; set; }
}
}

View File

@ -1,372 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Remotely.Shared.Win32
{
public static class ADVAPI32
{
#region Structs
public struct TOKEN_PRIVILEGES
{
public struct LUID
{
public UInt32 LowPart;
public Int32 HighPart;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}
public int PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)]
public LUID_AND_ATTRIBUTES[] Privileges;
}
public class USEROBJECTFLAGS
{
public int fInherit = 0;
public int fReserved = 0;
public int dwFlags = 0;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
#endregion
#region Enums
public enum TOKEN_INFORMATION_CLASS
{
/// <summary>
    /// The buffer receives a TOKEN_USER structure that contains the user account of the token.
    /// </summary>
TokenUser = 1,
/// <summary>
    /// The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token.
    /// </summary>
TokenGroups,
/// <summary>
    /// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token.
    /// </summary>
TokenPrivileges,
/// <summary>
    /// The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects.
    /// </summary>
TokenOwner,
/// <summary>
    /// The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects.
    /// </summary>
TokenPrimaryGroup,
/// <summary>
    /// The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects.
    /// </summary>
TokenDefaultDacl,
/// <summary>
    /// The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information.
    /// </summary>
TokenSource,
/// <summary>
    /// The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token.
    /// </summary>
TokenType,
/// <summary>
    /// The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails.
    /// </summary>
TokenImpersonationLevel,
/// <summary>
    /// The buffer receives a TOKEN_STATISTICS structure that contains various token statistics.
    /// </summary>
TokenStatistics,
/// <summary>
    /// The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token.
    /// </summary>
TokenRestrictedSids,
/// <summary>
    /// The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token.
    /// </summary>
TokenSessionId,
/// <summary>
    /// The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token.
    /// </summary>
TokenGroupsAndPrivileges,
/// <summary>
    /// Reserved.
    /// </summary>
TokenSessionReference,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag.
    /// </summary>
TokenSandBoxInert,
/// <summary>
    /// Reserved.
    /// </summary>
TokenAuditPolicy,
/// <summary>
    /// The buffer receives a TOKEN_ORIGIN value.
    /// </summary>
TokenOrigin,
/// <summary>
    /// The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token.
    /// </summary>
TokenElevationType,
/// <summary>
    /// The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token.
    /// </summary>
TokenLinkedToken,
/// <summary>
    /// The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated.
    /// </summary>
TokenElevation,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if the token has ever been filtered.
    /// </summary>
TokenHasRestrictions,
/// <summary>
    /// The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token.
    /// </summary>
TokenAccessInformation,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token.
    /// </summary>
TokenVirtualizationAllowed,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token.
    /// </summary>
TokenVirtualizationEnabled,
/// <summary>
    /// The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level.
    /// </summary>
TokenIntegrityLevel,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set.
    /// </summary>
TokenUIAccess,
/// <summary>
    /// The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy.
    /// </summary>
TokenMandatoryPolicy,
/// <summary>
    /// The buffer receives the token's logon security identifier (SID).
    /// </summary>
TokenLogonSid,
/// <summary>
    /// The maximum value for this enumeration
    /// </summary>
MaxTokenInfoClass
}
public enum LOGON_TYPE
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK,
LOGON32_LOGON_BATCH,
LOGON32_LOGON_SERVICE,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT,
LOGON32_LOGON_NEW_CREDENTIALS
}
public enum LOGON_PROVIDER
{
LOGON32_PROVIDER_DEFAULT,
LOGON32_PROVIDER_WINNT35,
LOGON32_PROVIDER_WINNT40,
LOGON32_PROVIDER_WINNT50
}
[Flags]
public enum CreateProcessFlags
{
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_NO_WINDOW = 0x08000000,
CREATE_PROTECTED_PROCESS = 0x00040000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_SUSPENDED = 0x00000004,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
DEBUG_PROCESS = 0x00000001,
DETACHED_PROCESS = 0x00000008,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
INHERIT_PARENT_AFFINITY = 0x00010000
}
public enum TOKEN_TYPE : int
{
TokenPrimary = 1,
TokenImpersonation = 2
}
public enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
#endregion
#region Constants
public const int TOKEN_DUPLICATE = 0x0002;
public const uint MAXIMUM_ALLOWED = 0x2000000;
public const int CREATE_NEW_CONSOLE = 0x00000010;
public const int CREATE_NO_WINDOW = 0x08000000;
public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
public const int STARTF_USESHOWWINDOW = 0x00000001;
public const int DETACHED_PROCESS = 0x00000008;
public const int TOKEN_ALL_ACCESS = 0x000f01ff;
public const int PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF;
public const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const int SYNCHRONIZE = 0x00100000;
public const int IDLE_PRIORITY_CLASS = 0x40;
public const int NORMAL_PRIORITY_CLASS = 0x20;
public const int HIGH_PRIORITY_CLASS = 0x80;
public const int REALTIME_PRIORITY_CLASS = 0x100;
public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001;
public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004;
public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000;
public const Int32 ANYSIZE_ARRAY = 1;
public const int UOI_FLAGS = 1;
public const int UOI_NAME = 2;
public const int UOI_TYPE = 3;
public const int UOI_USER_SID = 4;
public const int UOI_HEAPSIZE = 5;
public const int UOI_IO = 6;
#endregion
#region DLL Imports
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
[MarshalAs(UnmanagedType.Bool)] bool disableAllPrivileges,
ref TOKEN_PRIVILEGES newState,
UInt32 bufferLengthInBytes,
ref TOKEN_PRIVILEGES previousState,
out UInt32 returnLengthInBytes);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool AllocateLocallyUniqueId(out IntPtr pLuid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern SECUR32.WinErrors LsaNtStatusToWinError(SECUR32.WinStatusCodes status);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(
IntPtr TokenHandle,
SECUR32.TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
uint TokenInformationLength,
out uint ReturnLength);
[DllImport("advapi32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool LogonUser(
[MarshalAs(UnmanagedType.LPStr)] string pszUserName,
[MarshalAs(UnmanagedType.LPStr)] string pszDomain,
[MarshalAs(UnmanagedType.LPStr)] string pszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken);
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpTokenAttributes,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TOKEN_TYPE TokenType,
out IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = false)]
public static extern uint LsaNtStatusToWinError(uint status);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetUserObjectInformationW(IntPtr hObj, int nIndex,
[Out] byte[] pvInfo, uint nLength, out uint lpnLengthNeeded);
#endregion
}
}

View File

@ -1,81 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace Remotely.Shared.Win32
{
public static class GDI32
{
#region Enums
/// <summary>
/// Specifies a raster-operation code. These codes define how the color data for the
/// source rectangle is to be combined with the color data for the destination
/// rectangle to achieve the final color.
/// </summary>
public enum TernaryRasterOperations : uint
{
/// <summary>dest = source</summary>
SRCCOPY = 0x00CC0020,
/// <summary>dest = source OR dest</summary>
SRCPAINT = 0x00EE0086,
/// <summary>dest = source AND dest</summary>
SRCAND = 0x008800C6,
/// <summary>dest = source XOR dest</summary>
SRCINVERT = 0x00660046,
/// <summary>dest = source AND (NOT dest)</summary>
SRCERASE = 0x00440328,
/// <summary>dest = (NOT source)</summary>
NOTSRCCOPY = 0x00330008,
/// <summary>dest = (NOT src) AND (NOT dest)</summary>
NOTSRCERASE = 0x001100A6,
/// <summary>dest = (source AND pattern)</summary>
MERGECOPY = 0x00C000CA,
/// <summary>dest = (NOT source) OR dest</summary>
MERGEPAINT = 0x00BB0226,
/// <summary>dest = pattern</summary>
PATCOPY = 0x00F00021,
/// <summary>dest = DPSnoo</summary>
PATPAINT = 0x00FB0A09,
/// <summary>dest = pattern XOR dest</summary>
PATINVERT = 0x005A0049,
/// <summary>dest = (NOT dest)</summary>
DSTINVERT = 0x00550009,
/// <summary>dest = BLACK</summary>
BLACKNESS = 0x00000042,
/// <summary>dest = WHITE</summary>
WHITENESS = 0x00FF0062,
/// <summary>
/// Capture window as seen on screen. This includes layered windows
/// such as WPF windows with AllowsTransparency="true"
/// </summary>
CAPTUREBLT = 0x40000000
}
#endregion
#region DLL Imports
[DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
[DllImport("GDI32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);[DllImport("GDI32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("GDI32.dll")]
public static extern bool DeleteDC(IntPtr hdc);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("GDI32.dll")]
public static extern IntPtr GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("GDI32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
#endregion
}
}

View File

@ -1,86 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace Remotely.Shared.Win32
{
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetCommandLine();
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
[DllImport("kernel32.dll")]
public static extern uint WTSGetActiveConsoleSessionId();
/// <summary>
/// contains information about the current state of both physical and virtual memory, including extended memory
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MEMORYSTATUSEX
{
/// <summary>
/// Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
/// </summary>
public uint dwLength;
/// <summary>
/// Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).
/// </summary>
public uint dwMemoryLoad;
/// <summary>
/// Total size of physical memory, in bytes.
/// </summary>
public ulong ullTotalPhys;
/// <summary>
/// Size of physical memory available, in bytes.
/// </summary>
public ulong ullAvailPhys;
/// <summary>
/// Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead.
/// </summary>
public ulong ullTotalPageFile;
/// <summary>
/// Size of available memory to commit, in bytes. The limit is ullTotalPageFile.
/// </summary>
public ulong ullAvailPageFile;
/// <summary>
/// Total size of the user mode portion of the virtual address space of the calling process, in bytes.
/// </summary>
public ulong ullTotalVirtual;
/// <summary>
/// Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes.
/// </summary>
public ulong ullAvailVirtual;
/// <summary>
/// Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes.
/// </summary>
public ulong ullAvailExtendedVirtual;
/// <summary>
/// Initializes a new instance of the <see cref="T:MEMORYSTATUSEX"/> class.
/// </summary>
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}
}
}

View File

@ -1,377 +0,0 @@
using Microsoft.Win32.SafeHandles;
using Remotely.Shared.Win32;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
public static class SECUR32
{
public enum WinStatusCodes : uint
{
STATUS_SUCCESS = 0
}
public enum WinErrors : uint
{
NO_ERROR = 0,
}
public enum WinLogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
LOGON32_LOGON_NEW_CREDENTIALS = 9
}
// SECURITY_LOGON_TYPE
public enum SecurityLogonType
{
Interactive = 2, // Interactively logged on (locally or remotely)
Network, // Accessing system via network
Batch, // Started via a batch queue
Service, // Service started by service controller
Proxy, // Proxy logon
Unlock, // Unlock workstation
NetworkCleartext, // Network logon with cleartext credentials
NewCredentials, // Clone caller, new default credentials
RemoteInteractive, // Remote, yet interactive. Terminal server
CachedInteractive, // Try cached credentials without hitting the net.
CachedRemoteInteractive, // Same as RemoteInteractive, this is used internally for auditing purpose
CachedUnlock // Cached Unlock workstation
}
[StructLayout(LayoutKind.Sequential)]
public struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_SOURCE
{
public TOKEN_SOURCE(string name)
{
SourceName = new byte[8];
System.Text.Encoding.GetEncoding(1252).GetBytes(name, 0, name.Length, SourceName, 0);
if (!ADVAPI32.AllocateLocallyUniqueId(out SourceIdentifier))
throw new System.ComponentModel.Win32Exception();
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] SourceName;
public IntPtr SourceIdentifier;
}
[StructLayout(LayoutKind.Sequential)]
public struct KERB_INTERACTIVE_LOGON
{
public KERB_LOGON_SUBMIT_TYPE MessageType;
public string LogonDomainName;
public string UserName;
public string Password;
}
public enum KERB_LOGON_SUBMIT_TYPE
{
KerbInteractiveLogon = 2,
KerbSmartCardLogon = 6,
KerbWorkstationUnlockLogon = 7,
KerbSmartCardUnlockLogon = 8,
KerbProxyLogon = 9,
KerbTicketLogon = 10,
KerbTicketUnlockLogon = 11,
KerbS4ULogon = 12,
KerbCertificateLogon = 13,
KerbCertificateS4ULogon = 14,
KerbCertificateUnlockLogon = 15
}
public enum TOKEN_INFORMATION_CLASS
{
/// <summary>
    /// The buffer receives a TOKEN_USER structure that contains the user account of the token.
    /// </summary>
TokenUser = 1,
/// <summary>
    /// The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token.
    /// </summary>
TokenGroups,
/// <summary>
    /// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token.
    /// </summary>
TokenPrivileges,
/// <summary>
    /// The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects.
    /// </summary>
TokenOwner,
/// <summary>
    /// The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects.
    /// </summary>
TokenPrimaryGroup,
/// <summary>
    /// The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects.
    /// </summary>
TokenDefaultDacl,
/// <summary>
    /// The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information.
    /// </summary>
TokenSource,
/// <summary>
    /// The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token.
    /// </summary>
TokenType,
/// <summary>
    /// The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails.
    /// </summary>
TokenImpersonationLevel,
/// <summary>
    /// The buffer receives a TOKEN_STATISTICS structure that contains various token statistics.
    /// </summary>
TokenStatistics,
/// <summary>
    /// The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token.
    /// </summary>
TokenRestrictedSids,
/// <summary>
    /// The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token.
    /// </summary>
TokenSessionId,
/// <summary>
    /// The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token.
    /// </summary>
TokenGroupsAndPrivileges,
/// <summary>
    /// Reserved.
    /// </summary>
TokenSessionReference,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag.
    /// </summary>
TokenSandBoxInert,
/// <summary>
    /// Reserved.
    /// </summary>
TokenAuditPolicy,
/// <summary>
    /// The buffer receives a TOKEN_ORIGIN value.
    /// </summary>
TokenOrigin,
/// <summary>
    /// The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token.
    /// </summary>
TokenElevationType,
/// <summary>
    /// The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token.
    /// </summary>
TokenLinkedToken,
/// <summary>
    /// The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated.
    /// </summary>
TokenElevation,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if the token has ever been filtered.
    /// </summary>
TokenHasRestrictions,
/// <summary>
    /// The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token.
    /// </summary>
TokenAccessInformation,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token.
    /// </summary>
TokenVirtualizationAllowed,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token.
    /// </summary>
TokenVirtualizationEnabled,
/// <summary>
    /// The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level.
    /// </summary>
TokenIntegrityLevel,
/// <summary>
    /// The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set.
    /// </summary>
TokenUIAccess,
/// <summary>
    /// The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy.
    /// </summary>
TokenMandatoryPolicy,
/// <summary>
    /// The buffer receives the token's logon security identifier (SID).
    /// </summary>
TokenLogonSid,
/// <summary>
    /// The maximum value for this enumeration
    /// </summary>
MaxTokenInfoClass
}
[StructLayout(LayoutKind.Sequential)]
public struct QUOTA_LIMITS
{
readonly UInt32 PagedPoolLimit;
readonly UInt32 NonPagedPoolLimit;
readonly UInt32 MinimumWorkingSetSize;
readonly UInt32 MaximumWorkingSetSize;
readonly UInt32 PagefileLimit;
readonly Int64 TimeLimit;
}
[StructLayout(LayoutKind.Sequential)]
public struct LSA_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public /*PCHAR*/ IntPtr Buffer;
}
[DllImport("secur32.dll", SetLastError = true)]
public static extern WinStatusCodes LsaLogonUser(
[In] IntPtr LsaHandle,
[In] ref LSA_STRING OriginName,
[In] SecurityLogonType LogonType,
[In] UInt32 AuthenticationPackage,
[In] IntPtr AuthenticationInformation,
[In] UInt32 AuthenticationInformationLength,
[In] /*PTOKEN_GROUPS*/ IntPtr LocalGroups,
[In] ref TOKEN_SOURCE SourceContext,
[Out] /*PVOID*/ out IntPtr ProfileBuffer,
[Out] out UInt32 ProfileBufferLength,
[Out] out Int64 LogonId,
[Out] out IntPtr Token,
[Out] out QUOTA_LIMITS Quotas,
[Out] out WinStatusCodes SubStatus
);
[DllImport("secur32.dll", SetLastError = true)]
public static extern WinStatusCodes LsaRegisterLogonProcess(
IntPtr LogonProcessName,
out IntPtr LsaHandle,
out ulong SecurityMode
);
[DllImport("secur32.dll", SetLastError = false)]
public static extern WinStatusCodes LsaLookupAuthenticationPackage([In] IntPtr LsaHandle, [In] ref LSA_STRING PackageName, [Out] out UInt32 AuthenticationPackage);
[DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[ResourceExposure(ResourceScope.None)]
internal static extern int LsaConnectUntrusted(
[In, Out] ref SafeLsaLogonProcessHandle LsaHandle);
[DllImport("secur32.dll", SetLastError = false)]
public static extern WinStatusCodes LsaConnectUntrusted([Out] out IntPtr LsaHandle);
[System.Security.SecurityCritical] // auto-generated
internal sealed class SafeLsaLogonProcessHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeLsaLogonProcessHandle() : base(true) { }
// 0 is an Invalid Handle
internal SafeLsaLogonProcessHandle(IntPtr handle) : base(true)
{
SetHandle(handle);
}
internal static SafeLsaLogonProcessHandle InvalidHandle
{
get { return new SafeLsaLogonProcessHandle(IntPtr.Zero); }
}
[System.Security.SecurityCritical]
protected override bool ReleaseHandle()
{
// LsaDeregisterLogonProcess returns an NTSTATUS
return LsaDeregisterLogonProcess(handle) >= 0;
}
}
[DllImport("secur32.dll", SetLastError = true)]
[ResourceExposure(ResourceScope.None)]
internal static extern int LsaDeregisterLogonProcess(IntPtr handle);
public static void CreateNewSession()
{
var kli = new SECUR32.KERB_INTERACTIVE_LOGON()
{
MessageType = SECUR32.KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon,
UserName = "",
Password = ""
};
IntPtr kerbLogInfo;
SECUR32.LSA_STRING logonProc = new()
{
Buffer = Marshal.StringToHGlobalAuto("InstaLogon"),
Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")),
MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon"))
};
SECUR32.LSA_STRING originName = new()
{
Buffer = Marshal.StringToHGlobalAuto("InstaLogon"),
Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")),
MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon"))
};
SECUR32.LSA_STRING authPackage = new()
{
Buffer = Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A"),
Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A")),
MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A"))
};
IntPtr hLogonProc = Marshal.AllocHGlobal(Marshal.SizeOf(logonProc));
Marshal.StructureToPtr(logonProc, hLogonProc, false);
ADVAPI32.AllocateLocallyUniqueId(out IntPtr pluid);
LsaConnectUntrusted(out IntPtr lsaHan);
//SECUR32.LsaRegisterLogonProcess(hLogonProc, out lsaHan, out secMode);
SECUR32.LsaLookupAuthenticationPackage(lsaHan, ref authPackage, out uint authPackID);
kerbLogInfo = Marshal.AllocHGlobal(Marshal.SizeOf(kli));
Marshal.StructureToPtr(kli, kerbLogInfo, false);
var ts = new SECUR32.TOKEN_SOURCE("Insta");
SECUR32.LsaLogonUser(
lsaHan,
ref originName,
SECUR32.SecurityLogonType.Interactive,
authPackID,
kerbLogInfo,
(uint)Marshal.SizeOf(kerbLogInfo),
IntPtr.Zero,
ref ts,
out IntPtr profBuf,
out uint profBufLen,
out long logonID,
out IntPtr logonToken,
out QUOTA_LIMITS quotas,
out WinStatusCodes subStatus);
}
}

View File

@ -1,52 +0,0 @@
using System.Runtime.InteropServices;
namespace Remotely.Shared.Win32
{
// https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-isos
public class Shlwapi
{
[DllImport("shlwapi.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsOS(OsType osType);
}
public enum OsType
{
OS_WINDOWS = 0,
OS_NT = 1,
OS_WIN95ORGREATER = 2,
OS_NT4ORGREATER = 3,
OS_WIN98ORGREATER = 5,
OS_WIN98_GOLD = 6,
OS_WIN2000ORGREATER = 7,
OS_WIN2000PRO = 8,
OS_WIN2000SERVER = 9,
OS_WIN2000ADVSERVER = 10,
OS_WIN2000DATACENTER = 11,
OS_WIN2000TERMINAL = 12,
OS_EMBEDDED = 13,
OS_TERMINALCLIENT = 14,
OS_TERMINALREMOTEADMIN = 15,
OS_WIN95_GOLD = 16,
OS_MEORGREATER = 17,
OS_XPORGREATER = 18,
OS_HOME = 19,
OS_PROFESSIONAL = 20,
OS_DATACENTER = 21,
OS_ADVSERVER = 22,
OS_SERVER = 23,
OS_TERMINALSERVER = 24,
OS_PERSONALTERMINALSERVER = 25,
OS_FASTUSERSWITCHING = 26,
OS_WELCOMELOGONUI = 27,
OS_DOMAINMEMBER = 28,
OS_ANYSERVER = 29,
OS_WOW6432 = 30,
OS_WEBSERVER = 31,
OS_SMALLBUSINESSSERVER = 32,
OS_TABLETPC = 33,
OS_SERVERADMINUI = 34,
OS_MEDIACENTER = 35,
OS_APPLIANCE = 36,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace Remotely.Shared.Win32
{
public static class WTSAPI32
{
public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
public enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern int WTSEnumerateSessions(
System.IntPtr hServer,
int Reserved,
int Version,
ref System.IntPtr ppSessionInfo,
ref int pCount);
[DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)]
public static extern void WTSFreeMemory(IntPtr memory);
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQuerySessionInformation(IntPtr hServer, uint sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned);
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern IntPtr WTSOpenServer(string pServerName);
[StructLayout(LayoutKind.Sequential)]
public struct WTS_SESSION_INFO
{
public uint SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public string pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
}
}

View File

@ -1,230 +0,0 @@
using Remotely.Shared.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using static Remotely.Shared.Win32.ADVAPI32;
using static Remotely.Shared.Win32.User32;
namespace Remotely.Shared.Win32
{
// TODO: Use https://github.com/dotnet/pinvoke for all p/invokes. Remove signatures from this project.
public class Win32Interop
{
private static IntPtr _lastInputDesktop;
public static List<WindowsSession> GetActiveSessions()
{
var sessions = new List<WindowsSession>();
var consoleSessionId = Kernel32.WTSGetActiveConsoleSessionId();
sessions.Add(new WindowsSession()
{
ID = consoleSessionId,
Type = SessionType.Console,
Name = "Console",
Username = GetUsernameFromSessionId(consoleSessionId)
});
IntPtr ppSessionInfo = IntPtr.Zero;
var count = 0;
var enumSessionResult = WTSAPI32.WTSEnumerateSessions(WTSAPI32.WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref count);
var dataSize = Marshal.SizeOf(typeof(WTSAPI32.WTS_SESSION_INFO));
var current = ppSessionInfo;
if (enumSessionResult != 0)
{
for (int i = 0; i < count; i++)
{
WTSAPI32.WTS_SESSION_INFO sessionInfo = (WTSAPI32.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTSAPI32.WTS_SESSION_INFO));
current += dataSize;
if (sessionInfo.State == WTSAPI32.WTS_CONNECTSTATE_CLASS.WTSActive && sessionInfo.SessionID != consoleSessionId)
{
sessions.Add(new WindowsSession()
{
ID = sessionInfo.SessionID,
Name = sessionInfo.pWinStationName,
Type = SessionType.RDP,
Username = GetUsernameFromSessionId(sessionInfo.SessionID)
});
}
}
}
return sessions;
}
public static string GetCommandLine()
{
var commandLinePtr = Kernel32.GetCommandLine();
return Marshal.PtrToStringAuto(commandLinePtr);
}
public static bool GetCurrentDesktop(out string desktopName)
{
var inputDesktop = OpenInputDesktop();
try
{
byte[] deskBytes = new byte[256];
if (!GetUserObjectInformationW(inputDesktop, UOI_NAME, deskBytes, 256, out uint lenNeeded))
{
desktopName = string.Empty;
return false;
}
desktopName = Encoding.Unicode.GetString(deskBytes.Take((int)lenNeeded).ToArray()).Replace("\0", "");
return true;
}
finally
{
CloseDesktop(inputDesktop);
}
}
public static string GetUsernameFromSessionId(uint sessionId)
{
var username = string.Empty;
if (WTSAPI32.WTSQuerySessionInformation(IntPtr.Zero, sessionId, WTSAPI32.WTS_INFO_CLASS.WTSUserName, out var buffer, out var strLen) && strLen > 1)
{
username = Marshal.PtrToStringAnsi(buffer);
WTSAPI32.WTSFreeMemory(buffer);
}
return username;
}
public static IntPtr OpenInputDesktop()
{
return User32.OpenInputDesktop(0, true, ACCESS_MASK.GENERIC_ALL);
}
public static bool OpenInteractiveProcess(string applicationName,
int targetSessionId,
bool forceConsoleSession,
string desktopName,
bool hiddenWindow,
out PROCESS_INFORMATION procInfo)
{
uint winlogonPid = 0;
IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
procInfo = new PROCESS_INFORMATION();
// If not force console, find target session. If not present,
// use last active session.
var dwSessionId = Kernel32.WTSGetActiveConsoleSessionId();
if (!forceConsoleSession)
{
var activeSessions = GetActiveSessions();
if (activeSessions.Any(x => x.ID == targetSessionId))
{
dwSessionId = (uint)targetSessionId;
}
else
{
dwSessionId = activeSessions.Last().ID;
}
}
// Obtain the process ID of the winlogon process that is running within the currently active session.
Process[] processes = Process.GetProcessesByName("winlogon");
foreach (Process p in processes)
{
if ((uint)p.SessionId == dwSessionId)
{
winlogonPid = (uint)p.Id;
}
}
// Obtain a handle to the winlogon process.
hProcess = Kernel32.OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
// Obtain a handle to the access token of the winlogon process.
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
{
Kernel32.CloseHandle(hProcess);
return false;
}
// Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser.
SECURITY_ATTRIBUTES sa = new();
sa.Length = Marshal.SizeOf(sa);
// Copy the access token of the winlogon process; the newly created token will be a primary token.
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out hUserTokenDup))
{
Kernel32.CloseHandle(hProcess);
Kernel32.CloseHandle(hPToken);
return false;
}
// By default, CreateProcessAsUser creates a process on a non-interactive window station, meaning
// the window station has a desktop that is invisible and the process is incapable of receiving
// user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
// interaction with the new process.
STARTUPINFO si = new();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = @"winsta0\" + desktopName;
// Flags that specify the priority and creation method of the process.
uint dwCreationFlags;
if (hiddenWindow)
{
dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = 0;
}
else
{
dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE;
}
// Create a new process in the current user's logon session.
bool result = CreateProcessAsUser(hUserTokenDup, null, applicationName, ref sa, ref sa, false, dwCreationFlags, IntPtr.Zero, null, ref si, out procInfo);
// Invalidate the handles.
Kernel32.CloseHandle(hProcess);
Kernel32.CloseHandle(hPToken);
Kernel32.CloseHandle(hUserTokenDup);
return result;
}
public static void SetMonitorState(MonitorState state)
{
SendMessage(0xFFFF, 0x112, 0xF170, (int)state);
}
public static MessageBoxResult ShowMessageBox(IntPtr owner,
string message,
string caption,
MessageBoxType messageBoxType)
{
return (MessageBoxResult)MessageBox(owner, message, caption, (long)messageBoxType);
}
public static bool SwitchToInputDesktop()
{
try
{
CloseDesktop(_lastInputDesktop);
var inputDesktop = OpenInputDesktop();
if (inputDesktop == IntPtr.Zero)
{
return false;
}
var result = SetThreadDesktop(inputDesktop) && SwitchDesktop(inputDesktop);
_lastInputDesktop = inputDesktop;
return result;
}
catch
{
return false;
}
}
}
}

@ -1 +1 @@
Subproject commit a896025ebf2f9cbcb2ae280f88a178acc39acfd2
Subproject commit debde4e5a4ca08d37493632b76650d983b369352