2013-03-13 9 views
5

Mam obecnie usługę Windows, która działa na koncie systemowym. Mój problem polega na tym, że muszę uruchomić pewne procesy z poziomu usługi jako bieżący zalogowany użytkownik. Mam cały kod itp., Aby uzyskać bieżący zalogowany użytkownik/Aktywna sesja.Uruchom proces z usługi systemu Windows jako bieżący użytkownik.

Mój problem jest, że trzeba zapoczątkować proces jako zalogowany użytkownik, ale nie będą wiedzieć, poświadczenia użytkownika itp

Usługa .net skompilowane serwis i oczekuję, że muszę korzystać z niektórych metod pinvoke do zdobądź uchwyt jednego z obecnych procesów użytkownika, aby go powielić i lunch jako proces z uchwytem.

Niestety, nie mogę znaleźć żadnej dobrej dokumentacji/rozwiązania, jak ją wdrożyć?

Jeśli ktoś jest w stanie dać mi wskazówki/przykładu, bardzo bym to docenił.

* Aktualizacja * Myślę, że wyjaśniłem nieprawidłowo i trzeba reajust zgodnie z tym co faktycznie potrzebują. Niekoniecznie chcę rozpocząć nowy proces, chcę tylko podszyć się pod zalogowanego użytkownika. Byłem tak pochłonięty przeglądaniem CreateProcess itp., Doprowadziłem się do ścieżki tworzenia nowego procesu jako bieżący zalogowany użytkownik (co nie jest szczególnie tym, co chcę zrobić).

Z kolei ja po prostu chcę uruchomić kod w bieżącym kontekście użytkownika (Podszywanie się pod aktualnie zalogowanego użytkownika)?

+0

Co zrobić, jeśli żaden użytkownik się nie zalogował? –

+0

Myślę, że próbujesz uruchomić usługę okna jako konto administratora. – Pranav1688

Odpowiedz

9

Jedną z opcji jest aplikacja działająca w tle, która uruchamia się automatycznie, gdy użytkownik loguje się i słucha poleceń z usługi za pośrednictwem WCF lub oszczędzania, lub po prostu monitorując niektóre polecenia dotyczące pliku i czytania z tego miejsca.

Inną opcją jest zrobienie tego, o co prosiłeś - uruchomienie za pomocą interfejsu API systemu Windows. Ale kod jest dość przerażający. Oto próbka, której możesz użyć. Będzie on wykonać dowolną linię komend w bieżącej sesji użytkownika, metodą CreateProcessInConsoleSession:

internal class ApplicationLauncher 
{ 
    public enum TOKEN_INFORMATION_CLASS 
    { 
     TokenUser = 1, 
     TokenGroups, 
     TokenPrivileges, 
     TokenOwner, 
     TokenPrimaryGroup, 
     TokenDefaultDacl, 
     TokenSource, 
     TokenType, 
     TokenImpersonationLevel, 
     TokenStatistics, 
     TokenRestrictedSids, 
     TokenSessionId, 
     TokenGroupsAndPrivileges, 
     TokenSessionReference, 
     TokenSandBoxInert, 
     TokenAuditPolicy, 
     TokenOrigin, 
     MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum 
    } 

    public const int READ_CONTROL = 0x00020000; 

    public const int STANDARD_RIGHTS_REQUIRED = 0x000F0000; 

    public const int STANDARD_RIGHTS_READ = READ_CONTROL; 
    public const int STANDARD_RIGHTS_WRITE = READ_CONTROL; 
    public const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL; 

    public const int STANDARD_RIGHTS_ALL = 0x001F0000; 

    public const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF; 

    public const int TOKEN_ASSIGN_PRIMARY = 0x0001; 
    public const int TOKEN_DUPLICATE = 0x0002; 
    public const int TOKEN_IMPERSONATE = 0x0004; 
    public const int TOKEN_QUERY = 0x0008; 
    public const int TOKEN_QUERY_SOURCE = 0x0010; 
    public const int TOKEN_ADJUST_PRIVILEGES = 0x0020; 
    public const int TOKEN_ADJUST_GROUPS = 0x0040; 
    public const int TOKEN_ADJUST_DEFAULT = 0x0080; 
    public const int TOKEN_ADJUST_SESSIONID = 0x0100; 

    public const int TOKEN_ALL_ACCESS_P = (STANDARD_RIGHTS_REQUIRED | 
              TOKEN_ASSIGN_PRIMARY | 
              TOKEN_DUPLICATE | 
              TOKEN_IMPERSONATE | 
              TOKEN_QUERY | 
              TOKEN_QUERY_SOURCE | 
              TOKEN_ADJUST_PRIVILEGES | 
              TOKEN_ADJUST_GROUPS | 
              TOKEN_ADJUST_DEFAULT); 

    public const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID; 

    public const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY; 

    public const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE | 
            TOKEN_ADJUST_PRIVILEGES | 
            TOKEN_ADJUST_GROUPS | 
            TOKEN_ADJUST_DEFAULT; 

    public const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE; 

    public const uint MAXIMUM_ALLOWED = 0x2000000; 

    public const int CREATE_NEW_PROCESS_GROUP = 0x00000200; 
    public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400; 

    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 int CREATE_NEW_CONSOLE = 0x00000010; 

    public const string SE_DEBUG_NAME = "SeDebugPrivilege"; 
    public const string SE_RESTORE_NAME = "SeRestorePrivilege"; 
    public const string SE_BACKUP_NAME = "SeBackupPrivilege"; 

    public const int SE_PRIVILEGE_ENABLED = 0x0002; 

    public const int ERROR_NOT_ALL_ASSIGNED = 1300; 

    private const uint TH32CS_SNAPPROCESS = 0x00000002; 

    public static int INVALID_HANDLE_VALUE = -1; 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, 
     [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid); 

    [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, 
     CallingConvention = CallingConvention.StdCall)] 
    public static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, 
     ref SECURITY_ATTRIBUTES lpProcessAttributes, 
     ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, 
     String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern bool DuplicateToken(IntPtr ExistingTokenHandle, 
     int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); 

    [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")] 
    public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, 
     ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, 
     int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, 
     ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, 
     ref uint TokenInformation, uint TokenInformationLength); 

    [DllImport("userenv.dll", SetLastError = true)] 
    public static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit); 

    public static bool CreateProcessInConsoleSession(String CommandLine, bool bElevate) 
    { 

     PROCESS_INFORMATION pi; 

     bool bResult = false; 
     uint dwSessionId, winlogonPid = 0; 
     IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; 

     Debug.Print("CreateProcessInConsoleSession"); 
     // Log the client on to the local computer. 
     dwSessionId = WTSGetActiveConsoleSessionId(); 

     // Find the winlogon process 
     var procEntry = new PROCESSENTRY32(); 

     uint hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
     if (hSnap == INVALID_HANDLE_VALUE) 
     { 
      return false; 
     } 

     procEntry.dwSize = (uint) Marshal.SizeOf(procEntry); //sizeof(PROCESSENTRY32); 

     if (Process32First(hSnap, ref procEntry) == 0) 
     { 
      return false; 
     } 

     String strCmp = "explorer.exe"; 
     do 
     { 
      if (strCmp.IndexOf(procEntry.szExeFile) == 0) 
      { 
       // We found a winlogon process...make sure it's running in the console session 
       uint winlogonSessId = 0; 
       if (ProcessIdToSessionId(procEntry.th32ProcessID, ref winlogonSessId) && 
        winlogonSessId == dwSessionId) 
       { 
        winlogonPid = procEntry.th32ProcessID; 
        break; 
       } 
      } 
     } 
     while (Process32Next(hSnap, ref procEntry) != 0); 

     //Get the user token used by DuplicateTokenEx 
     WTSQueryUserToken(dwSessionId, ref hUserToken); 

     var si = new STARTUPINFO(); 
     si.cb = Marshal.SizeOf(si); 
     si.lpDesktop = "winsta0\\default"; 
     var tp = new TOKEN_PRIVILEGES(); 
     var luid = new LUID(); 
     hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); 

     if (
      !OpenProcessToken(hProcess, 
       TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY 
       | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken)) 
     { 
      Debug.Print(String.Format("CreateProcessInConsoleSession OpenProcessToken error: {0}", 
       Marshal.GetLastWin32Error())); 
     } 

     if (!LookupPrivilegeValue(IntPtr.Zero, SE_DEBUG_NAME, ref luid)) 
     { 
      Debug.Print(String.Format("CreateProcessInConsoleSession LookupPrivilegeValue error: {0}", 
       Marshal.GetLastWin32Error())); 
     } 

     var sa = new SECURITY_ATTRIBUTES(); 
     sa.Length = Marshal.SizeOf(sa); 

     if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, 
       (int) SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int) TOKEN_TYPE.TokenPrimary, 
       ref hUserTokenDup)) 
     { 
      Debug.Print(
       String.Format(
        "CreateProcessInConsoleSession DuplicateTokenEx error: {0} Token does not have the privilege.", 
        Marshal.GetLastWin32Error())); 
      CloseHandle(hProcess); 
      CloseHandle(hUserToken); 
      CloseHandle(hPToken); 
      return false; 
     } 

     if (bElevate) 
     { 
      //tp.Privileges[0].Luid = luid; 
      //tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 

      tp.PrivilegeCount = 1; 
      tp.Privileges = new int[3]; 
      tp.Privileges[2] = SE_PRIVILEGE_ENABLED; 
      tp.Privileges[1] = luid.HighPart; 
      tp.Privileges[0] = luid.LowPart; 

      //Adjust Token privilege 
      if (
       !SetTokenInformation(hUserTokenDup, TOKEN_INFORMATION_CLASS.TokenSessionId, ref dwSessionId, 
        (uint) IntPtr.Size)) 
      { 
       Debug.Print(
        String.Format(
         "CreateProcessInConsoleSession SetTokenInformation error: {0} Token does not have the privilege.", 
         Marshal.GetLastWin32Error())); 
       //CloseHandle(hProcess); 
       //CloseHandle(hUserToken); 
       //CloseHandle(hPToken); 
       //CloseHandle(hUserTokenDup); 
       //return false; 
      } 
      if (
       !AdjustTokenPrivileges(hUserTokenDup, false, ref tp, Marshal.SizeOf(tp), /*(PTOKEN_PRIVILEGES)*/ 
        IntPtr.Zero, IntPtr.Zero)) 
      { 
       int nErr = Marshal.GetLastWin32Error(); 

       if (nErr == ERROR_NOT_ALL_ASSIGNED) 
       { 
        Debug.Print(
         String.Format(
          "CreateProcessInConsoleSession AdjustTokenPrivileges error: {0} Token does not have the privilege.", 
          nErr)); 
       } 
       else 
       { 
        Debug.Print(String.Format("CreateProcessInConsoleSession AdjustTokenPrivileges error: {0}", nErr)); 
       } 
      } 
     } 

     uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; 
     IntPtr pEnv = IntPtr.Zero; 
     if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true)) 
     { 
      dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; 
     } 
     else 
     { 
      pEnv = IntPtr.Zero; 
     } 
     // Launch the process in the client's logon session. 
     bResult = CreateProcessAsUser(hUserTokenDup, // client's access token 
      null, // file to execute 
      CommandLine, // command line 
      ref sa, // pointer to process SECURITY_ATTRIBUTES 
      ref sa, // pointer to thread SECURITY_ATTRIBUTES 
      false, // handles are not inheritable 
      (int) dwCreationFlags, // creation flags 
      pEnv, // pointer to new environment block 
      null, // name of current directory 
      ref si, // pointer to STARTUPINFO structure 
      out pi // receives information about new process 
      ); 
     // End impersonation of client. 

     //GetLastError should be 0 
     int iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error(); 

     //Close handles task 
     CloseHandle(hProcess); 
     CloseHandle(hUserToken); 
     CloseHandle(hUserTokenDup); 
     CloseHandle(hPToken); 

     return (iResultOfCreateProcessAsUser == 0) ? true : false; 
    } 

    [DllImport("kernel32.dll")] 
    private static extern int Process32First(uint hSnapshot, ref PROCESSENTRY32 lppe); 

    [DllImport("kernel32.dll")] 
    private static extern int Process32Next(uint hSnapshot, ref PROCESSENTRY32 lppe); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern uint CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool CloseHandle(IntPtr hSnapshot); 

    [DllImport("kernel32.dll")] 
    private static extern uint WTSGetActiveConsoleSessionId(); 

    [DllImport("Wtsapi32.dll")] 
    private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken); 

    [DllImport("kernel32.dll")] 
    private static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId); 

    [DllImport("kernel32.dll")] 
    private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); 

    [DllImport("advapi32", SetLastError = true)] 
    [SuppressUnmanagedCodeSecurity] 
    private static extern bool OpenProcessToken(IntPtr ProcessHandle, // handle to process 
     int DesiredAccess, // desired access to process 
     ref IntPtr TokenHandle); 

    #region Nested type: LUID 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct LUID 
    { 
     public int LowPart; 
     public int HighPart; 
    } 

    #endregion 

    //end struct 

    #region Nested type: LUID_AND_ATRIBUTES 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct LUID_AND_ATRIBUTES 
    { 
     public LUID Luid; 
     public int Attributes; 
    } 

    #endregion 

    #region Nested type: PROCESSENTRY32 

    [StructLayout(LayoutKind.Sequential)] 
    private struct PROCESSENTRY32 
    { 
     public uint dwSize; 
     public readonly uint cntUsage; 
     public readonly uint th32ProcessID; 
     public readonly IntPtr th32DefaultHeapID; 
     public readonly uint th32ModuleID; 
     public readonly uint cntThreads; 
     public readonly uint th32ParentProcessID; 
     public readonly int pcPriClassBase; 
     public readonly uint dwFlags; 

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
     public readonly string szExeFile; 
    } 

    #endregion 

    #region Nested type: PROCESS_INFORMATION 

    [StructLayout(LayoutKind.Sequential)] 
    public struct PROCESS_INFORMATION 
    { 
     public IntPtr hProcess; 
     public IntPtr hThread; 
     public uint dwProcessId; 
     public uint dwThreadId; 
    } 

    #endregion 

    #region Nested type: SECURITY_ATTRIBUTES 

    [StructLayout(LayoutKind.Sequential)] 
    public struct SECURITY_ATTRIBUTES 
    { 
     public int Length; 
     public IntPtr lpSecurityDescriptor; 
     public bool bInheritHandle; 
    } 

    #endregion 

    #region Nested type: SECURITY_IMPERSONATION_LEVEL 

    private enum SECURITY_IMPERSONATION_LEVEL 
    { 
     SecurityAnonymous = 0, 
     SecurityIdentification = 1, 
     SecurityImpersonation = 2, 
     SecurityDelegation = 3, 
    } 

    #endregion 

    #region Nested type: STARTUPINFO 

    [StructLayout(LayoutKind.Sequential)] 
    public struct STARTUPINFO 
    { 
     public int cb; 
     public String lpReserved; 
     public String lpDesktop; 
     public String lpTitle; 
     public uint dwX; 
     public uint dwY; 
     public uint dwXSize; 
     public uint dwYSize; 
     public uint dwXCountChars; 
     public uint dwYCountChars; 
     public uint dwFillAttribute; 
     public uint dwFlags; 
     public short wShowWindow; 
     public short cbReserved2; 
     public IntPtr lpReserved2; 
     public IntPtr hStdInput; 
     public IntPtr hStdOutput; 
     public IntPtr hStdError; 
    } 

    #endregion 

    #region Nested type: TOKEN_PRIVILEGES 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct TOKEN_PRIVILEGES 
    { 
     internal int PrivilegeCount; 
     //LUID_AND_ATRIBUTES 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 
     internal int[] Privileges; 
    } 

    #endregion 

    #region Nested type: TOKEN_TYPE 

    private enum TOKEN_TYPE 
    { 
     TokenPrimary = 1, 
     TokenImpersonation = 2 
    } 

    #endregion 

    // handle to open access token 
} 
+0

To wygląda na to, czego szukam .. Przeczytam kod, który jest ładnie komentowany i wygląda prosto. – user1403598

+1

Interesujący, przykładowy kod robi * dokładnie * co [ten post na blogu zespołu wsparcia Windows SDK] (http://blogs.msdn.com/b/winsdk/archive/2009/07/14/launching-an-interactive-process-from-windows-service-in-windows-vista-and-later.aspx) mówi powinieneś "nigdy, nigdy nigdy nie robić": kradzież tokena dostępu do procesu eksploratora działającego na pulpicie interakcyjnego użytkownika, otwieranie tokena dostępu do tego procesu i tworzenie nowego procesu z tym tokenem. –

+0

Ten kod był dokładnie tym, czego szukałem. Utworzono nową klasę. Upuściłem ten kod, wykonałem połączenie i zadziałało pierwsza próba. Dziękuję bardzo za opublikowanie tego. – Grayson

9

Jak jest tak powszechne, ze tego rodzaju pytania dotyczące usług Windows, jesteś działających w mentalności systemu operacyjnego pojedynczego użytkownika . Cały powód, dla którego zdecydowałeś się napisać swoją aplikację jako usługę, był spowodowany konfliktami między twoim modelem mentalnym systemu operacyjnego dla jednego użytkownika a rzeczywistością systemu operacyjnego dla wielu użytkowników. Niestety, usługa nie rozwiązała wszystkich twoich problemów, a teraz próbujesz dowiedzieć się, jak osiągnąć drugi krok w ostatecznie skazanym na zhackowanie projekcie.

Faktem jest, że nie można zagwarantować, że nie jest jest „zalogowany użytkownik”. Jeśli nikt nie zalogował się na stacji roboczej, nikt nie zaloguje się, ale Twoja usługa będzie nadal działać.

Nawet jeśli jakoś przeszłość to poprzez zapewnienie, że ktoś będzie zawsze być zalogowany (niemożliwe), wtedy można uruchomić w sytuacji, gdy wiele użytkownicy zalogowany. W takim razie, który z twoich usług powinien rozpocząć proces? Czy powinien wybrać jeden z nich losowo?

Czy w twoim przypadku trzeba odróżnić użytkowników zalogowanych lokalnie od konsoli i tych, którzy są zalogowani zdalnie? Pamiętaj, że użytkownicy zdalni nie będą mieli konsoli lokalnej.

Jeśli zdołasz jakoś ominąć wszystkie te przeszkody (niestety, prawdopodobnie chowając głowę w piasku i udając, że Windows jest systemem operacyjnym dla jednego użytkownika), możesz skorzystać z funkcji WTSGetActiveConsoleSessionId, aby uzyskać identyfikator bieżącej sesji, funkcja WTSQueryUserToken, aby uzyskać token użytkownika odpowiadający temu identyfikatorowi sesji, a następnie funkcję CreateProcessAsUser, aby uruchomić proces w kontekście tego użytkownika. Jeśli taki istnieje. I mają odpowiednie uprawnienia. A fizyczna konsola nie jest podłączona do sesji fikcyjnej. I nie uruchamiasz kodu SKU serwera, który pozwala na wiele aktywnych sesji konsoli. I & hellip;

Jeśli możesz zdecydować o konkretnym użytkowniku, którego konto chcesz użyć do rozpoczęcia procesu pomocniczego, możesz zalogować się do tego użytkownika, manipulować jego tokenem użytkownika, wykonać proces, a na koniec zamknąć proces i wylogować użytkownika . CreateProcessWithLogonUser function zawija wiele z tych harów dla ciebie, sprawiając, że kod jest dużo bardziej smukły. Ale pozory mogą być mylące, a to nadal ma poważne konsekwencje bezpieczeństwa, które prawdopodobnie nie do końca zrozumiesz, jeśli zadajesz to pytanie w pierwszej kolejności. I naprawdę nie możesz sobie pozwolić na niezrozumienie takich zagrożeń bezpieczeństwa.

Poza tym użytkownicy, którzy są zalogowani za pomocą LogonUser (która jest wykonywana automatycznie podczas korzystania z funkcji CreateProcessWithLogonUser), nie mają stacji okien i pulpitu, na których mogą uruchamiać procesy interaktywne. Jeśli więc proces, który chcesz uruchomić w kontekście tego użytkownika, będzie pokazywał dowolny rodzaj interfejsu, nie masz szczęścia. Windows zabije twoją aplikację, gdy tylko spróbuje uzyskać dostęp do pulpitu, dla którego nie ma wymaganych uprawnień. Nie ma sposobu, aby z usługi Windows uzyskać uchwyt pulpitu, który będzie dla ciebie przydatny (co w dużym stopniu wyjaśnia wyjaśnienie ogólnej zasady, która prawdopodobnie już wiesz, że usługi nie mogą wyświetlać żadnego rodzaju interfejsu użytkownika).

+0

Naprawdę podobało mi się "ostatecznie skazane". Ale 'CreateProcessWithLogonW' nie pomoże mu, ponieważ nie ma poświadczeń użytkownika. –

+0

Usługa Windows została pierwotnie zaprojektowana do przyjmowania wiadomości przychodzących i przetwarzania ich zgodnie z wymaganiami (Korzystanie z systemu wiadomości ze zdalnego dostępu do usługi). Usługa działa tak celowo, ale teraz wymagana jest dodatkowa specyfikacja. Niefortunnie niektóre aplikacje Api muszą być wywoływane jako bieżący użytkownik, a więc powodem, dla którego teraz jest to wymagane. Rozumiem zagrożenia bezpieczeństwa, ale będzie to wywoływać tylko kilka interfejsów API zdefiniowanych dla użytkowników CU/Active. Mogę i usługa zapewnia, że ​​użytkownik jest zalogowany na komputerze, jeśli nie, to zgłosi to z powrotem. – user1403598

+0

Co zamierza "zgłosić"? Nie ma żadnego użytkownika zalogowanego! A jakie są te API, które należy wywołać? Dlaczego wymagają wywoływania jako określonego użytkownika? Wygląda na to, że jest to prawdziwe rozwiązanie twojego problemu. –

Powiązane problemy