Захват события входа в систему на локальном компьютере без прав администратора. Есть ли API?

Как пользователь без прав администратора, я хочу обнаружить событие, когда другой пользователь входит в систему. Я не могу использовать службу уведомлений о системных событиях (SensLogon2), поскольку для этого требуется, чтобы пользователь входил в группу администраторов. Есть ли другой API или есть определенные разрешения / привилегии, которые я могу предоставить текущему пользователю?

Нам нужно обнаружить, что другой пользователь входит в терминал через RDP, чтобы мы могли изменить состояние приложения, в котором находится текущий пользователь.

1 ответ

Решение

Вы можете сделать следующие шаги, чтобы получить информацию об изменениях сессии:

  1. Вызовите уведомление WTSRegisterSessionNotification с NOTIFY_FOR_ALL_SESSIONS в своей форме, чтобы получить сообщение WM_WTSSESSION_CHANGE
  2. переопределить void WndProc(ref Message m) формы и выполнить фильтрацию по WM_WTSSESSION_CHANGE (0x2b1)
  3. Извлечение идентификатора сеанса из LPARAM и события изменения состояния сеанса из WPARAM
  4. Вызовите WTSQuerySessionInformation с идентификатором сеанса, чтобы получить имя пользователя.

Вот рабочий пример с pInvoke. У меня есть Form1 (WinForm) в моем проекте. Это:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MessageLoop
{
    public partial class Form1 : Form
    {
        /// <summary>
        ///  WM_WTSSESSION_CHANGE message number for filtering in WndProc
        /// </summary>
        private const int WM_WTSSESSION_CHANGE = 0x2b1;

        public Form1()
        {
            InitializeComponent();
            NativeWrapper.WTSRegisterSessionNotification(this, SessionNotificationType.NOTIFY_FOR_ALL_SESSIONS);
        }
        protected override void OnClosing(CancelEventArgs e)
        {
            NativeWrapper.WTSUnRegisterSessionNotification(this);
            base.OnClosing(e);
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_WTSSESSION_CHANGE)
            {
                int eventType = m.WParam.ToInt32();
                int sessionId = m.LParam.ToInt32();
                WtsSessionChange reason = (WtsSessionChange)eventType;
                Trace.WriteLine(string.Format("SessionId: {0}, Username: {1}, EventType: {2}", 
                    sessionId, NativeWrapper.GetUsernameBySessionId(sessionId), reason));
            }
            base.WndProc(ref m);
        }
    }
}

Вот NativeWrapper.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MessageLoop
{
    public enum WtsSessionChange
    {
        WTS_CONSOLE_CONNECT = 1,
        WTS_CONSOLE_DISCONNECT = 2,
        WTS_REMOTE_CONNECT = 3,
        WTS_REMOTE_DISCONNECT = 4,
        WTS_SESSION_LOGON = 5,
        WTS_SESSION_LOGOFF = 6,
        WTS_SESSION_LOCK = 7,
        WTS_SESSION_UNLOCK = 8,
        WTS_SESSION_REMOTE_CONTROL = 9,
        WTS_SESSION_CREATE = 0xA,
        WTS_SESSION_TERMINATE = 0xB
    }
    public enum SessionNotificationType
    {
        NOTIFY_FOR_THIS_SESSION = 0,
        NOTIFY_FOR_ALL_SESSIONS = 1
    }
    public static class NativeWrapper
    {
        public static void WTSRegisterSessionNotification(Control control, SessionNotificationType sessionNotificationType)
        {
            if (!Native.WTSRegisterSessionNotification(control.Handle, (int)sessionNotificationType))
                throw new Win32Exception(Marshal.GetLastWin32Error()); 
        }
        public static void WTSUnRegisterSessionNotification(Control control)
        {
            if (!Native.WTSUnRegisterSessionNotification(control.Handle))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        public static string GetUsernameBySessionId(int sessionId)
        {           
            IntPtr buffer;
            int strLen;
            var username = "SYSTEM"; // assume SYSTEM as this will return "\0" below
            if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSUserName, out buffer, out strLen) && strLen > 1)
            {
                username = Marshal.PtrToStringAnsi(buffer); // don't need length as these are null terminated strings
                Native.WTSFreeMemory(buffer);
                if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSDomainName, out buffer, out strLen) && strLen > 1)
                {
                    username = Marshal.PtrToStringAnsi(buffer) + "\\" + username; // prepend domain name
                    Native.WTSFreeMemory(buffer);
                }
            }
            return username;
        }
    }
}

И последний файл Native.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace MessageLoop
{
    public static class Native
    {
        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)]
        internal static extern bool WTSRegisterSessionNotification(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] int dwFlags);

        [DllImport("wtsapi32.dll", SetLastError = true)]
        internal static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);

        [DllImport("Wtsapi32.dll")]
        internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);

        [DllImport("Wtsapi32.dll")]
        internal static extern void WTSFreeMemory(IntPtr pointer);
    }
}
Другие вопросы по тегам