CreateProcessAsUser la Création de la Fenêtre de Session Active
Je suis en utilisant CreateProcessAsUser partir d'un service windows (veuillez pouvons-nous rester dans le sujet, et supposons que j'ai une très bonne raison pour faire ce). Contrairement à ce que tout le monde se pose la question ici, j'obtiens une fenêtre dans ma session de terminal (session 1) au lieu de la même session que le service (session 0) - ce qui est indésirable.
Je appropriation Scott Allen code; et est venu avec ce qui suit. Changements notables sont les "revenir à soi", le "CREATE_NO_WINDOW" en ligne de commande et les arguments de soutien.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Security.Principal;
using System.ComponentModel;
using System.IO;
namespace SourceCode.Runtime.ChildProcessService
{
[SuppressUnmanagedCodeSecurity]
class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
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 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;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessID;
public Int32 dwThreadID;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
public const int GENERIC_ALL_ACCESS = 0x10000000;
public const int CREATE_NO_WINDOW = 0x08000000;
[
DllImport("kernel32.dll",
EntryPoint = "CloseHandle", SetLastError = true,
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
]
public static extern bool CloseHandle(IntPtr handle);
[
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, Int32 dwCreationFlags, IntPtr lpEnvrionment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
[
DllImport("advapi32.dll",
EntryPoint = "DuplicateTokenEx")
]
public static extern bool
DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
public static Process CreateProcessAsUser(string filename, string args)
{
var hToken = WindowsIdentity.GetCurrent().Token;
var hDupedToken = IntPtr.Zero;
var pi = new PROCESS_INFORMATION();
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
try
{
if (!DuplicateTokenEx(
hToken,
GENERIC_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref hDupedToken
))
throw new Win32Exception(Marshal.GetLastWin32Error());
var si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";
var path = Path.GetFullPath(filename);
var dir = Path.GetDirectoryName(path);
//Revert to self to create the entire process; not doing this might
//require that the currently impersonated user has "Replace a process
//level token" rights - we only want our service account to need
//that right.
using (var ctx = WindowsIdentity.Impersonate(IntPtr.Zero))
{
if (!CreateProcessAsUser(
hDupedToken,
path,
string.Format("\"{0}\" {1}", filename.Replace("\"", "\"\""), args),
ref sa, ref sa,
false, 0, IntPtr.Zero,
dir, ref si, ref pi
))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return Process.GetProcessById(pi.dwProcessID);
}
finally
{
if (pi.hProcess != IntPtr.Zero)
CloseHandle(pi.hProcess);
if (pi.hThread != IntPtr.Zero)
CloseHandle(pi.hThread);
if (hDupedToken != IntPtr.Zero)
CloseHandle(hDupedToken);
}
}
}
}
Supposons maintenant que le service est en cours d'exécution en vertu de l' "Domaine\MyService et je suis actuellement connecté en tant que" Domaine\Administrateur " - et que je suis le démarrage d'une application console comme un processus de travail. Lorsque j'utilise une application client pour accéder au service (le service n'est pas lancé en mode console c'est à dire qu'il est dans la session 0) et d'exécuter la méthode qui appelle la CreateProcessAsUser
le processus de travail s'affiche sur mon bureau.
Maintenant, je pourrait en faire une application windows avec pas de fenêtre, à côté de l'étape de la création de la fenêtre de la console; cependant, à la fin de la journée, c'est encore en cours de création de la session 1.
Des idées pourquoi l'application de la console n'est pas créé dans la même session en tant que service?
Essayé à l'aide de "Service-0×0-3e7$\Default" comme le bureau - qui provoque un crash de l'application.
Quelle version de Windows? Avez-vous essayé de quitter lpDeskTop à null?
Server 2008 R2. J'ai en effet essayé de réglage
lpDeskTop
à null
(qui a causé un accident dans le processus de travail) - j'ai aussi essayé de réglage pour différentes valeurs codées en dur tel que le construit-dans la session 0 ordinateur de bureau nom.Si de nombreuses circonstances sont à l'origine des accidents, il est peut-être un regroupement question. Pouvez-vous poster le code de vos structures et externes?
OriginalL'auteur Jonathan Dickinson | 2012-02-01
Vous devez vous connecter pour publier un commentaire.
Comme vous le savez probablement déjà, l'isolement de la Session de 0 pour des raisons de sécurité, et vous pouvez en lire plus à ce sujet ici
http://msdn.microsoft.com/en-us/windows/hardware/gg463353.aspx
Quant à savoir pourquoi votre console app est créé dans la session active (par exemple, session 1), de ce fait lié directement à votre jeton de l'utilisateur. Lorsque vous demandez de l'utilisateur actuel jeton, ce jeton automatiquement avec l'id de session de l'information - dans ce cas, c'est le login de session des services terminal (session 1). Cet id de session est la référence par le jeton qui a ensuite répliqué dans le DuplicateTokenEx et ensuite utilisé dans le CreateProcessAsUser appel. Afin de forcer la création de votre application console dans la session 0, vous aurez besoin de faire un appel explicite à la SetTokenInformation API (advapi32.dll), passé dans votre hDupedToken avant d'appeler CreateProcessAsUser comme ci-dessous
Voici plus d'infos sur SetTokenInformation http://msdn.microsoft.com/en-us/library/windows/desktop/aa379591(v=vs. 85).aspx
Merci beaucoup pour l'aide - je suis juste à avoir des problèmes avec l'acquisition de la
SE_TCB_NAME
droit (ce qui est nécessaire pourSetTokenInformation
). J'ai accordé mon compte de service "Agir en tant que partie du système d'exploitation" à droite (comme le SERVICE de fusil de chasse de l'assurance). J'ai essayé d'utiliserOpenThreadToken
avecTOKEN_ALL_ACCESS
- en vain. Vous avez gagné le +de 250 je suis juste en espérant vous avoir un peu plus d'expertise dans ce domaine pour m'aider.Vous obtenez le bounty. Temps de commencer un autre bounty ;).
Merci pour la générosité. Je ne pense pas qu'il y a beaucoup de moyen de contourner cela, si votre service est lancé à l'aide du compte d'utilisateur qui, par lui-même est limité OS privilège. Ne pouvez pas vous lancer à votre service à l'aide de compte LocalSystem? LocalSystem pouvez lancer votre processus et automatiquement que le droit de la sécurité et de l'accès à d'autres WTS API dont vous pourriez avoir besoin dans TS de l'environnement.
J'ai pensé à cela, mais il a une très haute installateur d'impact (notre premier service doit s'exécuter sous un compte de domaine) - encore, je vais le garder dans le sac pour plus tard et de voir si la direction va mordre, compte tenu du risque. Merci pour l'aide.
OriginalL'auteur Fadrian Sudaman
J'ai été en mesure de mettre en œuvre le post initial comme une solution de travail sur ma fin, cependant, je n'arrive pas à trouver un moyen de garder ma Fenêtre de console caché. J'ai essayé STARTF_USESHOWWINDOW et SW_HIDE mais ma commande fenêtre pop-up. Aucune idée pourquoi?
OriginalL'auteur Saif Khan
Essayer de déconner avec le jeu de caractères nommé paramètre de
MarshalAs
,StructLayout
, etDllImport
. Vous devrez peut-être ajouterMarshalAs
à diverses chaînes dans l'ordre pour ce faire. Ne vous embêtez pas avec les caractères Unicode: vous n'êtes pas l'utilisation de ce. Je vous recommande de créer de toutes pourCharSet.Ansi
premier. Exécuter tous les tests que vous avez déjà essayé de--c'est, bureau et tous les trucs fun. Si elle se bloque, les mettre tous à l'auto. Si cela ne fonctionne toujours pas, supprimez-les tous.En supposant que rien de tout cela fonctionne, l'interrupteur à
CreateUserProcessW
etCharSet.Unicode
de sorte que vous savez ce que vous allez obtenir. À bien y penser, il suffit de sauter cette étape.Si vous avez besoin de définir la
UnmanagedType
avecMarshalAs
pour les chaînes, vous voulezUnmanagedType.LPStr
pour la norme Ansi,UnmanagedType.LPTStr
pour l'Automobile, etUnmanagedType.LPWStr
pour l'Unicode. En fait, le faire pour tous vos cordes de toute façon.merci - je vais lui donner un aller, ce soir, et de faire rapport.
Bonne chance! Si vous vous sentez ambitieux, passez directement à l'Unicode.
OriginalL'auteur Zenexer