PsExec与Go服务运行系统进程的Winlogon桌面权限差异排查
系统进程运行Electron应用的两种方式差异排查
我正在开发一款Electron应用,该应用的子Node.js进程通过ffmpeg工具捕获桌面流。为捕获winlogon流,子进程中使用setThreadDesktop API将线程桌面切换至winlogon。
使用PsExec工具执行命令 PsExec64.exe -sid <path-to-exe> 以系统进程运行该Electron应用时,一切正常。
但通过Go语言编写的Windows服务(依赖golang.org/x/sys/windows包)按以下程序步骤以系统进程运行应用时,无法正常工作:子进程中的ffmpeg工具退出并返回错误(5),即拒绝访问winlogon桌面。
获取token的代码
wlPid, e := processID("winlogon.exe", uint32(sessionId)) if e != nil { log.Printf("Error in getting winlogon pid: %s", e.Error()) return 0xFFFFFFFF, e } hProcess, eo := windows.OpenProcess(windows.MAXIMUM_ALLOWED, true, wlPid) if eo != nil { log.Printf("Error opening process: %s", eo.Error()) return 0xFFFFFFFF, eo } token := windows.Token(impersonationToken) ope := windows.OpenProcessToken(hProcess, windows.TOKEN_ALL_ACCESS, &token) if ope != nil { log.Printf("OpenProcessToken failed %s", ope.Error()) return 0xFFFFFFFF, ope } systemSid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid) // Create the trustee to add to an ACE trustee := windows.TRUSTEE{ MultipleTrustee: nil, MultipleTrusteeOperation: windows.NO_MULTIPLE_TRUSTEE, TrusteeForm: windows.TRUSTEE_IS_SID, TrusteeType: windows.TRUSTEE_IS_USER, TrusteeValue: windows.TrusteeValueFromSID(systemSid), } ace := windows.EXPLICIT_ACCESS{ // AccessPermissions: windows.ACCESS_MASK(windows.READ_CONTROL), // WINSTA_CREATEDESKTOP | WINSTA_READSCREEN | WINSTA_ACCESSCLIPBOARD | WINSTA_WRITEATTRIBUTES | WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_READATTRIBUTES | // AccessMode: windows.SET_ACCESS, AccessPermissions: windows.STANDARD_RIGHTS_ALL, AccessMode: windows.GRANT_ACCESS, Inheritance: windows.INHERIT_ONLY, Trustee: trustee, } // Add the new ACE for the token user to the existing security descriptor for the window station sd, err := windows.BuildSecurityDescriptor(nil, nil, []windows.EXPLICIT_ACCESS{ace}, nil, nil) if err != nil { return 0xFFFFFFFF, fmt.Errorf("there was an error calling windows.BuildSecurityDescriptor for the station: %s", err) } if returnCode, _, err := procDuplicateTokenEx.Call(uintptr(token), windows.MAXIMUM_ALLOWED, uintptr(unsafe.Pointer(&sd)), uintptr(SecurityImpersonation), uintptr(TokenPrimary), uintptr(unsafe.Pointer(&userToken))); returnCode == 0 { // log.Printf("Dup Error: %s", err.Error()) return 0xFFFFFFFF, fmt.Errorf("call native DuplicateTokenEx: %s", err) } h := windows.Handle(token) if err := windows.CloseHandle(h); err != nil { // log.Printf("Close Error: %s", err.Error()) return 0xFFFFFFFF, fmt.Errorf("close windows handle used for token duplication: %s", err) } return userToken, nil
使用userToken创建进程的代码
if returnCode, _, err := procCreateEnvironmentBlock.Call(uintptr(unsafe.Pointer(&envInfo)), uintptr(userToken), 0); returnCode == 0 { return fmt.Errorf("create environment details for process: %s", err) } creationFlags := windows.CREATE_UNICODE_ENVIRONMENT | windows.CREATE_NEW_CONSOLE startupInfo.ShowWindow = windows.SW_SHOW startupInfo.Desktop = windows.StringToUTF16Ptr("winsta0\\default") if len(cmdLine) > 0 { commandLine = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cmdLine))) } if len(workDir) > 0 { workingDir = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(workDir))) } log.Printf("Calling Create Process as user") log.Println(userToken) if returnCode, _, err := procCreateProcessAsUser.Call( uintptr(userToken), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(appPath))), commandLine, 0, 0, 0, uintptr(creationFlags), uintptr(envInfo), workingDir, uintptr(unsafe.Pointer(&startupInfo)), uintptr(unsafe.Pointer(&processInfo)), ); returnCode == 0 { return fmt.Errorf("create process as user: %s", err) }
恳请Windows技术专家帮忙分析这两种以系统进程运行应用的方式存在哪些差异?
内容的提问来源于stack exchange,提问作者Hiren patel
相关产品推荐
相关产品推荐

