3

このトピックに関する数週間の調査の後、私はついに自分のスレッドを開始することにしました。経験のある人が助けてくれることを願っています。私はそこにあるさまざまなコーディング例を理解しようとしてインターネットを精査しましたが、実用的なソリューションをまとめようと試みました。いくつかの背景から始めましょう-

背景:
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]をクリックしてアプリケーションを閉じてください。」

誰かが私のコードを確認して、正しい方向に向けてくれることを願っています。それ以外の場合は、ここで何がうまくいかないのかをデバッグする方法についてアドバイスしてください。

事前にすべての入力に感謝します。

4

1 に答える 1

2

ソリューション:

完全なコードソリューションを投稿する前に、私は自分の答えをどのように見つけたかを共有したいと思いました。CreateProcessAsUser API関数に関するMSDNの記事を再確認した後、自分のプロセスが記事に記載されている必要な特権を実際に保持しているかどうかを確認する必要があることに気付きました。

SE_INCREASE_QUOTA_NAME

SE_ASSIGNPRIMARYTOKEN_NAME

また、記事には記載されていませんが、上記の特権を有効にするためにトークン特権を検索および調整するための他の関連するWindowsAPI呼び出しのいくつかにとっておそらく重要です。

SE_TCB_NAME

私のアプリケーションは、CAのITクライアントマネージャー(ITCM)ソフトウェアを使用してWindowsサーバーとPCを対象に配信されていることを思い出してください。コアCAITCMエージェントサービスは「ローカルシステム」としてログオンしますが、すべてのダーティワークの起動を実行し、SYSTEMアカウントとして実行するプラグインです。どうやら、システムアカウントと「ローカルシステム」アカウントの間には大きな違いがあります。

SysInternalのProcessExplorerツールを使用して、アプリケーションを検査し、必要なすべての特権を保持していないことを確認できました。テストを実行してからしばらく経ちましたので、実際にどの特権が保持されていなかったかを忘れてしまいます。

私が最初に犯した間違いは、不足している特権を有効にしようとするアンマネージWindows API関数呼び出しを作成することでしたが、残念ながら、そのようには機能しません。プロセスに特権があるか、ないかのどちらかです。それが特権を保持している場合、特権が有効になっていることを確認するのはあなたの唯一の責任です。

これを克服するために、私は別のアプローチを使用しなければなりませんでした。必要な権限を取得するには、アプリケーションをサービスとしてインストールして実行する必要がありました。これにより、アプリケーションを「ローカルシステム」アカウントとして実行できるようになりました。ただし、この1つの単純な要件を満たすためだけに、アプリケーション全体をインストール可能なサービスとして再設計することは意味がありませんでした。

代わりに、投稿しているコードである2番目のVB.NETプロジェクトを作成しました。2番目のプロジェクトは、起動パラメーターを受け取る単純なWindowsサービスです。最初の起動パラメータは、ログオンしているユーザーごとに起動するアプリケーションです。残りのスタートアップパラメータは、スタートアップスイッチとして指定したアプリケーションに渡されます:-)

適切な特権を保持し、ログインしたユーザーごとに起動するものを正確に指定するための起動パラメーターを動的に受信できるサービスを備えた私は、結果の実行可能ファイルを最初のプロジェクトに埋め込みました。

SYSTEMアカウントとして実行されている私の最初のプロジェクトには、新しいシステムサービスをインストールする権利/権限/特権があります。また、システムにログインしている各ユーザーのトレイサービスを開始するために必要なパラメーターを渡して、そのシステムサービスを開始する権限もあります。問題が解決しました!

これが私のWindowsサービスのコードです-

LaunchService.vb:

'****************************** Class Header *******************************\
' Project Name: LaunchService
' Class Name:   LaunchService
' File Name:    LaunchService.vb
' Author:       fonbr01
' 
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
' MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
' IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
' OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
' ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
' OTHER DEALINGS IN THE SOFTWARE.
'***************************************************************************/

Public Class LaunchService

    Protected Overrides Sub OnStart(ByVal args() As String)

        ' Local Variables
        Dim AppName As String

        ' Get the application name
        AppName = args(0)
        args(0) = " "

        ' Check for additional arguments
        If args.Length > 1 Then

            ' Shift the arguments
            For i As Integer = 1 To args.Length - 1

                ' Swap the args
                args(i - 1) = args(i)

            Next

            ' Remove the last argument
            args(args.Length - 1) = ""

        End If

        ' Launch the App for all users
        WindowsAPI.LaunchProcess(AppName, args)

    End Sub

    Protected Overrides Sub OnStop()

    End Sub

End Class

WindowsAPI.vb:

'****************************** Class Header *******************************\
' Project Name: LaunchService
' Class Name:   WindowsAPI
' File Name:    WindowsAPI.vb
' Author:       fonbr01
' 
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
' MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
' IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
' OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
' ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
' OTHER DEALINGS IN THE SOFTWARE.
'***************************************************************************/

' Imports
Imports Microsoft.Win32.SafeHandles
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Imports System.Diagnostics

' Windows API Class
Public Class WindowsAPI

    ' *************************
    ' * Windows API Functions
    ' *************************

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function AdjustTokenPrivileges(
        <[In]()> ByVal TokenHandle As SafeTokenHandle,
        <[In](), MarshalAs(UnmanagedType.Bool)> ByVal DisableAllPrivileges As Boolean,
        <[In]()> ByRef NewState As TOKEN_PRIVILEGES,
        <[In]()> ByVal BufferLengthInBytes As UInt32,
        <Out()> ByRef PreviousState As TOKEN_PRIVILEGES,
        <Out()> ByRef ReturnLengthInBytes As UInt32) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function CreateProcessAsUser(
        <[In]()> ByVal hToken As SafeTokenHandle,
        <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpApplicationName As String,
        <[In](), Out(), MarshalAs(UnmanagedType.LPWStr)> ByVal lpCommandLine As String,
        <[In]()> ByRef lpProcessAttributes As SECURITY_ATTRIBUTES,
        <[In]()> ByRef lpThreadAttributes As SECURITY_ATTRIBUTES,
        <[In](), MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean,
        <[In]()> ByVal dwCreationFlags As UInteger,
        <[In]()> ByVal lpEnvironment As IntPtr,
        <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpCurrentDirectory As String,
        <[In]()> ByRef lpStartupInfo As STARTUPINFO,
        <Out()> ByRef lpProcessInformation As PROCESS_INFORMATION) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function DuplicateToken(
        <[In]()> ByVal ExistingTokenHandle As SafeTokenHandle,
        <[In]()> ByVal ImpersonationLevel As SECURITY_IMPERSONATION_LEVEL,
        <Out()> ByRef DuplicateTokenHandle As SafeTokenHandle) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function DuplicateTokenEx(
        <[In]()> ByVal hExistingToken As IntPtr,
        <[In]()> ByVal dwDesiredAccess As UInteger,
        <[In]()> ByRef lpTokenAttributes As SECURITY_ATTRIBUTES,
        <[In]()> ByVal ImpersonationLevel As SECURITY_IMPERSONATION_LEVEL,
        <[In]()> ByVal TokenType As TOKEN_TYPE,
        <Out()> ByRef phNewToken As SafeTokenHandle) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function LookupPrivilegeValue(
        <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpSystemName As String,
        <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpName As String,
        <Out()> ByRef lpLuid As LUID) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function OpenProcessToken(
        <[In]()> ByVal hProcess As IntPtr,
        <[In]()> ByVal desiredAccess As UInt32,
        <Out()> ByRef hToken As SafeTokenHandle) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function


    ' *************************
    ' * Structures
    ' *************************

    <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 Structure LUID
        Public LowPart As UInt32
        Public HighPart As Integer
    End Structure

    Private Structure LUID_AND_ATTRIBUTES
        Public Luid As LUID
        Public Attributes As Integer
    End Structure

    Private Structure TOKEN_PRIVILEGES
        Public PrivilegeCount As UInt32
        <MarshalAs(UnmanagedType.ByValArray)> Public Privileges() As LUID_AND_ATTRIBUTES
    End Structure


    ' ******************************
    ' * Enumerations
    ' ******************************

    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 SECURITY_IMPERSONATION_LEVEL
        SecurityAnonymous = 0
        SecurityIdentification
        SecurityImpersonation
        SecurityDelegation
    End Enum

    Private Enum TOKEN_TYPE
        TokenPrimary = 1
        TokenImpersonation = 2
    End Enum


    ' ******************************
    ' * Constants
    ' ******************************

    Private Const SE_ASSIGNPRIMARYTOKEN_NAME As String = "SeAssignPrimaryTokenPrivilege"
    Private Const SE_INCREASE_QUOTA_NAME As String = "SeIncreaseQuotaPrivilege"
    Private Const SE_TCB_NAME As String = "SeTcbPrivilege"
    Private Const SE_PRIVILEGE_ENABLED As UInt32 = &H2


    ' ******************************
    ' * Safe Token Handle Class
    ' ******************************

    Private Class SafeTokenHandle
        Inherits SafeHandleZeroOrMinusOneIsInvalid

        Private Sub New()
            MyBase.New(True)
        End Sub

        Friend Sub New(ByVal handle As IntPtr)
            MyBase.New(True)
            MyBase.SetHandle(handle)
        End Sub

        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
        Friend Shared Function CloseHandle(ByVal handle As IntPtr) As Boolean
        End Function

        Protected Overrides Function ReleaseHandle() As Boolean
            Return SafeTokenHandle.CloseHandle(MyBase.handle)
        End Function

    End Class


    ' ******************************
    ' * Increase Privileges Function
    ' ******************************

    Public Shared Function IncreasePrivileges() As Boolean

        ' Local variables
        Dim hToken As SafeTokenHandle = Nothing
        Dim luid As LUID
        Dim NewState As TOKEN_PRIVILEGES
        NewState.PrivilegeCount = 1
        ReDim NewState.Privileges(0)

        ' Get current process token
        If OpenProcessToken(Diagnostics.Process.GetCurrentProcess.Handle, TokenAccessLevels.MaximumAllowed, hToken) = False Then

            ' Write debug
            WriteEvent("Error: Windows API OpenProcessToken function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Lookup SeIncreaseQuotaPrivilege
        If Not LookupPrivilegeValue(Nothing, SE_INCREASE_QUOTA_NAME, luid) Then

            ' Write debug
            WriteEvent("Error: Windows API LookupPrivilegeValue function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Enable SeIncreaseQuotaPrivilege
        NewState.Privileges(0).Luid = luid
        NewState.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED

        ' Adjust the token privileges
        If Not AdjustTokenPrivileges(hToken, False, NewState, Marshal.SizeOf(NewState), Nothing, Nothing) Then

            ' Write debug
            WriteEvent("Error: Windows API AdjustTokenPrivileges function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Lookup SeAssignPrimaryTokenPrivilege
        If Not LookupPrivilegeValue(Nothing, SE_ASSIGNPRIMARYTOKEN_NAME, luid) Then

            ' Write debug
            WriteEvent("Error: Windows API LookupPrivilegeValue function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Enable SeAssignPrimaryTokenPrivilege
        NewState.Privileges(0).Luid = luid
        NewState.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED

        ' Adjust the token privileges
        If Not AdjustTokenPrivileges(hToken, False, NewState, Marshal.SizeOf(NewState), Nothing, Nothing) Then

            ' Write debug
            WriteEvent("Error: Windows API AdjustTokenPrivileges function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Lookup SeTcbPrivilege
        If Not LookupPrivilegeValue(Nothing, SE_TCB_NAME, luid) Then

            ' Write debug
            WriteEvent("Error: Windows API LookupPrivilegeValue function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Enable SeTcbPrivilege
        NewState.Privileges(0).Luid = luid
        NewState.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED

        ' Adjust the token privileges
        If Not AdjustTokenPrivileges(hToken, False, NewState, Marshal.SizeOf(NewState), Nothing, Nothing) Then

            ' Write debug
            WriteEvent("Error: Windows API AdjustTokenPrivileges function returns an error." + Environment.NewLine +
                       "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            ' Return
            Return False

        End If

        ' Return
        Return True

    End Function


    ' ******************************
    ' * Launch Process Sub
    ' ******************************

    Public Shared Sub LaunchProcess(ByVal CmdLine As String, ByVal args As String())

        ' Local variables
        Dim Arguments As String = ""
        Dim ExplorerProcesses As Process()
        Dim hToken As SafeTokenHandle = Nothing
        Dim principle As WindowsIdentity
        Dim phNewToken As SafeTokenHandle = Nothing
        Dim si As STARTUPINFO
        Dim pi As PROCESS_INFORMATION

        ' Process arguments
        For Each arg As String In args

            ' Build argument string
            Arguments += " " + arg

        Next

        ' Increase Privileges
        If IncreasePrivileges() = False Then

            ' Write debug
            WriteEvent("Warning: Failed to increase current process privileges.", EventLogEntryType.Warning)

        End If

        ' Get all explorer.exe IDs
        ExplorerProcesses = Process.GetProcessesByName("explorer")

        ' Verify explorers were found
        If ExplorerProcesses.Length = 0 Then

            ' Write debug
            WriteEvent("Warning: No explorer.exe processes found.", EventLogEntryType.Warning)

            ' Return
            Exit Sub

        End If

        ' Iterate each explorer.exe process
        For Each hProcess As Process In ExplorerProcesses

            ' Get the user token handle
            If OpenProcessToken(hProcess.Handle, TokenAccessLevels.MaximumAllowed, hToken) = False Then

                ' Write debug
                WriteEvent("Error: Windows API OpenProcessToken function returns an error." + Environment.NewLine +
                           "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

                ' Iterate the next process
                Continue For

            End If

            ' Get the windows identity
            principle = New WindowsIdentity(hToken.DangerousGetHandle)

            ' Get a primary token
            If Not DuplicateTokenEx(hToken.DangerousGetHandle,
                TokenAccessLevels.MaximumAllowed,
                Nothing,
                SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
                TOKEN_TYPE.TokenPrimary,
                phNewToken) Then

                ' Write debug
                WriteEvent("Error: Windows API DuplicateTokenEx function returns an error." + Environment.NewLine +
                           "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

                ' Iterate the next process
                Continue For

            End If

            ' Initialize process and startup info
            pi = New PROCESS_INFORMATION
            si = New STARTUPINFO
            si.cb = Marshal.SizeOf(si)
            si.lpDesktop = Nothing

            ' Launch the process in the client's logon session
            If Not CreateProcessAsUser(phNewToken,
                Nothing,
                CmdLine + Arguments,
                Nothing,
                Nothing,
                False,
                CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT,
                Nothing,
                Nothing,
                si,
                pi) Then

                ' Write debug
                WriteEvent("Error: Windows API CreateProcessAsUser function returns an error." + Environment.NewLine +
                           "Windows API error code: " + Marshal.GetLastWin32Error.ToString, EventLogEntryType.Error)

            Else

                ' Write debug
                WriteEvent("Created new user process: " + Environment.NewLine +
                           "User:     " + principle.Name + Environment.NewLine +
                           "Process:  " + CmdLine + Arguments + Environment.NewLine +
                           "PID:      " + pi.dwProcessId.ToString, EventLogEntryType.Information)

            End If

            ' Free resources
            hToken.Close()
            hToken = Nothing
            phNewToken.Close()
            phNewToken = Nothing
            principle = Nothing
            pi = Nothing
            si = Nothing

        Next

    End Sub


    ' ******************************
    ' * Write Event Log Sub
    ' ******************************

    Public Shared Sub WriteEvent(EventMessage As String, EntryType As EventLogEntryType)

        ' Check if event source exists
        If Not EventLog.SourceExists("WinOffline Launch Service") Then

            ' Create the event source
            EventLog.CreateEventSource("WinOffline Launch Service", "System")

        End If

        ' Write the message
        EventLog.WriteEntry("WinOffline Launch Service", EventMessage, EntryType)

    End Sub

End Class

実装:

上記のように、2番目のプロジェクトからサービスの実行可能ファイルを取得し、それを最初のプロジェクトの「既存のアイテム」としてVisualStudioに追加しました。次に、「ビルドアクション」を変更して、サービス実行可能ファイルを最初のアプリケーション実行可能ファイルに埋め込みました。

最初のアプリケーションがターゲットで実行されると、コードを実行して、埋め込まれた実行可能ファイルをターゲットマシンに抽出します。あなたはそのコードのためにグーグルすることができます、それはかなり単純です。

組み込みサービスの実行可能ファイルがローカルシステム上のパスに抽出された後、実行する4つの「sc」コマンドを次に示します。

sc create <ServiceName> binpath= <Full Path to Service Executable> start= demand
sc start <ServiceName> <Full Path to App to Launch for all Users> <Parameters>
sc stop <ServiceName>
sc delete <ServiceName>

注:最初のscコマンドでは、等号の後にスペースを入れることを忘れないでください。

scコマンドの使用は、installutil.exeを使用したり、MSIにサービスをパッケージ化してインストールするためのセットアッププロジェクトを作成したりするよりもはるかに簡単です。次のコマンドに進む前に、各scコマンドが戻るのを待っていることを確認してください。

最後の注意:

ポジティブな洞察とフィードバックを提供してくれたすべての人に、すべてのあなたの助けに感謝します。私が喜んでコードを投稿するのは、あなた自身のような善良な人々のためです。これを行うことができなかった、またはユーザーのデスクトップに侵入して何かを実行することはどういうわけか悪意があると主張しようとしたすべての人にとって、私はあなたが箱から出して考え始めることを丁寧に勧めます。あなたが私のチームで働いてほしくない!

何かが悪意のある人や危険な人に悪意のある、または危険な影響を与える可能性があるという理由だけで、それはまったく達成されるべきではないという考え方で人生を歩むのは滑りやすい坂道です。あなたの悪臭を放つ思考は、宇宙で美しいものすべてに反しています。

于 2013-08-24T17:27:47.863 に答える