1
0

More than 3 years have passed since last update.

CreateProcessAsUser を用いて Go で作成したサービスからリンクドトークンでプロセスを起動する

Last updated at Posted at 2020-04-30

blono/win にまたいくつかの API を追加したので、サービスからのプロセスの起動がコーディングしやすくなった

main.go
func GetActiveSession() uint32 {
    var si *win.WTS_SESSION_INFO
    var count uint32

    if win.WTSEnumerateSessions(win.WTS_CURRENT_SERVER_HANDLE, 0, 1, &si, &count) != 0 {
        defer win.WTSFreeMemory(uintptr(unsafe.Pointer(si)))

        size := int(unsafe.Sizeof(win.WTS_SESSION_INFO{}))

        for i := 0; i < int(count); i++ {
            sipi := unsafe.Pointer(uintptr(unsafe.Pointer(si)) + uintptr(i*size))
            sii := *(*win.WTS_SESSION_INFO)(sipi)

            if sii.State == win.WTSActive {
                return sii.SessionId
            }
        }
    }

    return 0
}

func CreateProcessAsUser(app, param string, token win.HANDLE, creationFlags uint32, env uintptr, ppi *win.PROCESS_INFORMATION) win.BOOL {
    var pi win.PROCESS_INFORMATION
    var si win.STARTUPINFO
    var arg string

    si.Cb = uint32(unsafe.Sizeof(si))
    si.LpDesktop = NewUTF16(`winsta0\default`)

    if param == "" {
        arg = app
    } else {
        arg = app + " " + param
    }

    result := win.CreateProcessAsUser(token, nil, &arg, nil, nil, win.FALSE, creationFlags, env, nil, &si, &pi)
    if ppi == nil {
        win.CloseHandle(pi.HThread)
        win.CloseHandle(pi.HProcess)
    } else {
        *ppi = pi
    }

    return result
}

func CreateProcessAsActiveUser(app, param string, ppi *win.PROCESS_INFORMATION) win.BOOL {
    activeSession := GetActiveSession()
    var userToken win.HANDLE

    if win.WTSQueryUserToken(activeSession, &userToken) != 0 {
        defer win.CloseHandle(userToken)

        var linkedToken win.HANDLE
        var size uint32 = uint32(unsafe.Sizeof(linkedToken))

        if win.GetTokenInformation(userToken, win.TokenLinkedToken, uintptr(unsafe.Pointer(&linkedToken)), size, &size) != 0 {
            defer win.CloseHandle(linkedToken)

            var duplicatedToken win.HANDLE

            if win.DuplicateTokenEx(linkedToken, win.MAXIMUM_ALLOWED, nil, win.SecurityImpersonation, win.TokenPrimary, &duplicatedToken) != 0 {
                var creationFlags uint32 = win.CREATE_NEW_CONSOLE | win.NORMAL_PRIORITY_CLASS
                var env uintptr

                if win.CreateEnvironmentBlock(&env, duplicatedToken, win.TRUE) != 0 {
                    creationFlags |= win.CREATE_UNICODE_ENVIRONMENT
                    defer win.DestroyEnvironmentBlock(env)
                }

                return CreateProcessAsUser(app, param, duplicatedToken, creationFlags, env, ppi)
            }
        }
    }

    return win.FALSE
}

Go で Windows Service を作成する で作成した Windows サービスから呼び出すことで動作を確認可能。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0