• 关于windows上的账号(权限)切换


    这2年一直在做一个运维项目,如果你要在windwos上实现不同进程的权限切换,那么这篇文章会对你有用的!

    最重要的函数CreateProcessWithLogonW

    在UNIX平台上如果你要对一个进程降权有跟多办法,不管是su命令 还是python的os函数都可以很容易的达到目的。
    但是在windwos上要降权就不是很容易了。基本原则就是高级权限切低级权限不需要密码,低级权限使用高级权限需要密码。

    依赖模块代码如下 文件名:win_startup.py

    # -*- coding: utf-8 -*-
    '''
        特定于windwos平台 根据以下内容做适度调整
        https://stackoverflow.com/a/43233332
        http://stackoverflow.com/questions/29566330
    '''
    from __future__ import absolute_import, unicode_literals
    import os
    import collections
    import psutil
    
    import ctypes
    from ctypes import wintypes
    
    
    import win32con
    import win32api
    import win32process
    import win32security
    import win32service
    import ntsecuritycon
    
    from logger import aglogger
    log = aglogger.logger
    
    ntdll = ctypes.WinDLL('ntdll')
    secur32 = ctypes.WinDLL('secur32')
    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
    advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
    userenv = ctypes.WinDLL('userenv', use_last_error=True)
    
    SYSTEM_SID = "S-1-5-18"
    LOCAL_SRV_SID = "S-1-5-19"
    NETWORK_SRV_SID = "S-1-5-19"
    
    LOGON_WITH_PROFILE = 0x00000001
    
    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
    )
    
    MAX_COMPUTER_NAME_LENGTH = 15
    
    SECURITY_LOGON_TYPE = wintypes.ULONG
    Interactive = 2
    Network = 3
    Batch = 4
    Service = 5
    
    LOGON_SUBMIT_TYPE = wintypes.ULONG
    PROFILE_BUFFER_TYPE = wintypes.ULONG
    
    MsV1_0InteractiveLogon = 2
    MsV1_0Lm20Logon = 3
    MsV1_0NetworkLogon = 4
    MsV1_0WorkstationUnlockLogon = 7
    MsV1_0S4ULogon = 12
    MsV1_0NoElevationLogon = 82
    
    KerbInteractiveLogon = 2
    KerbWorkstationUnlockLogon = 7
    KerbS4ULogon = 12
    
    MSV1_0_S4U_LOGON_FLAG_CHECK_LOGONHOURS = 0x2
    
    KERB_S4U_LOGON_FLAG_CHECK_LOGONHOURS = 0x2
    KERB_S4U_LOGON_FLAG_IDENTITY = 0x8
    
    TOKEN_SOURCE_LENGTH = 8
    
    NEGOTIATE_PACKAGE_NAME = b'Negotiate'
    MICROSOFT_KERBEROS_NAME = b'Kerberos'
    MSV1_0_PACKAGE_NAME = b'MICROSOFT_AUTHENTICATION_PACKAGE_V1_0'
    
    DELETE = 0x00010000
    READ_CONTROL = 0x00020000
    WRITE_DAC = 0x00040000
    WRITE_OWNER = 0x00080000
    
    STANDARD_RIGHTS_REQUIRED = (
        DELETE |
        READ_CONTROL |
        WRITE_DAC |
        WRITE_OWNER
    )
    
    TOKEN_ASSIGN_PRIMARY = 0x0001
    TOKEN_DUPLICATE = 0x0002
    TOKEN_IMPERSONATE = 0x0004
    TOKEN_QUERY = 0x0008
    TOKEN_QUERY_SOURCE = 0x0010
    TOKEN_ADJUST_PRIVILEGES = 0x0020
    TOKEN_ADJUST_GROUPS = 0x0040
    TOKEN_ADJUST_DEFAULT = 0x0080
    TOKEN_ADJUST_SESSIONID = 0x0100
    
    TOKEN_ALL_ACCESS = (
        STANDARD_RIGHTS_REQUIRED |
        TOKEN_ASSIGN_PRIMARY |
        TOKEN_DUPLICATE |
        TOKEN_IMPERSONATE |
        TOKEN_QUERY |
        TOKEN_QUERY_SOURCE |
        TOKEN_ADJUST_PRIVILEGES |
        TOKEN_ADJUST_GROUPS |
        TOKEN_ADJUST_DEFAULT |
        TOKEN_ADJUST_SESSIONID
    )
    
    DUPLICATE_CLOSE_SOURCE = 0x00000001
    DUPLICATE_SAME_ACCESS = 0x00000002
    
    TOKEN_TYPE = wintypes.ULONG
    TokenPrimary = 1
    TokenImpersonation = 2
    
    SECURITY_IMPERSONATION_LEVEL = wintypes.ULONG
    SecurityAnonymous = 0
    SecurityIdentification = 1
    SecurityImpersonation = 2
    SecurityDelegation = 3
    
    
    class NTSTATUS(wintypes.LONG):
    
        def to_error(self):
            return ntdll.RtlNtStatusToDosError(self)
    
        def __repr__(self):
            name = self.__class__.__name__
            status = wintypes.ULONG.from_buffer(self)
            return '{}({})'.format(name, status.value)
    
    
    PNTSTATUS = ctypes.POINTER(NTSTATUS)
    
    
    class BOOL(wintypes.BOOL):
        def __repr__(self):
            name = self.__class__.__name__
            return '{}({})'.format(name, bool(self))
    
    
    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 "{}({})".format(self.__class__.__name__, int(self))
    
    
    class LARGE_INTEGER(wintypes.LARGE_INTEGER):
        # https://msdn.microsoft.com/en-us/library/ff553204
        ntdll.RtlSecondsSince1970ToTime.restype = None
        _unix_epoch = wintypes.LARGE_INTEGER()
        ntdll.RtlSecondsSince1970ToTime(0, ctypes.byref(_unix_epoch))
        _unix_epoch = _unix_epoch.value
    
        def __int__(self):
            return self.value
    
        def __repr__(self):
            name = self.__class__.__name__
            return '{}({})'.format(name, self.value)
    
        def as_time(self):
            time100ns = self.value - self._unix_epoch
            if time100ns >= 0:
                return time100ns / 1e7
            raise ValueError('value predates the Unix epoch')
    
        @classmethod
        def from_time(cls, t):
            time100ns = int(t * 10**7)
            return cls(time100ns + cls._unix_epoch)
    
    
    CHAR = ctypes.c_char
    WCHAR = ctypes.c_wchar
    PCHAR = ctypes.POINTER(CHAR)
    PWCHAR = ctypes.POINTER(WCHAR)
    
    
    class STRING(ctypes.Structure):
        _fields_ = (
            ('Length', wintypes.USHORT),
            ('MaximumLength', wintypes.USHORT),
            ('Buffer', PCHAR),
        )
    
    
    LPSTRING = ctypes.POINTER(STRING)
    
    
    class UNICODE_STRING(ctypes.Structure):
        _fields_ = (
            ('Length', wintypes.USHORT),
            ('MaximumLength', wintypes.USHORT),
            ('Buffer', PWCHAR),
        )
    
    
    LPUNICODE_STRING = ctypes.POINTER(UNICODE_STRING)
    
    
    class LUID(ctypes.Structure):
        _fields_ = (
            ('LowPart', wintypes.DWORD),
            ('HighPart', wintypes.LONG),
        )
    
        def __new__(cls, value=0):
            return cls.from_buffer_copy(ctypes.c_ulonglong(value))
    
        def __int__(self):
            return ctypes.c_ulonglong.from_buffer(self).value
    
        def __repr__(self):
            name = self.__class__.__name__
            return '{}({})'.format(name, int(self))
    
    
    LPLUID = ctypes.POINTER(LUID)
    PSID = wintypes.LPVOID
    
    
    class SID_AND_ATTRIBUTES(ctypes.Structure):
        _fields_ = (
            ('Sid', PSID),
            ('Attributes', wintypes.DWORD),
        )
    
    
    LPSID_AND_ATTRIBUTES = ctypes.POINTER(SID_AND_ATTRIBUTES)
    
    
    class TOKEN_GROUPS(ctypes.Structure):
        _fields_ = (
            ('GroupCount', wintypes.DWORD),
            ('Groups', SID_AND_ATTRIBUTES * 1),
        )
    
    
    LPTOKEN_GROUPS = ctypes.POINTER(TOKEN_GROUPS)
    
    
    class TOKEN_SOURCE(ctypes.Structure):
        _fields_ = (
            ('SourceName', CHAR * TOKEN_SOURCE_LENGTH),
            ('SourceIdentifier', LUID),
        )
    
        def __init__(self, SourceName=None, SourceIdentifier=None):
            super(TOKEN_SOURCE, self).__init__()
            if SourceName is not None:
                if not isinstance(SourceName, bytes):
                    SourceName = SourceName.encode('mbcs')
                self.SourceName = SourceName
            if SourceIdentifier is None:
                luid = self.SourceIdentifier  # pylint: disable=access-member-before-definition
                ntdll.NtAllocateLocallyUniqueId(ctypes.byref(luid))
            else:
                self.SourceIdentifier = SourceIdentifier
    
    
    LPTOKEN_SOURCE = ctypes.POINTER(TOKEN_SOURCE)
    py_source_context = TOKEN_SOURCE(b"PYTHON  ")
    py_origin_name = __name__.encode()
    py_logon_process_name = "{}-{}".format(py_origin_name, os.getpid())
    SIZE_T = ctypes.c_size_t
    
    
    class QUOTA_LIMITS(ctypes.Structure):
        _fields_ = (('PagedPoolLimit', SIZE_T),
                    ('NonPagedPoolLimit', SIZE_T),
                    ('MinimumWorkingSetSize', SIZE_T),
                    ('MaximumWorkingSetSize', SIZE_T),
                    ('PagefileLimit', SIZE_T),
                    ('TimeLimit', wintypes.LARGE_INTEGER))
    
    
    LPQUOTA_LIMITS = ctypes.POINTER(QUOTA_LIMITS)
    LPULONG = ctypes.POINTER(wintypes.ULONG)
    LSA_OPERATIONAL_MODE = wintypes.ULONG
    LPLSA_OPERATIONAL_MODE = LPULONG
    LPHANDLE = ctypes.POINTER(wintypes.HANDLE)
    LPLPVOID = ctypes.POINTER(wintypes.LPVOID)
    LPDWORD = ctypes.POINTER(wintypes.DWORD)
    
    
    class ContiguousUnicode(ctypes.Structure):
        # _string_names_: sequence matched to underscore-prefixed fields
        def __init__(self, *args, **kwargs):
            super(ContiguousUnicode, self).__init__(*args, **kwargs)
    
        def _get_unicode_string(self, name):
            wchar_size = ctypes.sizeof(WCHAR)
            s = getattr(self, '_{}'.format(name))
            length = s.Length // wchar_size
            buf = s.Buffer
            if buf:
                return buf[:length]
            return None
    
        def _set_unicode_buffer(self, value):
            cls = type(self)
            wchar_size = ctypes.sizeof(WCHAR)
            bufsize = (len(value) + 1) * wchar_size
            ctypes.resize(self, ctypes.sizeof(cls) + bufsize)
            addr = ctypes.addressof(self) + ctypes.sizeof(cls)
            ctypes.memmove(addr, value, bufsize)
    
        def _set_unicode_string(self, name, value):
            values = []
            for n in self._string_names_:
                if n == name:
                    values.append(value or '')
                else:
                    values.append(getattr(self, n) or '')
            self._set_unicode_buffer('x00'.join(values))
    
            cls = type(self)
            wchar_size = ctypes.sizeof(WCHAR)
            addr = ctypes.addressof(self) + ctypes.sizeof(cls)
            for n, v in zip(self._string_names_, values):
                ptr = ctypes.cast(addr, PWCHAR)
                ustr = getattr(self, '_{}'.format(n))
                length = ustr.Length = len(v) * wchar_size
                full_length = length + wchar_size
                if ((n == name and value is None) or
                    (n != name and not (length or ustr.Buffer))):
                    ustr.Buffer = None
                    ustr.MaximumLength = 0
                else:
                    ustr.Buffer = ptr
                    ustr.MaximumLength = full_length
                addr += full_length
    
        def __getattr__(self, name):
            if name not in self._string_names_:
                raise AttributeError
            return self._get_unicode_string(name)
    
        def __setattr__(self, name, value):
            if name in self._string_names_:
                self._set_unicode_string(name, value)
            else:
                super(ContiguousUnicode, self).__setattr__(name, value)
    
        @classmethod
        def from_address_copy(cls, address, size=None):
            x = ctypes.Structure.__new__(cls)
            if size is not None:
                ctypes.resize(x, size)
            ctypes.memmove(ctypes.byref(x), address, ctypes.sizeof(x))
            delta = ctypes.addressof(x) - address
            for n in cls._string_names_:
                ustr = getattr(x, '_{}'.format(n))
                addr = ctypes.c_void_p.from_buffer(ustr.Buffer)
                if addr:
                    addr.value += delta
            return x
    
    
    class AuthInfo(ContiguousUnicode):
        # _message_type_: from a logon-submit-type enumeration
        def __init__(self):
            super(AuthInfo, self).__init__()
            self.MessageType = self._message_type_
    
    
    class MSV1_0_INTERACTIVE_LOGON(AuthInfo):
        _message_type_ = MsV1_0InteractiveLogon
        _string_names_ = 'LogonDomainName', 'UserName', 'Password'
    
        _fields_ = (('MessageType', LOGON_SUBMIT_TYPE),
                    ('_LogonDomainName', UNICODE_STRING),
                    ('_UserName', UNICODE_STRING),
                    ('_Password', UNICODE_STRING))
    
        def __init__(self, UserName=None, Password=None, LogonDomainName=None):
            super(MSV1_0_INTERACTIVE_LOGON, self).__init__()
            if LogonDomainName is not None:
                self.LogonDomainName = LogonDomainName
            if UserName is not None:
                self.UserName = UserName
            if Password is not None:
                self.Password = Password
    
    
    class S4ULogon(AuthInfo):
        _string_names_ = 'UserPrincipalName', 'DomainName'
    
        _fields_ = (('MessageType', LOGON_SUBMIT_TYPE),
                    ('Flags', wintypes.ULONG),
                    ('_UserPrincipalName', UNICODE_STRING),
                    ('_DomainName', UNICODE_STRING))
    
        def __init__(self, UserPrincipalName=None, DomainName=None, Flags=0):
            super(S4ULogon, self).__init__()
            self.Flags = Flags
            if UserPrincipalName is not None:
                self.UserPrincipalName = UserPrincipalName
            if DomainName is not None:
                self.DomainName = DomainName
    
    
    class MSV1_0_S4U_LOGON(S4ULogon):
        _message_type_ = MsV1_0S4ULogon
    
    
    class KERB_S4U_LOGON(S4ULogon):
        _message_type_ = KerbS4ULogon
    
    
    PMSV1_0_S4U_LOGON = ctypes.POINTER(MSV1_0_S4U_LOGON)
    PKERB_S4U_LOGON = ctypes.POINTER(KERB_S4U_LOGON)
    
    
    class ProfileBuffer(ContiguousUnicode):
        # _message_type_
        def __init__(self):
            super(ProfileBuffer, self).__init__()
            self.MessageType = self._message_type_
    
    
    class MSV1_0_INTERACTIVE_PROFILE(ProfileBuffer):
        _message_type_ = MsV1_0InteractiveLogon
        _string_names_ = ('LogonScript', 'HomeDirectory', 'FullName',
                          'ProfilePath', 'HomeDirectoryDrive', 'LogonServer')
        _fields_ = (('MessageType', PROFILE_BUFFER_TYPE),
                    ('LogonCount', wintypes.USHORT),
                    ('BadPasswordCount', wintypes.USHORT),
                    ('LogonTime', LARGE_INTEGER),
                    ('LogoffTime', LARGE_INTEGER),
                    ('KickOffTime', LARGE_INTEGER),
                    ('PasswordLastSet', LARGE_INTEGER),
                    ('PasswordCanChange', LARGE_INTEGER),
                    ('PasswordMustChange', LARGE_INTEGER),
                    ('_LogonScript', UNICODE_STRING),
                    ('_HomeDirectory', UNICODE_STRING),
                    ('_FullName', UNICODE_STRING),
                    ('_ProfilePath', UNICODE_STRING),
                    ('_HomeDirectoryDrive', UNICODE_STRING),
                    ('_LogonServer', UNICODE_STRING),
                    ('UserFlags', wintypes.ULONG))
    
    
    def _check_status(result, func, args):
        if result.value < 0:
            raise ctypes.WinError(result.to_error())
        return args
    
    
    def _check_bool(result, func, args):
        if not result:
            raise ctypes.WinError(ctypes.get_last_error())
        return args
    
    
    INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
    INVALID_DWORD_VALUE = wintypes.DWORD(-1).value  # ~WinAPI
    INFINITE = INVALID_DWORD_VALUE
    STD_INPUT_HANDLE = wintypes.DWORD(-10).value
    STD_OUTPUT_HANDLE = wintypes.DWORD(-11).value
    STD_ERROR_HANDLE = wintypes.DWORD(-12).value
    
    
    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)
    LPBYTE = ctypes.POINTER(wintypes.BYTE)
    LPHANDLE = PHANDLE = ctypes.POINTER(ctypes.c_void_p)
    LPDWORD = ctypes.POINTER(ctypes.c_ulong)
    
    
    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)
    
    
    LPSTARTUPINFO = ctypes.POINTER(STARTUPINFO)
    
    
    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),)
    
    
    LPSTARTUPINFOEX = ctypes.POINTER(STARTUPINFOEX)
    
    
    class PROCESS_INFORMATION(ctypes.Structure):
        """https://msdn.microsoft.com/en-us/library/ms684873"""
        _fields_ = (('hProcess', wintypes.HANDLE),
                    ('hThread', wintypes.HANDLE),
                    ('dwProcessId', wintypes.DWORD),
                    ('dwThreadId', wintypes.DWORD))
    
    
    LPPROCESS_INFORMATION = ctypes.POINTER(PROCESS_INFORMATION)
    
    
    class HANDLE_IHV(wintypes.HANDLE):
        pass
    
    
    def errcheck_ihv(result, func, args):
        if result.value == INVALID_HANDLE_VALUE:
            raise ctypes.WinError()
        return result.value
    
    
    class DWORD_IDV(wintypes.DWORD):
        pass
    
    
    def errcheck_idv(result, func, args):
        if result.value == INVALID_DWORD_VALUE:
            raise ctypes.WinError()
        return result.value
    
    
    def errcheck_bool(result, func, args):
        if not result:
            raise ctypes.WinError()
        return args
    
    
    def _win(func, restype, *argtypes):
        func.restype = restype
        func.argtypes = argtypes
        if issubclass(restype, NTSTATUS):
            func.errcheck = _check_status
        elif issubclass(restype, BOOL):
            func.errcheck = _check_bool
        elif issubclass(restype, HANDLE_IHV):
            func.errcheck = errcheck_ihv
        elif issubclass(restype, DWORD_IDV):
            func.errcheck = errcheck_idv
        else:
            func.errcheck = errcheck_bool
    
    
    # https://msdn.microsoft.com/en-us/library/ms683231
    _win(kernel32.GetStdHandle, HANDLE_IHV,
        wintypes.DWORD)  # _In_ nStdHandle
    
    
    # https://msdn.microsoft.com/en-us/library/ms724211
    _win(kernel32.CloseHandle, wintypes.BOOL,
        wintypes.HANDLE)  # _In_ hObject
    
    
    # https://msdn.microsoft.com/en-us/library/ms724935
    _win(kernel32.SetHandleInformation, wintypes.BOOL,
        wintypes.HANDLE,  # _In_ hObject
        wintypes.DWORD,   # _In_ dwMask
        wintypes.DWORD)   # _In_ dwFlags
    
    
    # https://msdn.microsoft.com/en-us/library/ms724251
    _win(kernel32.DuplicateHandle, wintypes.BOOL,
        wintypes.HANDLE,  # _In_  hSourceProcessHandle,
        wintypes.HANDLE,  # _In_  hSourceHandle,
        wintypes.HANDLE,  # _In_  hTargetProcessHandle,
        LPHANDLE,         # _Out_ lpTargetHandle,
        wintypes.DWORD,   # _In_  dwDesiredAccess,
        wintypes.BOOL,    # _In_  bInheritHandle,
        wintypes.DWORD)   # _In_  dwOptions
    
    
    # https://msdn.microsoft.com/en-us/library/ms683179
    _win(kernel32.GetCurrentProcess, wintypes.HANDLE)
    
    
    # https://msdn.microsoft.com/en-us/library/ms683189
    _win(kernel32.GetExitCodeProcess, wintypes.BOOL,
        wintypes.HANDLE,  # _In_  hProcess,
        LPDWORD)          # _Out_ lpExitCode
    
    
    # https://msdn.microsoft.com/en-us/library/aa365152
    _win(kernel32.CreatePipe, wintypes.BOOL,
        PHANDLE,                # _Out_    hReadPipe,
        PHANDLE,                # _Out_    hWritePipe,
        LPSECURITY_ATTRIBUTES,  # _In_opt_ lpPipeAttributes,
        wintypes.DWORD)         # _In_     nSize
    
    
    # https://msdn.microsoft.com/en-us/library/ms682431
    #_win(advapi32.CreateProcessWithTokenW, wintypes.BOOL,
    #    PHANDLE,       # _In_        lpUsername
    #    wintypes.DWORD,         # _In_        dwLogonFlags
    #    wintypes.LPCWSTR,       # _In_opt_    lpApplicationName
    #    wintypes.LPWSTR,        # _Inout_opt_ lpCommandLine
    #    wintypes.DWORD,         # _In_        dwCreationFlags
    #    wintypes.LPVOID,        # _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
    
    
    # https://msdn.microsoft.com/en-us/library/ms683179
    _win(kernel32.GetCurrentProcess, wintypes.HANDLE)
    
    
    # https://msdn.microsoft.com/en-us/library/ms724251
    _win(kernel32.DuplicateHandle, BOOL,
        wintypes.HANDLE,  # _In_  hSourceProcessHandle
        wintypes.HANDLE,  # _In_  hSourceHandle
        wintypes.HANDLE,  # _In_  hTargetProcessHandle
        LPHANDLE,         # _Out_ lpTargetHandle
        wintypes.DWORD,   # _In_  dwDesiredAccess
        wintypes.BOOL,    # _In_  bInheritHandle
        wintypes.DWORD)   # _In_  dwOptions
    
    
    # https://msdn.microsoft.com/en-us/library/ms724295
    _win(kernel32.GetComputerNameW, BOOL,
        wintypes.LPWSTR,  # _Out_   lpBuffer
        LPDWORD)          # _Inout_ lpnSize
    
    
    # https://msdn.microsoft.com/en-us/library/aa379295
    _win(advapi32.OpenProcessToken, BOOL,
        wintypes.HANDLE,  # _In_  ProcessHandle
        wintypes.DWORD,   # _In_  DesiredAccess
        LPHANDLE)         # _Out_ TokenHandle
    
    
    # https://msdn.microsoft.com/en-us/library/aa446617
    _win(advapi32.DuplicateTokenEx, BOOL,
        wintypes.HANDLE,               # _In_     hExistingToken
        wintypes.DWORD,                # _In_     dwDesiredAccess
        LPSECURITY_ATTRIBUTES,         # _In_opt_ lpTokenAttributes
        SECURITY_IMPERSONATION_LEVEL,  # _In_     ImpersonationLevel
        TOKEN_TYPE,                    # _In_     TokenType
        LPHANDLE)                      # _Out_    phNewToken
    
    
    # https://msdn.microsoft.com/en-us/library/ff566415
    _win(ntdll.NtAllocateLocallyUniqueId, NTSTATUS,
        LPLUID)  # _Out_ LUID
    
    
    # https://msdn.microsoft.com/en-us/library/aa378279
    _win(secur32.LsaFreeReturnBuffer, NTSTATUS,
        wintypes.LPVOID,)  # _In_ Buffer
    
    
    # https://msdn.microsoft.com/en-us/library/aa378265
    _win(secur32.LsaConnectUntrusted, NTSTATUS,
        LPHANDLE,)  # _Out_ LsaHandle
    
    
    #https://msdn.microsoft.com/en-us/library/aa378318
    _win(secur32.LsaRegisterLogonProcess, NTSTATUS,
        LPSTRING,                # _In_  LogonProcessName
        LPHANDLE,                # _Out_ LsaHandle
        LPLSA_OPERATIONAL_MODE)  # _Out_ SecurityMode
    
    
    # https://msdn.microsoft.com/en-us/library/aa378269
    _win(secur32.LsaDeregisterLogonProcess, NTSTATUS,
        wintypes.HANDLE)  # _In_ LsaHandle
    
    
    # https://msdn.microsoft.com/en-us/library/aa378297
    _win(secur32.LsaLookupAuthenticationPackage, NTSTATUS,
        wintypes.HANDLE,  # _In_  LsaHandle
        LPSTRING,         # _In_  PackageName
        LPULONG)          # _Out_ AuthenticationPackage
    
    
    # https://msdn.microsoft.com/en-us/library/aa378292
    _win(secur32.LsaLogonUser, NTSTATUS,
        wintypes.HANDLE,      # _In_     LsaHandle
        LPSTRING,             # _In_     OriginName
        SECURITY_LOGON_TYPE,  # _In_     LogonType
        wintypes.ULONG,       # _In_     AuthenticationPackage
        wintypes.LPVOID,      # _In_     AuthenticationInformation
        wintypes.ULONG,       # _In_     AuthenticationInformationLength
        LPTOKEN_GROUPS,       # _In_opt_ LocalGroups
        LPTOKEN_SOURCE,       # _In_     SourceContext
        LPLPVOID,             # _Out_    ProfileBuffer
        LPULONG,              # _Out_    ProfileBufferLength
        LPLUID,               # _Out_    LogonId
        LPHANDLE,             # _Out_    Token
        LPQUOTA_LIMITS,       # _Out_    Quotas
        PNTSTATUS)            # _Out_    SubStatus
    
    
    def duplicate_token(source_token=None, access=TOKEN_ALL_ACCESS,
                        impersonation_level=SecurityImpersonation,
                        token_type=TokenPrimary, attributes=None):
        close_source = False
        if source_token is None:
            close_source = True
            source_token = HANDLE()
            advapi32.OpenProcessToken(kernel32.GetCurrentProcess(),
                TOKEN_ALL_ACCESS, ctypes.byref(source_token))
        token = HANDLE()
        try:
            advapi32.DuplicateTokenEx(source_token, access, attributes,
                impersonation_level, token_type, ctypes.byref(token))
        finally:
            if close_source:
                source_token.Close()
        return token
    
    
    def lsa_connect_untrusted():
        handle = wintypes.HANDLE()
        secur32.LsaConnectUntrusted(ctypes.byref(handle))
        return handle.value
    
    
    def lsa_register_logon_process(logon_process_name):
        if not isinstance(logon_process_name, bytes):
            logon_process_name = logon_process_name.encode('mbcs')
        logon_process_name = logon_process_name[:127]
        buf = ctypes.create_string_buffer(logon_process_name, 128)
        name = STRING(len(logon_process_name), len(buf), buf)
        handle = wintypes.HANDLE()
        mode = LSA_OPERATIONAL_MODE()
        secur32.LsaRegisterLogonProcess(ctypes.byref(name),
            ctypes.byref(handle), ctypes.byref(mode))
        return handle.value
    
    
    def lsa_lookup_authentication_package(lsa_handle, package_name):
        if not isinstance(package_name, bytes):
            package_name = package_name.encode('mbcs')
        package_name = package_name[:127]
        buf = ctypes.create_string_buffer(package_name)
        name = STRING(len(package_name), len(buf), buf)
        package = wintypes.ULONG()
        secur32.LsaLookupAuthenticationPackage(lsa_handle, ctypes.byref(name),
            ctypes.byref(package))
        return package.value
    
    
    LOGONINFO = collections.namedtuple('LOGONINFO', ('Token', 'LogonId',
                    'Profile', 'Quotas'))
    
    
    def lsa_logon_user(auth_info, local_groups=None, origin_name=py_origin_name,
                       source_context=None, auth_package=None, logon_type=None,
                       lsa_handle=None):
        if local_groups is None:
            plocal_groups = LPTOKEN_GROUPS()
        else:
            plocal_groups = ctypes.byref(local_groups)
        if source_context is None:
            source_context = py_source_context
        if not isinstance(origin_name, bytes):
            origin_name = origin_name.encode('mbcs')
        buf = ctypes.create_string_buffer(origin_name)
        origin_name = STRING(len(origin_name), len(buf), buf)
        if auth_package is None:
            if isinstance(auth_info, MSV1_0_S4U_LOGON):
                auth_package = NEGOTIATE_PACKAGE_NAME
            elif isinstance(auth_info, KERB_S4U_LOGON):
                auth_package = MICROSOFT_KERBEROS_NAME
            else:
                auth_package = MSV1_0_PACKAGE_NAME
        if logon_type is None:
            if isinstance(auth_info, S4ULogon):
                logon_type = win32con.LOGON32_LOGON_NETWORK
            else:
                logon_type = Interactive
        profile_buffer = wintypes.LPVOID()
        profile_buffer_length = wintypes.ULONG()
        profile = None
        logonid = LUID()
        htoken = HANDLE()
        quotas = QUOTA_LIMITS()
        substatus = NTSTATUS()
        deregister = False
        if lsa_handle is None:
            lsa_handle = lsa_connect_untrusted()
            deregister = True
        try:
            if isinstance(auth_package, (str, bytes)):
                auth_package = lsa_lookup_authentication_package(lsa_handle,
                                    auth_package)
            try:
                secur32.LsaLogonUser(lsa_handle, ctypes.byref(origin_name),
                    logon_type, auth_package, ctypes.byref(auth_info),
                    ctypes.sizeof(auth_info), plocal_groups,
                    ctypes.byref(source_context), ctypes.byref(profile_buffer),
                    ctypes.byref(profile_buffer_length), ctypes.byref(logonid),
                    ctypes.byref(htoken), ctypes.byref(quotas),
                    ctypes.byref(substatus))
            except WindowsError:  # pylint: disable=undefined-variable
                if substatus.value:
                    raise ctypes.WinError(substatus.to_error())
                raise
            finally:
                if profile_buffer:
                    address = profile_buffer.value
                    buftype = PROFILE_BUFFER_TYPE.from_address(address).value
                    if buftype == MsV1_0InteractiveLogon:
                        profile = MSV1_0_INTERACTIVE_PROFILE.from_address_copy(
                                    address, profile_buffer_length.value)
                    secur32.LsaFreeReturnBuffer(address)
        finally:
            if deregister:
                secur32.LsaDeregisterLogonProcess(lsa_handle)
        return LOGONINFO(htoken, logonid, profile, quotas)
    
    
    def logon_msv1(name, password, domain=None, local_groups=None,
                    origin_name=py_origin_name, source_context=None):
        return lsa_logon_user(MSV1_0_INTERACTIVE_LOGON(name, password, domain),
                    local_groups, origin_name, source_context)
    
    
    def logon_msv1_s4u(name, local_groups=None, origin_name=py_origin_name,
                        source_context=None):
        domain = ctypes.create_unicode_buffer(MAX_COMPUTER_NAME_LENGTH + 1)
        length = wintypes.DWORD(len(domain))
        kernel32.GetComputerNameW(domain, ctypes.byref(length))
        return lsa_logon_user(MSV1_0_S4U_LOGON(name, domain.value),
                    local_groups, origin_name, source_context)
    
    
    def logon_kerb_s4u(name, realm=None, local_groups=None,
                         origin_name=py_origin_name,
                         source_context=None,
                         logon_process_name=py_logon_process_name):
        lsa_handle = lsa_register_logon_process(logon_process_name)
        try:
            return lsa_logon_user(KERB_S4U_LOGON(name, realm),
                        local_groups, origin_name, source_context,
                        lsa_handle=lsa_handle)
        finally:
            secur32.LsaDeregisterLogonProcess(lsa_handle)
    
    
    def DuplicateHandle(hsrc=kernel32.GetCurrentProcess(),
                        srchandle=kernel32.GetCurrentProcess(),
                        htgt=kernel32.GetCurrentProcess(),
                        access=0, inherit=False,
                        options=win32con.DUPLICATE_SAME_ACCESS):
        tgthandle = wintypes.HANDLE()
        kernel32.DuplicateHandle(hsrc, srchandle,
                                 htgt, ctypes.byref(tgthandle),
                                 access, inherit, options)
        return tgthandle.value
    
    
    def CreatePipe(inherit_read=False, inherit_write=False):
        read, write = wintypes.HANDLE(), wintypes.HANDLE()
        kernel32.CreatePipe(ctypes.byref(read), ctypes.byref(write), None, 0)
        if inherit_read:
            kernel32.SetHandleInformation(read, win32con.HANDLE_FLAG_INHERIT,
                                          win32con.HANDLE_FLAG_INHERIT)
        if inherit_write:
            kernel32.SetHandleInformation(write, win32con.HANDLE_FLAG_INHERIT,
                                          win32con.HANDLE_FLAG_INHERIT)
        return read.value, write.value
    
    
    def set_user_perm(obj, perm, sid):
        '''
        根据设置的sid设置对象权限
        '''
        info = (
            win32security.OWNER_SECURITY_INFORMATION |
            win32security.GROUP_SECURITY_INFORMATION |
            win32security.DACL_SECURITY_INFORMATION
        )
        sd = win32security.GetUserObjectSecurity(obj, info)
        dacl = sd.GetSecurityDescriptorDacl()
        ace_cnt = dacl.GetAceCount()
        found = False
        for idx in range(0, ace_cnt):
            (aceType, aceFlags), ace_mask, ace_sid = dacl.GetAce(idx)
            ace_exists = (
                aceType == ntsecuritycon.ACCESS_ALLOWED_ACE_TYPE and
                ace_mask == perm and
                ace_sid == sid
            )
            if ace_exists:
                # If the ace already exists, do nothing
                break
        else:
            dacl.AddAccessAllowedAce(dacl.GetAclRevision(), perm, sid)
            sd.SetSecurityDescriptorDacl(1, dacl, 0)
            win32security.SetUserObjectSecurity(obj, info, sd)
    
    
    def grant_winsta_and_desktop(th):
        '''
        给当前令牌用户访问当前进程 window station and desktop 权限.
        '''
        current_sid = win32security.GetTokenInformation(th, win32security.TokenUser)[0]
        # Add permissions for the sid to the current windows station and thread id.
        # This prevents windows error 0xC0000142.
        winsta = win32process.GetProcessWindowStation()
        set_user_perm(winsta, WINSTA_ALL, current_sid)
        desktop = win32service.GetThreadDesktop(win32api.GetCurrentThreadId())
        set_user_perm(desktop, DESKTOP_ALL, current_sid)
    
    
    def environment_string(env):
        senv = ''
        for k, v in env.items():
            senv += k + '=' + v + ''
        senv += ''
        return ctypes.create_unicode_buffer(senv)
    
    
    def CreateProcessWithTokenW(token,
                                logonflags=0,
                                applicationname=None,
                                commandline=None,
                                creationflags=0,
                                environment=None,
                                currentdirectory=None,
                                startupinfo=None):
        creationflags |= win32con.CREATE_UNICODE_ENVIRONMENT
        if commandline is not None:
            commandline = ctypes.create_unicode_buffer(commandline)
        if startupinfo is None:
            startupinfo = STARTUPINFO()
        if currentdirectory is not None:
            currentdirectory = ctypes.create_unicode_buffer(currentdirectory)
        if environment:
            environment = ctypes.pointer(
               environment_string(environment)
            )
        process_info = PROCESS_INFORMATION()
        ret = advapi32.CreateProcessWithTokenW(
            token,
            logonflags,
            applicationname,
            commandline,
            creationflags,
            environment,
            currentdirectory,
            ctypes.byref(startupinfo),
            ctypes.byref(process_info),
        )
        if ret == 0:
            winerr = win32api.GetLastError()
            exc = WindowsError(win32api.FormatMessage(winerr))  # pylint: disable=undefined-variable
            exc.winerror = winerr
            raise exc
        return process_info
    
    
    def enumerate_tokens(sid=None, session_id=None, privs=None):
        '''
        枚举当前进程可以访问的任何tokens
        Optionally filter by sid.
        '''
        for p in psutil.process_iter():
            if p.pid == 0:
                continue
            try:
                ph = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, p.pid)
            except win32api.error as exc:
                if exc.winerror == 5:
                    log.debug("Unable to OpenProcess pid=%d name=%s", p.pid, p.name())
                    continue
                raise exc
            try:
                access = (
                    win32security.TOKEN_DUPLICATE |
                    win32security.TOKEN_QUERY |
                    win32security.TOKEN_IMPERSONATE |
                    win32security.TOKEN_ASSIGN_PRIMARY
                )
                th = win32security.OpenProcessToken(ph, access)
            except Exception as exc:
                log.debug("OpenProcessToken failed pid=%d name=%s user%s", p.pid, p.name(), p.username())
                continue
            try:
                process_sid = win32security.GetTokenInformation(th, win32security.TokenUser)[0]
            except Exception as exc:
                log.exception("GetTokenInformation pid=%d name=%s user%s", p.pid, p.name(), p.username())
                continue
    
            proc_sid = win32security.ConvertSidToStringSid(process_sid)
            if sid and sid != proc_sid:
                log.debug("Token for pid does not match user sid: %s", sid)
                continue
    
            if session_id and win32security.GetTokenInformation(th, win32security.TokenSessionId) != session_id:
                continue
    
            def has_priv(tok, priv):
                luid = win32security.LookupPrivilegeValue(None, priv)
                for priv_luid, flags in win32security.GetTokenInformation(tok, win32security.TokenPrivileges):
                    if priv_luid == luid:
                        return True
                return False
            if privs:
                has_all = True
                for name in privs:
                    if not has_priv(th, name):
                        has_all = False
                if not has_all:
                    continue
            yield dup_token(th)
    
    
    def impersonate_sid(sid, session_id=None, privs=None):
        '''
        根据给的sid找到已经存在进程的令牌 并返回
        '''
        for tok in enumerate_tokens(sid, session_id, privs):
            tok = dup_token(tok)
            elevate_token(tok)
            if win32security.ImpersonateLoggedOnUser(tok) == 0:
                raise WindowsError("Impersonation failure")  # pylint: disable=undefined-variable
            return tok
        raise WindowsError("Impersonation failure")  # pylint: disable=undefined-variable
    
    
    def dup_token(th):
        '''
        复制进程令牌
        '''
        # TODO: is `duplicate_token` the same?
        sec_attr = win32security.SECURITY_ATTRIBUTES()
        sec_attr.bInheritHandle = True
        return win32security.DuplicateTokenEx(
           th,
           win32security.SecurityImpersonation,
           win32con.MAXIMUM_ALLOWED,
           win32security.TokenPrimary,
           sec_attr,
        )
    
    
    def elevate_token(th):
        '''
        将所有令牌特权设置为已经启用
        '''
        # 获取此令牌包含的权限列表
        privileges = win32security.GetTokenInformation(
            th, win32security.TokenPrivileges)
    
        # 创建一组要启用的所有权限
        enable_privs = set()
        for luid, flags in privileges:
            enable_privs.add((luid, win32con.SE_PRIVILEGE_ENABLED))
    
        # 启用权限
        if win32security.AdjustTokenPrivileges(th, 0, enable_privs) == 0:
            raise WindowsError(win32api.FormatMessage(win32api.GetLastError()))  # pylint: disable=undefined-variable
    
    
    def make_inheritable(token):
        '''创建句柄'''
        return win32api.DuplicateHandle(
            win32api.GetCurrentProcess(),
            token,
            win32api.GetCurrentProcess(),
            0,
            1,
            win32con.DUPLICATE_SAME_ACCESS
        )
    
    
    def CreateProcessWithLogonW(username=None, domain=None, password=None,
            logonflags=0, applicationname=None, commandline=None, creationflags=0,
            environment=None, currentdirectory=None, startupinfo=None):
        creationflags |= win32con.CREATE_UNICODE_ENVIRONMENT
        if commandline is not None:
            commandline = ctypes.create_unicode_buffer(commandline)
        if startupinfo is None:
            startupinfo = STARTUPINFO()
        process_info = PROCESS_INFORMATION()
        advapi32.CreateProcessWithLogonW(
            username,
            domain,
            password,
            logonflags,
            applicationname,
            commandline,
            creationflags,
            environment,
            currentdirectory,
            ctypes.byref(startupinfo),
            ctypes.byref(process_info),
        )
        return process_info
    
    

    执行bat脚本主函数如下

    # -*- coding: utf-8 -*-
    '''
    此module适用于在system或者win上以普通用户的权限执行某个命令  或者以普通用户的权限切换到其他用户执行命令(需要密码)
    '''
    import sys
    reload(sys)
    sys.setdefaultencoding('utf8')
    
    import ctypes
    import os
    import logging
    import psutil
    try:
        import psutil
        HAS_PSUTIL = True
    except ImportError:
        HAS_PSUTIL = False
    
    try:
        import win32api
        import win32con
        import win32process
        import win32security
        import win32pipe
        import win32event
        import win32profile
        import msvcrt
        HAS_WIN32 = True
    except ImportError:
        HAS_WIN32 = False
    
    from logger import aglogger
    import win_startup
    log = aglogger.logger
    
    class CommandExecutionError(Exception):
        pass
    
    def __virtual__():
    
        if not HAS_WIN32 or not HAS_PSUTIL:
            return False, 'This utility requires pywin32 and psutil'
        return 'win_runas'
    
    def proc_pid(file_name,pid = 0):
        try:
            tmp_read = dict()
            if os.path.isfile(file_name):
                with open(file_name, "r+") as fd:
                    tmp_read = fd.read()
                tmp_writd = eval(tmp_read)
                if isinstance(tmp_writd, dict) and pid:
                    if isinstance(tmp_writd.get("pid"), list):
                        tmp_writd["pid"].append(str(pid))
                    else:
                        tmp_writd["pid"] = [str(pid)]
                    with open(file_name, "w") as fd:
                        fd.write(str(tmp_writd))
            else:
                log.error("file not find {}".format(file_name))
        except Exception as e:
            log.error(e)
    
    
    def split_username(username):
        # TODO: Is there a windows api for this?
        domain = '.'
        if '@' in username:
            username, domain = username.split('@')
        if '\' in username:
            domain, username = username.split('\')
        return username, domain
    
    
    def runas(cmdLine, username, password=None, cwd = 'C:/xxx' ):
        '''
        用其他用户的权限执行一个命令。如果这个进程 运行的权限是admin或者system权限不需要密码。
        其他非特权用户需要密码。命令以提供账户的级别权限运行。
        '''
    
        # 从当前进程获取令牌
        access = (
            win32security.TOKEN_QUERY |
            win32security.TOKEN_ADJUST_PRIVILEGES
        )
        th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), access)
        win_startup.elevate_token(th)
    
        #尝试模拟system用户  此进程用户需要被授予SeImpersonatePrivilege权限 Administrator用户默认有这个权限
        try:
            impersonation_token = win_startup.impersonate_sid(
                win_startup.SYSTEM_SID,
                session_id=0,
                privs=['SeTcbPrivilege'],
            )
        except WindowsError:  # pylint: disable=undefined-variable
            log.debug("Unable to impersonate SYSTEM user")
            impersonation_token = None
    
        # 模拟system用户失败 回退到非特权用户
        if not impersonation_token:
            log.debug("No impersonation token, using unprivileged runas")
            return runas_unpriv(cmdLine, username, password, cwd)
    
        username, domain = split_username(username)
        #验证这个用户的域和sid是否账户(UAC验证)
        try:
            _, domain, _ = win32security.LookupAccountName(domain, username)
        except Exception as exc:
            log.error("exc {}".format(exc))
            raise CommandExecutionError(exc)
    
        if domain == 'NT AUTHORITY':
            #作为系统级账户登录  SYSTEM, LOCAL SERVICE, or NETWORK SERVICE.
            logonType = win32con.LOGON32_LOGON_SERVICE
            user_token = win32security.LogonUser(
                username,
                domain,
                '',
                win32con.LOGON32_LOGON_SERVICE,
                win32con.LOGON32_PROVIDER_DEFAULT,
            )
        elif password:
            # 使用密码登录
            user_token = win32security.LogonUser(
                username,
                domain,
                password,
                win32con.LOGON32_LOGON_INTERACTIVE,
                win32con.LOGON32_PROVIDER_DEFAULT,
            )
        else:
            #不使用密码登录  总是返回最高级别的token
            user_token = win_startup.logon_msv1_s4u(username).Token
    
        # 如果需要获取要提升的用户令牌
        elevation_type = win32security.GetTokenInformation(
            user_token, win32security.TokenElevationType
        )
        if elevation_type > 1:
            user_token = win32security.GetTokenInformation(
                user_token,
                win32security.TokenLinkedToken
            )
    
        # 提升用户令牌
        win_startup.elevate_token(user_token)
    
        #确保用户令牌有访问桌面权限
        win_startup.grant_winsta_and_desktop(user_token)
    
        # 创建输入输出管道 包括正确输出和错误输出
        security_attributes = win32security.SECURITY_ATTRIBUTES()
        security_attributes.bInheritHandle = 1
    
        stdin_read, stdin_write = win32pipe.CreatePipe(security_attributes, 0)
        stdin_read = win_startup.make_inheritable(stdin_read)
    
        stdout_read, stdout_write = win32pipe.CreatePipe(security_attributes, 0)
        stdout_write = win_startup.make_inheritable(stdout_write)
    
        stderr_read, stderr_write = win32pipe.CreatePipe(security_attributes, 0)
        stderr_write = win_startup.make_inheritable(stderr_write)
    
        #运行进程但是不显示gui界面
        creationflags = (
            win32process.CREATE_NO_WINDOW |
            win32process.CREATE_NEW_CONSOLE |
            win32process.CREATE_SUSPENDED
        )
    
        # startup_info = win_startup.STARTUPINFO(
        #     dwFlags=win32con.STARTF_USESTDHANDLES,
        #     hStdInput=stdin_read.handle,
        #     hStdOutput=stdout_write.handle,
        #     hStdError=stderr_write.handle,
        # )
        startup_info = win_startup.STARTUPINFO(
            dwFlags=win32con.STARTF_USESTDHANDLES,
            hStdInput=stdin_read.handle,
            hStdOutput=stdout_write.handle,
            hStdError=stdout_write.handle,
        )
    
        # 得到对应用户的环境变量信息
        env = win32profile.CreateEnvironmentBlock(user_token, False)
    
        #创建一个挂起状态的进程
        process_info = win_startup.CreateProcessWithTokenW(
            int(user_token),
            logonflags=1,
            applicationname=None,
            commandline=cmdLine,
            currentdirectory=cwd,
            creationflags=creationflags,
            startupinfo=startup_info,
            environment=env,
        )
    
        hProcess = process_info.hProcess
        hThread = process_info.hThread
        dwProcessId = process_info.dwProcessId
        dwThreadId = process_info.dwThreadId
    
        win_startup.kernel32.CloseHandle(stdin_write.handle)
        win_startup.kernel32.CloseHandle(stdout_write.handle)
        win_startup.kernel32.CloseHandle(stderr_write.handle)
    
        ret = {'pid': dwProcessId}
        # 让这个进程运行
        log.info('winsubproc_account pid {}'.format(dwProcessId))
        psutil.Process(dwProcessId).resume()
    
        # 等待进程退出 并且返回退出码
        if win32event.WaitForSingleObject(hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0:
            exitcode = win32process.GetExitCodeProcess(hProcess)
            ret['retcode'] = exitcode
    
        # 读取标准输出
        fd_out = msvcrt.open_osfhandle(stdout_read.handle, os.O_RDONLY | os.O_TEXT)
        # with os.fdopen(fd_out, 'r') as f_out:
            # stdout = f_out.read()
        # fo = os.fdopen(fd_out, "r")
        # os.lseek(fo, 0, 0)
        #将标准输出和错误重定向到同一个管道
        ret['stdout'] = os.read(fd_out, 1000 * 1024 * 1024)
    
        # 读取错误输出
        # fd_err = msvcrt.open_osfhandle(stderr_read.handle, os.O_RDONLY | os.O_TEXT)
    
        # fo = os.fdopen(fd_err, "w+")
        # fo.write("Python is a great language.")
        # ret['stderr'] = os.read(fd_err, 10 * 1024 * 1024)
        ret['stderr'] = ''
    
        win_startup.kernel32.CloseHandle(hProcess)
        win32api.CloseHandle(user_token)
        if impersonation_token:
            win32security.RevertToSelf()
        win32api.CloseHandle(impersonation_token)
        return ret
    
    
    def runas_unpriv(cmd, username, password, cwd=None):
        '''
        在非特权的方式工作
        '''
        # 创建子进程和父进程之间的可被继承的输入输出管道
        c2pread, c2pwrite = win_startup.CreatePipe(
            inherit_read=False, inherit_write=True,
        )
        errread, errwrite = win_startup.CreatePipe(
            inherit_read=False, inherit_write=True,
        )
    
        # 创建输入通道
        stdin = win_startup.kernel32.GetStdHandle(
                win_startup.STD_INPUT_HANDLE,
        )
        dupin = win_startup.DuplicateHandle(srchandle=stdin, inherit=True)
    
        # 获取要运行cmd的结构信息
        # startup_info = win_startup.STARTUPINFO(
        #     dwFlags=win32con.STARTF_USESTDHANDLES,
        #     hStdInput=dupin,
        #     hStdOutput=c2pwrite,
        #     hStdError=errwrite,
        # )
        startup_info = win_startup.STARTUPINFO(
            dwFlags=win32con.STARTF_USESTDHANDLES,
            hStdInput=dupin,
            hStdOutput=c2pwrite,
            hStdError=c2pwrite,
        )
    
        username, domain = split_username(username)
        # 返回运行进程的信息 后面用到
        process_info = win_startup.CreateProcessWithLogonW(
                username=username,
                domain=domain,
                password=password,
                logonflags=win_startup.LOGON_WITH_PROFILE,
                commandline=cmd,
                startupinfo=startup_info,
                currentdirectory=cwd)
    
        win_startup.kernel32.CloseHandle(dupin)
        win_startup.kernel32.CloseHandle(c2pwrite)
        win_startup.kernel32.CloseHandle(errwrite)
        win_startup.kernel32.CloseHandle(process_info.hThread)
        #保存输出信息结构体
        ret = {'pid': process_info.dwProcessId}
        # 正常输出
        fd_out = msvcrt.open_osfhandle(c2pread, os.O_RDONLY | os.O_TEXT)
        # with os.fdopen(fd_out, 'r') as f_out:
        #     ret['stdout'] = f_out.read()
        ret['stdout'] = os.read(fd_out, 1000 * 1024 * 1024)
        # 错误输出
        # fd_err = msvcrt.open_osfhandle(errread, os.O_RDONLY | os.O_TEXT)
        # with os.fdopen(fd_err, 'r') as f_err:
        #     ret['stderr'] = f_err.read()
        ret['stderr'] = ""
        # 返回退出码
        if win_startup.kernel32.WaitForSingleObject(process_info.hProcess, win32event.INFINITE) == 
                win32con.WAIT_OBJECT_0:
            exitcode = win_startup.wintypes.DWORD()
            win_startup.kernel32.GetExitCodeProcess(process_info.hProcess,ctypes.byref(exitcode))
            ret['retcode'] = exitcode.value
        # 关闭进程句柄对象
        win_startup.kernel32.CloseHandle(process_info.hProcess)
        return ret
    
    if __name__ == "__main__":
        import tempfile,time
        outfile = './a.txt'
    
        cmd = 'C:/bb.bat 1'
        comspec = os.environ.get("COMSPEC", "cmd.exe")
        cmd = '{} /c "{}"'.format(comspec, cmd)
        f = open(outfile,'wb+')
        out_fileno = f.fileno()
        try:
            # print cmd
            res = runas(cmd,username,passwd)
            print res
            print res['stdout'].decode('gbk')
            # print type(res['stdout'])
            # print res['pid']
            # print psutil.Process(26672)
        except Exception as e:
            print e
    #     stdout = f_out.read()
        # while True:
        #     x = fd.read()
        #     if x:
        #         print x
        #     else:
        #         break
    
    

    说明

    返回值是一个字典,从脚本进程拿输出我把正确输出和错误输出重定向到了正确输出的管道。为了避免bat脚本中的start语句造成读输出操作阻塞,我直接操作了文件描述符,没有os.fdopen转文件对象之后再操作。如果你是administrator或者system之类的特权账号,密码不是必须的。如果是一个普通用户要切换到另外一个账户进行操作则需要密码。

  • 相关阅读:
    在阿里云上遇见更好的Oracle(三)
    从传统IT快速走向公共云计算
    在阿里云上遇见更好的Oracle(二)
    Oracle 11g 审计跟踪管理
    在阿里云上遇见更好的Oracle(一)
    Elasticsearch中的DocValues
    初识Django —Python API接口编程入门
    为什么mysqld启动报错
    云计算产品的四件套
    说说云计算中的地域和可用区概念
  • 原文地址:https://www.cnblogs.com/sening/p/10581370.html
Copyright © 2020-2023  润新知