如何以Windows服务的不同用户身份运行进程

如何以Windows服务的不同用户身份运行进程

问题描述:

我已创建一个在用户登录前已启动的服务。该服务以“网络服务”用户身份运行。它不时需要运行一个更新过程,该过程需要作为域用户运行。必须考虑在更新过程开始时没有用户登录的情况。由于密码规则(需要不时更改),因此无法以域用户身份运行服务。 当需要运行更新过程时,域用户的密码将从另一台机器获取。 我的问题是,该服务能够使用CreateProcessWithLogonW以域用户身份创建该进程,但一旦该进程启动,它立即销毁。返回值是0,我没有得到标准输出,也没有标准错误。我得到的唯一提示是错误代码为0xc0000142的事件日志中的条目。 我也尝试了我在网上找到的其他几种解决方案。但是没有解决方案。例如我也尝试过LogonUser - > Adjust privileges - > CreateProcessAsUser。 操作系统是Windows 7. 更新程序只是一个控制台应用程序。我只需要返回代码,stdout和stderr。当进程启动时,不应该弹出窗口。 任何人都可以帮助我解决问题吗?最好的将是Python中的一个例子。提前致谢。 最好的问候, 马丁如何以Windows服务的不同用户身份运行进程

更新: 目前,我结束了与下面的代码:

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) 

但它不工作。该过程是由所需的用户创建的,但是当它启动时会立即销毁。返回码为0. stdout上没有输出,也没有stderr。 GetLastError也返回0.事件查看器中未显示任何条目。

+0

你用Python创建或C++为您服务:如果用户会话或会话0

这里执行的是代码不要紧?用Python我建议看一下“runas”工具。用C++ - CreateProcessAsUser。 –

+0

首先,您应该调查[托管服务帐户](https://technet.microsoft.com/en-us/library/hh831451(v = ws.11).aspx),这可能无需执行此操作通过允许您以域用户身份运行服务。 –

+0

@HarryJohnston,'CreateProcessWithLogonW'和'CreateProcessWithTokenW'默认处理参数中的桌面信息给调用者,例如, “服务0x0-3e7 $ \ DEFAULT”。 OTOH,'CreateProcessAsUser'可以在不更新安全描述符的情况下工作。它默认将桌面信息留空。在[window-station连接规则](https://msdn.microsoft.com/en-us/library/ms684859)之后,如果子进程没有继承父进程的WindowStation,则系统将创建一个名为登录会话ID。所以我们需要通过'STARTUPINFOEX'控制继承。 – eryksun

最后我发现了如何做到这一点。这是相当复杂的,我不得不合并来自几个例子(其中一些在C)的代码。当以网络服务系统用户执行时,下面的示例工作。

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))