このトピックに関する数週間の調査の後、私はついに自分のスレッドを開始することにしました。経験のある人が助けてくれることを願っています。私はそこにあるさまざまなコーディング例を理解しようとしてインターネットを精査しましたが、実用的なソリューションをまとめようと試みました。いくつかの背景から始めましょう-
背景:
CA IT Client Manager(ITCM)を使用して組織内のWindowsServerおよびPCに配信されるvb.netアプリケーションがあります。Microsoft SCCMと同様に、CA ITCMには、各PCでSYSTEMとして実行されるエージェントサービスがあります。したがって、アプリケーションがターゲットPCで配信および実行されると、「NT Authority\SYSTEM」コンテキストで実行されます。
問題:
アプリケーションの初期段階で、ログインしている各ユーザーのコンテキストで実行されているプロセスがあり、停止する必要があります。アプリケーションの実行の最後に、ログオンしているユーザーごとにこのプロセスを再開して、ユーザーがログオフして再度ログオンする必要がないようにする必要があります。私が停止しているプロセスは、実際にはユーザーがデスクトップで操作できるシステムトレイプロセスです。
VB.NETソリューションの追跡:
インターネットで延々と調査していると、ログオンしている各ユーザーのパスワードを取得したり、ユーザーに資格情報の入力を求めたりしない限り、この問題に対するネイティブの.NETソリューションはないようです。これは私にとってオプションではないため、ログオンしているユーザーの資格情報を知らなくても、必要とせずにプロセスを開始する方法を見つける必要があります。
この方法を調べて、CreateProcessAsUserWindowsAPI関数にたどり着きました。私が理解していることから、私はこれらの線に沿って何かをすることができます-(以下を参照)
注:
VB.NETでWindowsAPIへのアンマネージコード呼び出しを使用するのはこれが初めてです。さまざまな投稿からコードをつなぎ合わせたため、定数、列挙、関数宣言には多くのあいまいさがあります。これらの宣言のいずれかに誤りがある場合は、お知らせください。データ型を別の型として「マーシャリング」する必要がある場合について、多くの質問があります。注意深く読んでください!!
同様の投稿から数え切れないほどの例があったので、CreateProcessAsUserページのMSDNの例に従おうとしました。
MSDNリンク: http:
//msdn.microsoft.com/en-us/library/windows/desktop/ms682429 (v = vs.85).aspx
リンクの例:http:
//msdn.microsoft.com/en-us/library/windows/desktop/aa379608 (v = vs.85).aspx
各WindowsAPI呼び出しの有効性を確認することに加えて、操作の全体的な順序を確認し、これを複雑にしすぎているか、何かが不足している可能性があるかどうかを知らせてください。Microsoftの例から実装していない唯一のコードは、各SIDにインタラクティブWindowsステーションへのフルアクセスを許可し、続いてSIDにインタラクティブデスクトップへのフルアクセスを許可することです。私は間違っているかもしれませんが、各ユーザーはすでにインタラクティブデスクトップにアクセスできるはずです。
Public Class WindowsAPI
Private Const SE_CREATE_TOKEN_NAME As String = "SeCreateTokenPrivilege"
Private Const SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege"
Private Const SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege"
Private Const SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"
Private Const SE_UNSOLICITED_INPUT_NAME = "SeUnsolicitedInputPrivilege"
Private Const SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege"
Private Const SE_TCB_NAME = "SeTcbPrivilege"
Private Const SE_SECURITY_NAME = "SeSecurityPrivilege"
Private Const SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege"
Private Const SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege"
Private Const SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege"
Private Const SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege"
Private Const SE_PROF_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege"
Private Const SE_INC_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege"
Private Const SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege"
Private Const SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege"
Private Const SE_BACKUP_NAME = "SeBackupPrivilege"
Private Const SE_RESTORE_NAME = "SeRestorePrivilege"
Private Const SE_SHUTDOWN_NAME = "SeShutdownPrivilege"
Private Const SE_DEBUG_NAME = "SeDebugPrivilege"
Private Const SE_AUDIT_NAME = "SeAuditPrivilege"
Private Const SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege"
Private Const SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege"
Private Const SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege"
Private Const SE_UNDOCK_NAME = "SeUndockPrivilege"
Private Const SE_SYNC_AGENT_NAME = "SeSyncAgentPrivilege"
Private Const SE_ENABLE_DELEGATION_NAME = "SeEnableDelegationPrivilege"
Private Const SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege"
Private Const SE_IMPERSONATE_NAME = "SeImpersonatePrivilege"
Private Const SE_CREATE_GLOBAL_NAME = "SeCreateGlobalPrivilege"
Private Const SE_PRIVILEGE_ENABLED As Integer = &H2
Private Enum WindowShowStyle As UInteger
Hide = 0
ShowNormal = 1
ShowMinimized = 2
ShowMaximized = 3
Maximize = 3
ShowNormalNoActivate = 4
Show = 5
Minimize = 6
ShowMinNoActivate = 7
ShowNoActivate = 8
Restore = 9
ShowDefault = 10
ForceMinimized = 11
End Enum
Private Enum STARTF As Integer
STARTF_USESHOWWINDOW = &H1
STARTF_USESIZE = &H2
STARTF_USEPOSITION = &H4
STARTF_USECOUNTCHARS = &H8
STARTF_USEFILLATTRIBUTE = &H10
STARTF_RUNFULLSCREEN = &H20
STARTF_FORCEONFEEDBACK = &H40
STARTF_FORCEOFFFEEDBACK = &H80
STARTF_USESTDHANDLES = &H100
STARTF_USEHOTKEY = &H200
End Enum
Private Enum CreateProcessFlags
DEBUG_PROCESS = &H1
DEBUG_ONLY_THIS_PROCESS = &H2
CREATE_SUSPENDED = &H4
DETACHED_PROCESS = &H8
CREATE_NEW_CONSOLE = &H10
NORMAL_PRIORITY_CLASS = &H20
IDLE_PRIORITY_CLASS = &H40
HIGH_PRIORITY_CLASS = &H80
REALTIME_PRIORITY_CLASS = &H100
CREATE_NEW_PROCESS_GROUP = &H200
CREATE_UNICODE_ENVIRONMENT = &H400
CREATE_SEPARATE_WOW_VDM = &H800
CREATE_SHARED_WOW_VDM = &H1000
CREATE_FORCEDOS = &H2000
BELOW_NORMAL_PRIORITY_CLASS = &H4000
ABOVE_NORMAL_PRIORITY_CLASS = &H8000
INHERIT_PARENT_AFFINITY = &H10000
INHERIT_CALLER_PRIORITY = &H20000
CREATE_PROTECTED_PROCESS = &H40000
EXTENDED_STARTUPINFO_PRESENT = &H80000
PROCESS_MODE_BACKGROUND_BEGIN = &H100000
PROCESS_MODE_BACKGROUND_END = &H200000
CREATE_BREAKAWAY_FROM_JOB = &H1000000
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = &H2000000
CREATE_DEFAULT_ERROR_MODE = &H4000000
CREATE_NO_WINDOW = &H8000000
PROFILE_USER = &H10000000
PROFILE_KERNEL = &H20000000
PROFILE_SERVER = &H40000000
CREATE_IGNORE_SYSTEM_DEFAULT = &H80000000
End Enum
Private Enum ACCESS_MASK
DELETE = &H10000
READ_CONTROL = &H20000
WRITE_DAC = &H40000
WRITE_OWNER = &H80000
SYNCHRONIZE = &H100000
STANDARD_RIGHTS_REQUIRED = &HF0000
STANDARD_RIGHTS_READ = &H20000
STANDARD_RIGHTS_WRITE = &H20000
STANDARD_RIGHTS_EXECUTE = &H20000
STANDARD_RIGHTS_ALL = &H1F0000
SPECIFIC_RIGHTS_ALL = &HFFFF
ACCESS_SYSTEM_SECURITY = &H1000000
MAXIMUM_ALLOWED = &H2000000
GENERIC_READ = &H80000000
GENERIC_WRITE = &H40000000
GENERIC_EXECUTE = &H20000000
GENERIC_ALL = &H10000000
DESKTOP_READOBJECTS = &H1
DESKTOP_CREATEWINDOW = &H2
DESKTOP_CREATEMENU = &H4
DESKTOP_HOOKCONTROL = &H8
DESKTOP_JOURNALRECORD = &H10
DESKTOP_JOURNALPLAYBACK = &H20
DESKTOP_ENUMERATE = &H40
DESKTOP_WRITEOBJECTS = &H80
DESKTOP_SWITCHDESKTOP = &H100
WINSTA_ENUMDESKTOPS = &H1
WINSTA_READATTRIBUTES = &H2
WINSTA_ACCESSCLIPBOARD = &H4
WINSTA_CREATEDESKTOP = &H8
WINSTA_WRITEATTRIBUTES = &H10
WINSTA_ACCESSGLOBALATOMS = &H20
WINSTA_EXITWINDOWS = &H40
WINSTA_ENUMERATE = &H100
WINSTA_READSCREEN = &H200
WINSTA_ALL_ACCESS = &H37F
End Enum
<StructLayout(LayoutKind.Sequential)>
Private Structure PROCESS_INFORMATION
Public hProcess As IntPtr
Public hThread As IntPtr
Public dwProcessId As System.UInt32
Public dwThreadId As System.UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Private Structure SECURITY_ATTRIBUTES
Public nLength As System.UInt32
Public lpSecurityDescriptor As IntPtr
Public bInheritHandle As Boolean
End Structure
<StructLayout(LayoutKind.Sequential)>
Private Structure STARTUPINFO
Public cb As System.UInt32
Public lpReserved As String
Public lpDesktop As String
Public lpTitle As String
Public dwX As System.UInt32
Public dwY As System.UInt32
Public dwXSize As System.UInt32
Public dwYSize As System.UInt32
Public dwXCountChars As System.UInt32
Public dwYCountChars As System.UInt32
Public dwFillAttribute As System.UInt32
Public dwFlags As System.UInt32
Public wShowWindow As Short
Public cbReserved2 As Short
Public lpReserved2 As IntPtr
Public hStdInput As IntPtr
Public hStdOutput As IntPtr
Public hStdError As IntPtr
End Structure
Private Enum SECURITY_IMPERSONATION_LEVEL
SecurityAnonymous = 0
SecurityIdentification = 1
SecurityImpersonation = 2
SecurityDelegation = 3
End Enum
Private Enum TOKEN_TYPE
TokenPrimary = 1
TokenImpersonation = 2
End Enum
Structure LUID
Public LowPart As UInt32
Public HighPart As Integer
End Structure
Structure TOKEN_PRIVILEGES
Public PrivilegeCount As Integer
Public TheLuid As LUID
Public Attributes As Integer
End Structure
Enum TOKEN_INFORMATION_CLASS
TokenUser = 1
TokenGroups
TokenPrivileges
TokenOwner
TokenPrimaryGroup
TokenDefaultDacl
TokenSource
TokenType
TokenImpersonationLevel
TokenStatistics
TokenRestrictedSids
TokenSessionId
TokenGroupsAndPrivileges
TokenSessionReference
TokenSandBoxInert
TokenAuditPolicy
TokenOrigin
TokenElevationType
TokenLinkedToken
TokenElevation
TokenHasRestrictions
TokenAccessInformation
TokenVirtualizationAllowed
TokenVirtualizationEnabled
TokenIntegrityLevel
TokenUIAccess
TokenMandatoryPolicy
TokenLogonSid
MaxTokenInfoClass
End Enum
<StructLayoutAttribute(LayoutKind.Sequential)>
Public Structure SECURITY_DESCRIPTOR
Public revision As Byte
Public size As Byte
Public control As Short
Public owner As IntPtr
Public group As IntPtr
Public sacl As IntPtr
Public dacl As IntPtr
End Structure
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function AdjustTokenPrivileges(ByVal TokenHandle As IntPtr,
ByVal DisableAllPrivileges As Boolean,
ByRef NewState As TOKEN_PRIVILEGES,
ByVal BufferLengthInBytes As UInt32,
ByRef PreviousState As TOKEN_PRIVILEGES,
ByRef ReturnLengthInBytes As UInt32) As Boolean
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function CreateProcessAsUser(ByVal hToken As IntPtr,
ByVal lpApplicationName As String,
ByVal lpCommandLine As String,
ByRef lpProcessAttributes As SECURITY_ATTRIBUTES,
ByRef lpThreadAttributes As SECURITY_ATTRIBUTES,
ByVal bInheritHandles As Boolean,
ByVal dwCreationFlags As UInteger,
ByVal lpEnvironment As IntPtr,
ByVal lpCurrentDirectory As String,
ByRef lpStartupInfo As STARTUPINFO,
ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function DuplicateTokenEx(ByVal hExistingToken As IntPtr,
ByVal dwDesiredAccess As UInteger,
ByRef lpTokenAttributes As SECURITY_ATTRIBUTES,
ByVal ImpersonationLevel As SECURITY_IMPERSONATION_LEVEL,
ByVal TokenType As TOKEN_TYPE,
ByRef phNewToken As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function ImpersonateLoggedOnUser(ByVal hToken As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr,
ByVal DesiredAccess As Integer,
ByRef TokenHandle As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function RevertToSelf() As Boolean
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function GetProcessWindowStation() As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function OpenDesktop(ByVal lpszDesktop As String,
ByVal dwFlags As Integer,
ByVal fInderit As Boolean,
ByVal dwDesiredAccess As Integer) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function OpenWindowStation(ByVal lpszWinSta As String,
ByVal fInherit As Boolean,
ByVal dwDesiredAccess As ACCESS_MASK) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function SetProcessWindowStation(ByVal hWinSta As IntPtr) As Boolean
End Function
Public Shared Function LaunchProcess(ByVal CmdLine As String) As Boolean
' Declare and initialize variables
Dim ExplorerProcesses As Process()
Dim UserTokenHandle As IntPtr
Dim PrimaryTokenHandle As IntPtr
Dim CurrentWinStationHandle As IntPtr
Dim InteractiveWinStationHandle As IntPtr
Dim InteractiveDesktopHandle As IntPtr
Dim StartupInfo As STARTUPINFO
Dim ProcessInfo As PROCESS_INFORMATION
' Get all explorer.exe IDs
ExplorerProcesses = Process.GetProcessesByName("explorer")
' Verify explorers were found
If ExplorerProcesses.Length = 0 Then
' Return
Return True
End If
' Iterate each explorer.exe process
For Each ExplorerProcess As Process In ExplorerProcesses
' Get the user token handle address (Query access level)
If OpenProcessToken(ExplorerProcess.Handle, TokenAccessLevels.MaximumAllowed, UserTokenHandle) = False Then
' Do some error handling
' Iterate the next process
Continue For
End If
' Get a primary token
If DuplicateTokenEx(UserTokenHandle,
TokenAccessLevels.MaximumAllowed,
Nothing,
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenPrimary,
PrimaryTokenHandle) = False Then
' Do some error handling
' Iterate the next process
Continue For
End If
' Save a handle to the current window station
CurrentWinStationHandle = GetProcessWindowStation()
' Check for valid handle to the windows station
If CurrentWinStationHandle = IntPtr.Zero Then
' Do some error handling
' Iterate the next process
Continue For
End If
' Get a handle to the interactive window station
InteractiveWinStationHandle = OpenWindowStation("winsta0", False, ACCESS_MASK.READ_CONTROL Or ACCESS_MASK.WRITE_DAC)
' Check for a valid handle
If InteractiveWinStationHandle = Nothing Then
' Do some error handling
' Iterate the next user
Continue For
End If
' To get the correct default desktop, set the caller's window station to the interactive window station
If SetProcessWindowStation(InteractiveWinStationHandle) = False Then
' Do some error handling
' Iterate the next user
Continue For
End If
' Get handle to interactive desktop
InteractiveDesktopHandle = OpenDesktop("default",
0,
False,
ACCESS_MASK.READ_CONTROL Or
ACCESS_MASK.WRITE_DAC Or
ACCESS_MASK.DESKTOP_WRITEOBJECTS Or
ACCESS_MASK.DESKTOP_READOBJECTS)
' Restore the caller's window station
If SetProcessWindowStation(CurrentWinStationHandle) = False Then
' Do some error handling
' Iterate the next user
Continue For
End If
' Check for a valid handle
If InteractiveDesktopHandle = IntPtr.Zero Then
' Do some error handling
' Iterate the next user
Continue For
End If
' Initialize process and startup info
ProcessInfo = New PROCESS_INFORMATION
StartupInfo = New STARTUPINFO
StartupInfo.cb = Marshal.SizeOf(StartupInfo)
StartupInfo.lpDesktop = "winsta0\default"
' Impersonate client to ensure access to executable file
If ImpersonateLoggedOnUser(PrimaryTokenHandle) = False Then
' Do some error handling
' Iterate the next user
Continue For
End If
' Launch the process in the client's logon session
If CreateProcessAsUser(PrimaryTokenHandle,
Nothing,
CmdLine,
Nothing,
Nothing,
False,
CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT Or
CreateProcessFlags.NORMAL_PRIORITY_CLASS Or,
Nothing,
Nothing,
StartupInfo,
ProcessInfo) = False Then
' Do some error handling
' Iterate the next user
Continue For
End If
' End impersonation of client
If RevertToSelf() = False Then
' Do some error handling
' Iterate the next user
Continue For
End If
Next
' Check for open handle
If Not PrimaryTokenHandle = IntPtr.Zero Then
' Close the handle
CloseHandle(PrimaryTokenHandle)
End If
' Return
Return True
End Function
End Class
結果:
現在、管理者アカウント(ローカルマシンでVisual Studio 2010からソリューションを実行)から、およびITCM(ローカルマシンでSYSTEMアカウントから実行)を介してアプリケーションを配信することにより、LaunchProcess関数の呼び出しをテストしています。どちらの場合も、指定されたプロセスをユーザーセッションで開始しますが、次のエラーが発生します。
「アプリケーションを正しく起動できませんでした(0xc0000142)。[OK]をクリックしてアプリケーションを閉じてください。」
誰かが私のコードを確認して、正しい方向に向けてくれることを願っています。それ以外の場合は、ここで何がうまくいかないのかをデバッグする方法についてアドバイスしてください。
事前にすべての入力に感謝します。