CreateProcessWithLogonW,作为另一个桌面上的另一个用户创建进程,使用浏览器失败

时间:2015-06-01 14:23:13

标签: python windows winapi ctypes

首先,很难找到一个复杂的标题,因为整个情况复杂而令人困惑。

我正在尝试以具有受限权限的用户创建进程(用户是“用户”组的一部分)。该过程应该在另一个桌面上生成(我们将其命名为“test”),而不是"default" - 桌面上。使用CreateProcessWithLogonW功能的进程正在使用管理员权限运行。虽然普通应用程序(记事本,vlc,winrar)运行没有问题,但IE,Firefox,Chrome等浏览器应用程序似乎有问题。它们已经启动,但它们在没有错误代码的情况下立即关闭。如果我使用具有管理权限的用户,则每个应用程序都会运行而不会出现错误。

我正在为winstation和桌面的DACL添加ACE。此外,如果我像这样开始cmd.exe并尝试运行firefox,则会出现同样的问题。我正在使用python 2.7和ctypes以及win32api:

from _ctypes import Array, POINTER, sizeof, byref
from ctypes import wintypes, windll, WinError
import ctypes
from ctypes.wintypes import BYTE, HANDLE, DWORD, BOOL, LPCWSTR, LPWSTR, LPVOID

from win32con import CREATE_NEW_CONSOLE, READ_CONTROL, WRITE_DAC, \
GROUP_SECURITY_INFORMATION, DESKTOP_WRITEOBJECTS, DESKTOP_READOBJECTS
import win32con
from win32security import ACL_REVISION_DS
import win32security
import win32service


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)


GENERIC_ACCESS =  (win32con.GENERIC_READ    | win32con.GENERIC_WRITE |\
win32con.GENERIC_EXECUTE | win32con.GENERIC_ALL)



INVALID_HANDLE_VALUE = -1
CREATE_UNICODE_ENVIRONMENT = 0x00000400

CData = Array.__base__
LPBYTE = POINTER(BYTE)

class PROCESS_INFORMATION(ctypes.Structure):
    _fields_ = [
        ('hProcess',    HANDLE),
        ('hThread',     HANDLE),
        ('dwProcessId', DWORD),
        ('dwThreadId',  DWORD),
    ]
LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)


class STARTUPINFOW(ctypes.Structure):
    _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))

LPSTARTUPINFOW = POINTER(STARTUPINFOW)


windll.advapi32.CreateProcessWithLogonW.restype = BOOL
windll.advapi32.CreateProcessWithLogonW.argtypes = [
    LPCWSTR, # lpUsername
    LPCWSTR, # lpDomain
    LPCWSTR, # lpPassword
    DWORD,   # dwLogonFlags
    LPCWSTR, # lpApplicationName
    LPWSTR,  # lpCommandLine (inout)
    DWORD,   # dwCreationFlags
    LPVOID, # lpEnvironment  (force Unicode)
    LPCWSTR, # lpCurrentDirectory
    LPSTARTUPINFOW, # lpStartupInfo
    LPPROCESS_INFORMATION, # lpProcessInfo (out)
]

def CreateProcessWithLogonW(
    lpUsername=None, 
    lpDomain=None, 
    lpPassword=None, 
    dwLogonFlags=0, 
    lpApplicationName=0, 
    lpCommandLine=None,
    dwCreationFlags=0, 
    lpEnvironment=None, 
    lpCurrentDirectory=None,
    startupInfo=None):

    if (lpCommandLine is not None and not isinstance(lpCommandLine, CData)):
        lpCommandLine = ctypes.create_unicode_buffer(lpCommandLine)

    dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT     

    if startupInfo is None:
        startupInfo = STARTUPINFOW(sizeof(STARTUPINFOW))

    processInformation = PROCESS_INFORMATION(INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE)

    success = windll.advapi32.CreateProcessWithLogonW(
        lpUsername, lpDomain, lpPassword, dwLogonFlags, lpApplicationName,
        lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory, 
        byref(startupInfo), byref(processInformation))

    if not success:
        raise WinError()
    return processInformation


if __name__ == '__main__':

    user_group_sid = win32security.LookupAccountName('','Users')[0]

    #
    #Adding rights for user group "users" to winsta0
    #
    #getting winsta0 handle
    hwinsta = win32service.OpenWindowStation("winsta0",False,READ_CONTROL | WRITE_DAC )
    #getting security descriptor by winsta0-handle
    sec_desc_winsta = win32security.GetUserObjectSecurity(hwinsta,win32security.OWNER_SECURITY_INFORMATION |win32security.DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION)
    #getting DACL from security descriptor
    dacl_winsta = sec_desc_winsta.GetSecurityDescriptorDacl()
    if dacl_winsta is None:
        #create DACL if not exisiting
        dacl_winsta=win32security.ACL()
    #Adding ACEs to DACL for specific user group
    dacl_winsta.AddAccessAllowedAce(ACL_REVISION_DS,GENERIC_ACCESS,user_group_sid)
    dacl_winsta.AddAccessAllowedAce(ACL_REVISION_DS,WINSTA_ALL,user_group_sid)
    #setting modified DACL for winsta0
    win32security.SetSecurityInfo(hwinsta, win32security.SE_WINDOW_OBJECT,win32security.DACL_SECURITY_INFORMATION,None,None,dacl_winsta,None)

    #
    #Adding rights for user group "users" to desktop
    #
    #getting handle of different Desktop
    hdesk = win32service.OpenDesktop("test",0 ,False,READ_CONTROL | WRITE_DAC |DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS)
    #getting security descriptor by desktop-handle
    sec_desc_desk = win32security.GetUserObjectSecurity(hdesk,win32security.OWNER_SECURITY_INFORMATION |win32security.DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION )
    #getting DACL from security descriptor
    dacl_desk = sec_desc_desk.GetSecurityDescriptorDacl()
    if dacl_desk is None:
        #create DACL if not exisiting
        dacl_desk=win32security.ACL()
    #Adding ACEs to DACL for specific user group
    dacl_desk.AddAccessAllowedAce(ACL_REVISION_DS,GENERIC_ACCESS,user_group_sid)
    dacl_desk.AddAccessAllowedAce(ACL_REVISION_DS,DESKTOP_ALL,user_group_sid)
    #setting modified DACL for desktop
    win32security.SetSecurityInfo(hdesk, win32security.SE_WINDOW_OBJECT,win32security.DACL_SECURITY_INFORMATION,None,None,dacl_desk,None)

    firefox = "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"
    notepad = "C:\\windows\\notepad.exe"

    si = STARTUPINFOW()
    si.lpDesktop = "winsta0\\test"

    pi = CreateProcessWithLogonW("test", 
                                ".", 
                                "password",
                                0x00000001,
                                None,
                                firefox,
                                CREATE_NEW_CONSOLE,
                                startupInfo=si)

奇怪的是,如果我切换到“测试”-desktop并使用ShellRunas(shift +右键单击 - >以不同的用户身份运行),它可以完美运行。因此,我似乎缺少授予我的用户一些权利,但我不知道哪些权利。

所以这是我的问题:

  1. 我是否正确使用CreateProccesWithLogonW
  2. CreateProccesWithLogonWShellrunas之间的区别是什么?
  3. Shellrunas如何在幕后工作?

0 个答案:

没有答案