我已经创build了一个在用户login之前已经启动的服务。该服务以“networking服务”用户身份运行。 它不时需要运行一个更新过程,这个过程需要作为一个域用户运行。 必须考虑在更新过程开始时没有用户login的情况。 由于密码规则(需要不时更改),不能以域用户的身份运行服务。 需要运行更新过程时,域用户的密码是从另一台机器获取的。 我的问题是,该服务能够创build进程作为域用户与CreateProcessWithLogonW但一旦进程开始立即销毁。 返回值是0,我没有得到stdout和没有stderr。 我得到的唯一提示是错误代码为0xc0000142的事件日志中的条目。 我也尝试了我在网上find的其他几个解决scheme。 但是没有解决scheme。 例如我也尝试过LogonUser – > Adjust privileges – > CreateProcessAsUser。 操作系统是Windows 7.更新程序只是一个控制台应用程序。 我只需要返回代码,stdout和stderr。 当进程启动时,不应该popup窗口。 任何人都可以帮助我一个工作解决scheme? 最好的将是Python中的一个例子。 提前致谢。 最好的问候,马丁
更新:目前我结束了以下代码:
import os import sys import types import subprocess import ctypes from ctypes import wintypes import win32con import win32event import win32api import win32security kernel32 = ctypes.WinDLL('kernel32', use_last_error = True) advapi32 = ctypes.WinDLL('advapi32', use_last_error = True) ERROR_INVALID_HANDLE = 0x0006 INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value INVALID_DWORD_VALUE = wintypes.DWORD(-1).value DEBUG_PROCESS = 0x00000001 DEBUG_ONLY_THIS_PROCESS = 0x00000002 CREATE_SUSPENDED = 0x00000004 DETACHED_PROCESS = 0x00000008 CREATE_NEW_CONSOLE = 0x00000010 CREATE_NEW_PROCESS_GROUP = 0x00000200 CREATE_UNICODE_ENVIRONMENT = 0x00000400 CREATE_SEPARATE_WOW_VDM = 0x00000800 CREATE_SHARED_WOW_VDM = 0x00001000 INHERIT_PARENT_AFFINITY = 0x00010000 CREATE_PROTECTED_PROCESS = 0x00040000 EXTENDED_STARTUPINFO_PRESENT = 0x00080000 CREATE_BREAKAWAY_FROM_JOB = 0x01000000 CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000 CREATE_DEFAULT_ERROR_MODE = 0x04000000 CREATE_NO_WINDOW = 0x08000000 STARTF_USESHOWWINDOW = 0x00000001 STARTF_USESIZE = 0x00000002 STARTF_USEPOSITION = 0x00000004 STARTF_USECOUNTCHARS = 0x00000008 STARTF_USEFILLATTRIBUTE = 0x00000010 STARTF_RUNFULLSCREEN = 0x00000020 STARTF_FORCEONFEEDBACK = 0x00000040 STARTF_FORCEOFFFEEDBACK = 0x00000080 STARTF_USESTDHANDLES = 0x00000100 STARTF_USEHOTKEY = 0x00000200 STARTF_TITLEISLINKNAME = 0x00000800 STARTF_TITLEISAPPID = 0x00001000 STARTF_PREVENTPINNING = 0x00002000 SW_HIDE = 0 SW_SHOWNORMAL = 1 SW_SHOWMINIMIZED = 2 SW_SHOWMAXIMIZED = 3 SW_SHOWNOACTIVATE = 4 SW_SHOW = 5 SW_MINIMIZE = 6 SW_SHOWMINNOACTIVE = 7 SW_SHOWNA = 8 SW_RESTORE = 9 SW_SHOWDEFAULT = 10 # ~STARTUPINFO SW_FORCEMINIMIZE = 11 LOGON_WITH_PROFILE = 0x00000001 LOGON_NETCREDENTIALS_ONLY = 0x00000002 STD_INPUT_HANDLE = wintypes.DWORD(-10).value STD_OUTPUT_HANDLE = wintypes.DWORD(-11).value STD_ERROR_HANDLE = wintypes.DWORD(-12).value SYNCHRONIZE = 0x00100000 WAIT_OBJECT_0 = win32event.WAIT_OBJECT_0 WAIT_OBJECT_1 = WAIT_OBJECT_0 + 1 class HANDLE(wintypes.HANDLE): __slots__ = ( 'closed', ) def __int__(self): return self.value or 0 def Detach(self): if not getattr(self, 'closed', False): self.closed = True value = int(self) self.value = None return value raise ValueError("already closed") def Close(self, CloseHandle=kernel32.CloseHandle): if self and not getattr(self, 'closed', False): CloseHandle(self.Detach()) __del__ = Close def __repr__(self): return "%s(%d)" % (self.__class__.__name__, int(self)) class PROCESS_INFORMATION(ctypes.Structure): """https://msdn.microsoft.com/en-us/library/ms684873""" __slots__ = '_cached_hProcess', '_cached_hThread' _fields_ = (('_hProcess', HANDLE), ('_hThread', HANDLE), ('dwProcessId', wintypes.DWORD), ('dwThreadId', wintypes.DWORD)) @property def hProcess(self): if not hasattr(self, '_cached_hProcess'): self._cached_hProcess = self._hProcess return self._cached_hProcess @property def hThread(self): if not hasattr(self, '_cached_hThread'): self._cached_hThread = self._hThread return self._cached_hThread def __del__(self): try: self.hProcess.Close() finally: self.hThread.Close() LPPROCESS_INFORMATION = ctypes.POINTER(PROCESS_INFORMATION) LPBYTE = ctypes.POINTER(wintypes.BYTE) class STARTUPINFO(ctypes.Structure): """https://msdn.microsoft.com/en-us/library/ms686331""" _fields_ = (('cb', wintypes.DWORD), ('lpReserved', wintypes.LPWSTR), ('lpDesktop', wintypes.LPWSTR), ('lpTitle', wintypes.LPWSTR), ('dwX', wintypes.DWORD), ('dwY', wintypes.DWORD), ('dwXSize', wintypes.DWORD), ('dwYSize', wintypes.DWORD), ('dwXCountChars', wintypes.DWORD), ('dwYCountChars', wintypes.DWORD), ('dwFillAttribute', wintypes.DWORD), ('dwFlags', wintypes.DWORD), ('wShowWindow', wintypes.WORD), ('cbReserved2', wintypes.WORD), ('lpReserved2', LPBYTE), ('hStdInput', wintypes.HANDLE), ('hStdOutput', wintypes.HANDLE), ('hStdError', wintypes.HANDLE)) def __init__(self, **kwds): self.cb = ctypes.sizeof(self) super(STARTUPINFO, self).__init__(**kwds) class PROC_THREAD_ATTRIBUTE_LIST(ctypes.Structure): pass PPROC_THREAD_ATTRIBUTE_LIST = ctypes.POINTER(PROC_THREAD_ATTRIBUTE_LIST) class STARTUPINFOEX(STARTUPINFO): _fields_ = (('lpAttributeList', PPROC_THREAD_ATTRIBUTE_LIST),) LPSTARTUPINFO = ctypes.POINTER(STARTUPINFO) LPSTARTUPINFOEX = ctypes.POINTER(STARTUPINFOEX) class SECURITY_ATTRIBUTES(ctypes.Structure): _fields_ = (('nLength', wintypes.DWORD), ('lpSecurityDescriptor', wintypes.LPVOID), ('bInheritHandle', wintypes.BOOL)) def __init__(self, **kwds): self.nLength = ctypes.sizeof(self) super(SECURITY_ATTRIBUTES, self).__init__(**kwds) LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES) class HANDLE_IHV(HANDLE): pass class DWORD_IDV(wintypes.DWORD): pass def _check_ihv(result, func, args): if result.value == INVALID_HANDLE_VALUE: raise ctypes.WinError(ctypes.get_last_error()) return result.value def _check_idv(result, func, args): if result.value == INVALID_DWORD_VALUE: raise ctypes.WinError(ctypes.get_last_error()) return result.value def _check_bool(result, func, args): if not result: raise ctypes.WinError(ctypes.get_last_error()) return args def WIN(func, restype, *argtypes): func.restype = restype func.argtypes = argtypes if issubclass(restype, HANDLE_IHV): func.errcheck = _check_ihv elif issubclass(restype, DWORD_IDV): func.errcheck = _check_idv else: func.errcheck = _check_bool # https://msdn.microsoft.com/en-us/library/ms724211 WIN(kernel32.CloseHandle, wintypes.BOOL, wintypes.HANDLE,) # _In_ HANDLE hObject # https://msdn.microsoft.com/en-us/library/ms685086 WIN(kernel32.ResumeThread, DWORD_IDV, wintypes.HANDLE,) # _In_ hThread # https://msdn.microsoft.com/en-us/library/ms682425 WIN(kernel32.CreateProcessW, wintypes.BOOL, wintypes.LPCWSTR, # _In_opt_ lpApplicationName wintypes.LPWSTR, # _Inout_opt_ lpCommandLine LPSECURITY_ATTRIBUTES, # _In_opt_ lpProcessAttributes LPSECURITY_ATTRIBUTES, # _In_opt_ lpThreadAttributes wintypes.BOOL, # _In_ bInheritHandles wintypes.DWORD, # _In_ dwCreationFlags wintypes.LPCWSTR, # _In_opt_ lpEnvironment wintypes.LPCWSTR, # _In_opt_ lpCurrentDirectory LPSTARTUPINFO, # _In_ lpStartupInfo LPPROCESS_INFORMATION) # _Out_ lpProcessInformation # https://msdn.microsoft.com/en-us/library/ms682429 WIN(advapi32.CreateProcessAsUserW, wintypes.BOOL, wintypes.HANDLE, # _In_opt_ hToken wintypes.LPCWSTR, # _In_opt_ lpApplicationName wintypes.LPWSTR, # _Inout_opt_ lpCommandLine LPSECURITY_ATTRIBUTES, # _In_opt_ lpProcessAttributes LPSECURITY_ATTRIBUTES, # _In_opt_ lpThreadAttributes wintypes.BOOL, # _In_ bInheritHandles wintypes.DWORD, # _In_ dwCreationFlags wintypes.LPCWSTR, # _In_opt_ lpEnvironment wintypes.LPCWSTR, # _In_opt_ lpCurrentDirectory LPSTARTUPINFO, # _In_ lpStartupInfo LPPROCESS_INFORMATION) # _Out_ lpProcessInformation # https://msdn.microsoft.com/en-us/library/ms682434 WIN(advapi32.CreateProcessWithTokenW, wintypes.BOOL, wintypes.HANDLE, # _In_ hToken wintypes.DWORD, # _In_ dwLogonFlags wintypes.LPCWSTR, # _In_opt_ lpApplicationName wintypes.LPWSTR, # _Inout_opt_ lpCommandLine wintypes.DWORD, # _In_ dwCreationFlags wintypes.LPCWSTR, # _In_opt_ lpEnvironment wintypes.LPCWSTR, # _In_opt_ lpCurrentDirectory LPSTARTUPINFO, # _In_ lpStartupInfo LPPROCESS_INFORMATION) # _Out_ lpProcessInformation # https://msdn.microsoft.com/en-us/library/ms682431 WIN(advapi32.CreateProcessWithLogonW, wintypes.BOOL, wintypes.LPCWSTR, # _In_ lpUsername wintypes.LPCWSTR, # _In_opt_ lpDomain wintypes.LPCWSTR, # _In_ lpPassword wintypes.DWORD, # _In_ dwLogonFlags wintypes.LPCWSTR, # _In_opt_ lpApplicationName wintypes.LPWSTR, # _Inout_opt_ lpCommandLine wintypes.DWORD, # _In_ dwCreationFlags wintypes.LPCWSTR, # _In_opt_ lpEnvironment wintypes.LPCWSTR, # _In_opt_ lpCurrentDirectory LPSTARTUPINFO, # _In_ lpStartupInfo LPPROCESS_INFORMATION) # _Out_ lpProcessInformation CREATION_TYPE_NORMAL = 0 CREATION_TYPE_LOGON = 1 CREATION_TYPE_TOKEN = 2 CREATION_TYPE_USER = 3 class CREATIONINFO(object): __slots__ = ( 'dwCreationType', 'lpApplicationName', 'lpCommandLine', 'bUseShell', 'lpProcessAttributes', 'lpThreadAttributes', 'bInheritHandles', 'dwCreationFlags', 'lpEnvironment', 'lpCurrentDirectory', 'hToken', 'lpUsername', 'lpDomain', 'lpPassword', 'dwLogonFlags' ) def __init__(self, dwCreationType = CREATION_TYPE_NORMAL, lpApplicationName = None, lpCommandLine = None, bUseShell = False, lpProcessAttributes = None, lpThreadAttributes = None, bInheritHandles = False, dwCreationFlags = 0, lpEnvironment = None, lpCurrentDirectory = None, hToken = None, dwLogonFlags = 0, lpUsername = None, lpDomain = None, lpPassword = None): self.dwCreationType = dwCreationType self.lpApplicationName = lpApplicationName self.lpCommandLine = lpCommandLine self.bUseShell = bUseShell self.lpProcessAttributes = lpProcessAttributes self.lpThreadAttributes = lpThreadAttributes self.bInheritHandles = bInheritHandles self.dwCreationFlags = dwCreationFlags self.lpEnvironment = lpEnvironment self.lpCurrentDirectory = lpCurrentDirectory self.hToken = hToken self.lpUsername = lpUsername self.lpDomain = lpDomain self.lpPassword = lpPassword self.dwLogonFlags = dwLogonFlags def create_environment(environ): if environ is None: return None items = ['%s=%s' % (k, environ[k]) for k in sorted(environ)] buf = '\x00'.join(items) length = len(buf) + 2 if buf else 1 return ctypes.create_unicode_buffer(buf, length) def create_process(commandline = None, creationinfo = None, startupinfo = None): if creationinfo is None: creationinfo = CREATIONINFO() if startupinfo is None: startupinfo = STARTUPINFO() elif isinstance(startupinfo, subprocess.STARTUPINFO): startupinfo = STARTUPINFO(dwFlags = startupinfo.dwFlags, hStdInput = startupinfo.hStdInput, hStdOutput = startupinfo.hStdOutput, hStdError = startupinfo.hStdError, wShowWindow = startupinfo.wShowWindow) si, ci, pi = startupinfo, creationinfo, PROCESS_INFORMATION() if commandline is None: commandline = ci.lpCommandLine if not commandline is None: if ci.bUseShell: si.dwFlags |= STARTF_USESHOWWINDOW si.wShowWindow = SW_HIDE comspec = os.environ.get("ComSpec", os.path.join(os.environ["SystemRoot"], "System32", "cmd.exe")) commandline = '"{}" /c "{}"'.format(comspec, commandline) commandline = ctypes.create_unicode_buffer(commandline) dwCreationFlags = ci.dwCreationFlags | CREATE_UNICODE_ENVIRONMENT lpEnvironment = create_environment(ci.lpEnvironment) if ((dwCreationFlags & DETACHED_PROCESS) and ((dwCreationFlags & CREATE_NEW_CONSOLE) or (ci.dwCreationType == CREATION_TYPE_LOGON) or (ci.dwCreationType == CREATION_TYPE_TOKEN))): raise RuntimeError('DETACHED_PROCESS is incompatible with CREATE_NEW_CONSOLE, which is implied for the logon and token creation types') if ci.dwCreationType == CREATION_TYPE_NORMAL: if not kernel32.CreateProcessW(ci.lpApplicationName, commandline, ci.lpProcessAttributes, ci.lpThreadAttributes, ci.bInheritHandles, dwCreationFlags, lpEnvironment, ci.lpCurrentDirectory, ctypes.byref(si), ctypes.byref(pi)): raise RuntimeError("CreateProcessW failed with error code %d!" % win32api.GetLastError()) elif ci.dwCreationType == CREATION_TYPE_LOGON: if not advapi32.CreateProcessWithLogonW(ci.lpUsername, ci.lpDomain, ci.lpPassword, ci.dwLogonFlags, ci.lpApplicationName, commandline, dwCreationFlags, lpEnvironment, ci.lpCurrentDirectory, ctypes.byref(si), ctypes.byref(pi)): raise RuntimeError("CreateProcessWithLogonW failed with error code %d!" % win32api.GetLastError()) elif ci.dwCreationType == CREATION_TYPE_TOKEN: if not advapi32.CreateProcessWithTokenW(ci.hToken, ci.dwLogonFlags, ci.lpApplicationName, commandline, dwCreationFlags, lpEnvironment, ci.lpCurrentDirectory, ctypes.byref(si), ctypes.byref(pi)): raise RuntimeError("CreateProcessWithTokenW failed with error code %d!" % win32api.GetLastError()) elif ci.dwCreationType == CREATION_TYPE_USER: if not advapi32.CreateProcessAsUserW(ci.hToken, ci.lpApplicationName, commandline, ci.lpProcessAttributes, ci.lpThreadAttributes, ci.bInheritHandles, dwCreationFlags, lpEnvironment, ci.lpCurrentDirectory, ctypes.byref(si), ctypes.byref(pi)): raise RuntimeError("CreateProcessAsUserW failed with error code %d!" % win32api.GetLastError()) else: raise ValueError('invalid process creation type') return pi def LogonUser(domain, user, password, bNetwork = False): return win32security.LogonUser(user, domain, password, win32con.LOGON32_LOGON_NETWORK if bNetwork else win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT) def AdjustPriv(priv, bEnable = True, prc = None): if prc is None: prc = win32api.GetCurrentProcess() htoken = win32security.OpenProcessToken(prc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY) id = win32security.LookupPrivilegeValue(None, priv) if bEnable: newPriv = [ ( id, win32security.SE_PRIVILEGE_ENABLED ) ] else: newPriv = [ ( id, 0 ) ] win32security.AdjustTokenPrivileges(htoken, 0, newPriv) rc = win32api.GetLastError() if rc: print("AdjustPriv of %s failed with error code %d!" % (priv, rc)) class Popen(subprocess.Popen): def __init__(self, *args, **kwds): ci = self._creationinfo = kwds.pop('creationinfo', CREATIONINFO()) if kwds.pop('suspended', False): ci.dwCreationFlags |= CREATE_SUSPENDED self._child_started = False super(Popen, self).__init__(*args, **kwds) if sys.version_info[0] == 2: def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, to_close, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (MS Windows version)""" commandline = (args if isinstance(args, types.StringTypes) else subprocess.list2cmdline(args)) self._common_execute_child(executable, commandline, shell, close_fds, creationflags, env, cwd, startupinfo, p2cread, c2pwrite, errwrite, to_close) else: def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session): """Execute program (MS Windows version)""" assert not pass_fds, "pass_fds not supported on Windows." commandline = (args if isinstance(args, str) else subprocess.list2cmdline(args)) self._common_execute_child(executable, commandline, shell, close_fds, creationflags, env, cwd, startupinfo, p2cread, c2pwrite, errwrite) def _common_execute_child(self, executable, commandline, shell, close_fds, creationflags, env, cwd, startupinfo, p2cread, c2pwrite, errwrite, to_close=()): ci = self._creationinfo if not executable is None: ci.lpApplicationName = executable if commandline: ci.lpCommandLine = commandline if shell: ci.bUseShell = shell if not close_fds: ci.bInheritHandles = int(not close_fds) if creationflags: ci.dwCreationFlags |= creationflags if not env is None: ci.lpEnvironment = env if not cwd is None: ci.lpCurrentDirectory = cwd if startupinfo is None: startupinfo = STARTUPINFO() si = self._startupinfo = startupinfo default = None if sys.version_info[0] == 2 else -1 if default not in ( p2cread, c2pwrite, errwrite ): si.dwFlags |= STARTF_USESTDHANDLES si.hStdInput = int(p2cread) si.hStdOutput = int(c2pwrite) si.hStdError = int(errwrite) try: pi = create_process(creationinfo = ci, startupinfo = si) finally: if sys.version_info[0] == 2: if not p2cread is None: p2cread.Close() to_close.remove(p2cread) if not c2pwrite is None: c2pwrite.Close() to_close.remove(c2pwrite) if not errwrite is None: errwrite.Close() to_close.remove(errwrite) else: if p2cread != -1: p2cread.Close() if c2pwrite != -1: c2pwrite.Close() if errwrite != -1: errwrite.Close() if hasattr(self, '_devnull'): os.close(self._devnull) if not ci.dwCreationFlags & CREATE_SUSPENDED: self._child_started = True # Retain the process handle, but close the thread handle if it's no longer needed. self._processinfo = pi self._handle = pi.hProcess.Detach() self.pid = pi.dwProcessId if self._child_started: pi.hThread.Close() self.returncode = ctypes.WinError().winerror def start(self): if self._child_started: raise RuntimeError("processes can only be started once") hThread = self._processinfo.hThread prev_count = kernel32.ResumeThread(hThread) if prev_count > 1: for _ in range(1, prev_count): if kernel32.ResumeThread(hThread) <= 1: break else: raise RuntimeError('cannot start the main thread') # The thread's previous suspend count was 0 or 1, so it should be running now. self._child_started = True hThread.Close() def __del__(self): if not self._child_started: try: if hasattr(self, '_processinfo'): self._processinfo.hThread.Close() finally: if hasattr(self, '_handle'): self.terminate() super(Popen, self).__del__() def KillProcessTree(pid): try: import psutil parent = psutil.Process(pid) for child in parent.children(recursive = True): child.kill() parent.kill() except: pass def RunAs(cmdLine, domain, user, password, bNetwork = False, cwd = None, bUseShell = False, bShow = True, hWaitStop = None, timeout = 0): if cwd is None: cwd = "C:\\Temp" token = LogonUser(domain, user, password, bNetwork) if not token: raise RuntimeError("LogonUser failed with error code %d!" % win32api.GetLastError()) hToken = token.handle if bShow: ci = CREATIONINFO(CREATION_TYPE_USER, hToken = hToken, bUseShell = bUseShell) si = None else: ci = CREATIONINFO(CREATION_TYPE_USER, hToken = hToken, dwCreationFlags = CREATE_NO_WINDOW, bUseShell = bUseShell) si = STARTUPINFO(wShowWindow = SW_HIDE, dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW) AdjustPriv(win32security.SE_TAKE_OWNERSHIP_NAME) AdjustPriv(win32security.SE_TCB_NAME) AdjustPriv(win32security.SE_CHANGE_NOTIFY_NAME) AdjustPriv(win32security.SE_INCREASE_QUOTA_NAME) AdjustPriv(win32security.SE_ASSIGNPRIMARYTOKEN_NAME) AdjustPriv(win32security.SE_CREATE_TOKEN_NAME) win32security.ImpersonateLoggedOnUser(hToken) prc = Popen(cmdLine, creationinfo = ci, startupinfo = si, cwd = cwd, universal_newlines = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, stdin = subprocess.PIPE) hPrc = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, prc.pid) if timeout > 0: timeout *= 1000 else: timeout = win32event.INFINITE if hWaitStop is None: rc = win32event.WaitForSingleObject(hPrc, int(timeout)) else: rc = win32event.WaitForMultipleObjects(( hPrc, hWaitStop ), 0, int(timeout)) win32security.RevertToSelf() if rc != WAIT_OBJECT_0: KillProcessTree(prc.pid) return -1, "", "Timeout running command." if rc == WAIT_OBJECT_1: KillProcessTree(prc.pid) return -2, "", "Command was cancelled." return prc.returncode, prc.stdout.read(), prc.stderr.read() cmdLine = r"C:\Windows\System32\cmd.exe /C timeout /T 5 > nul" rc, stdOut, stdErr = RunAs(cmdLine, "DOMAIN", "USER", pw, timeout = 0, bNetwork = True)
但它不起作用。 这个过程是用所需的用户创build的,但是当它启动的时候会立即销毁。 返回码为0. stdout上没有输出,也没有stderr。 GetLastError也返回0.事件查看器中没有显示任何条目。
最后,我发现如何做到这一点。 这是相当复杂的,我不得不合并几个例子(其中一些在C)的代码。 下面的例子作为网络服务或系统用户执行时工作。 如果在用户会话或会话0中执行,则无关紧要。
这里是代码:
import os import msvcrt import win32security import win32con import win32pipe import win32process import win32api import win32net import win32file import win32event import win32profile import win32service GENERIC_ACCESS = win32con.GENERIC_READ | win32con.GENERIC_WRITE | win32con.GENERIC_EXECUTE | win32con.GENERIC_ALL WINSTA_ALL = (win32con.WINSTA_ACCESSCLIPBOARD | win32con.WINSTA_ACCESSGLOBALATOMS | \ win32con.WINSTA_CREATEDESKTOP | win32con.WINSTA_ENUMDESKTOPS | \ win32con.WINSTA_ENUMERATE | win32con.WINSTA_EXITWINDOWS | \ win32con.WINSTA_READATTRIBUTES | win32con.WINSTA_READSCREEN | \ win32con.WINSTA_WRITEATTRIBUTES | win32con.DELETE | \ win32con.READ_CONTROL | win32con.WRITE_DAC | \ win32con.WRITE_OWNER) DESKTOP_ALL = (win32con.DESKTOP_CREATEMENU | win32con.DESKTOP_CREATEWINDOW | \ win32con.DESKTOP_ENUMERATE | win32con.DESKTOP_HOOKCONTROL | \ win32con.DESKTOP_JOURNALPLAYBACK | win32con.DESKTOP_JOURNALRECORD | \ win32con.DESKTOP_READOBJECTS | win32con.DESKTOP_SWITCHDESKTOP | \ win32con.DESKTOP_WRITEOBJECTS | win32con.DELETE | \ win32con.READ_CONTROL | win32con.WRITE_DAC | \ win32con.WRITE_OWNER) def runAsDomainUser(domainName, userName, password, cmdLine, maxWait): # maxWait = Maximum execution time in ms userGroupSid = win32security.LookupAccountName(domainName, userName)[0] # Login as domain user and create new session userToken = win32security.LogonUser(userName, domainName, password, win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT) rc = win32api.GetLastError() if userToken is None or (rc != 0): return -1, "", "LogonUser failed with RC=%d!" % rc profileDir = win32profile.GetUserProfileDirectory(userToken) tokenUser = win32security.GetTokenInformation(userToken, win32security.TokenUser) # Set access rights to window station hWinSta = win32service.OpenWindowStation("winsta0", False, win32con.READ_CONTROL | win32con.WRITE_DAC ) # Get security descriptor by winsta0-handle secDescWinSta = win32security.GetUserObjectSecurity(hWinSta, win32security.OWNER_SECURITY_INFORMATION | win32security.DACL_SECURITY_INFORMATION | win32con.GROUP_SECURITY_INFORMATION) # Get DACL from security descriptor daclWinSta = secDescWinSta.GetSecurityDescriptorDacl() if daclWinSta is None: # Create DACL if not exisiting daclWinSta = win32security.ACL() # Add ACEs to DACL for specific user group daclWinSta.AddAccessAllowedAce(win32security.ACL_REVISION_DS, GENERIC_ACCESS, userGroupSid) daclWinSta.AddAccessAllowedAce(win32security.ACL_REVISION_DS, WINSTA_ALL, userGroupSid) # Set modified DACL for winsta0 win32security.SetSecurityInfo(hWinSta, win32security.SE_WINDOW_OBJECT, win32security.DACL_SECURITY_INFORMATION, None, None, daclWinSta, None) # Set access rights to desktop hDesktop = win32service.OpenDesktop("default", 0, False, win32con.READ_CONTROL | win32con.WRITE_DAC | win32con.DESKTOP_WRITEOBJECTS | win32con.DESKTOP_READOBJECTS) # Get security descriptor by desktop-handle secDescDesktop = win32security.GetUserObjectSecurity(hDesktop, win32security.OWNER_SECURITY_INFORMATION | win32security.DACL_SECURITY_INFORMATION | win32con.GROUP_SECURITY_INFORMATION ) # Get DACL from security descriptor daclDesktop = secDescDesktop.GetSecurityDescriptorDacl() if daclDesktop is None: #create DACL if not exisiting daclDesktop = win32security.ACL() # Add ACEs to DACL for specific user group daclDesktop.AddAccessAllowedAce(win32security.ACL_REVISION_DS, GENERIC_ACCESS, userGroupSid) daclDesktop.AddAccessAllowedAce(win32security.ACL_REVISION_DS, DESKTOP_ALL, userGroupSid) # Set modified DACL for desktop win32security.SetSecurityInfo(hDesktop, win32security.SE_WINDOW_OBJECT, win32security.DACL_SECURITY_INFORMATION, None, None, daclDesktop, None) # Setup stdin, stdOut and stderr secAttrs = win32security.SECURITY_ATTRIBUTES() secAttrs.bInheritHandle = 1 stdOutRd, stdOutWr = win32pipe.CreatePipe(secAttrs, 0) stdErrRd, stdErrWr = win32pipe.CreatePipe(secAttrs, 0) ppid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(ppid, stdOutRd, ppid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(stdOutRd) stdOutRd = tmp environment = win32profile.CreateEnvironmentBlock(userToken, False) startupInfo = win32process.STARTUPINFO() startupInfo.dwFlags = win32con.STARTF_USESTDHANDLES startupInfo.hStdOutput = stdOutWr startupInfo.hStdError = stdErrWr hPrc = win32process.CreateProcessAsUser( userToken, None, # appName cmdLine, # commandLine None, # processAttributes None, # threadAttributes 1, # bInheritHandles win32process.CREATE_NEW_CONSOLE, # dwCreationFlags environment, # newEnvironment profileDir, # currentDirectory startupInfo)[0] win32file.CloseHandle(stdErrWr) win32file.CloseHandle(stdOutWr) win32security.RevertToSelf() # Wait for process to complete stdOutBuf = os.fdopen(msvcrt.open_osfhandle(stdOutRd, 0), "rb") stdErrBuf = os.fdopen(msvcrt.open_osfhandle(stdErrRd, 0), "rb") win32event.WaitForSingleObject(hPrc, maxWait) stdOut = stdOutBuf.read() stdErr = stdErrBuf.read() rc = win32process.GetExitCodeProcess(hPrc) return rc, str(stdOut, "utf-8"), str(stdErr, "utf-8") if __name__ == "__main__": cmdLine = "C:/Windows/System32/cmd.exe" domainName = input("Domain: ") userName = input("User: ") password = input("Password: ") print(runAsDomainUser(domainName, userName, password, cmdLine, 60000))