调用CreateProcessWithLogonW后,Python崩溃

2024-10-04 01:33:04 发布

您现在位置:Python中文网/ 问答频道 /正文

使用找到的代码here可以作为备用用户成功启动应用程序。但是,应用程序启动后,Python崩溃,Windows显示“python.exe已经停止工作”。它似乎只在函数完成调用后发生,但似乎不是由函数内的任何东西引起的。在

import ctypes, sys
from ctypes import Structure, sizeof

NULL  = 0
TRUE  = 1
FALSE = 0

INVALID_HANDLE_VALUE = -1

WORD   = ctypes.c_ushort
DWORD  = ctypes.c_uint
LPSTR  = ctypes.c_char_p
LPBYTE = LPSTR
HANDLE = DWORD

# typedef struct _PROCESS_INFORMATION {
#     HANDLE hProcess;
#     HANDLE hThread;
#     DWORD dwProcessId;
#     DWORD dwThreadId;
# } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
class PROCESS_INFORMATION(Structure):
   _pack_   = 1
   _fields_ = [
       ('hProcess',    HANDLE),
       ('hThread',     HANDLE),
       ('dwProcessId', DWORD),
       ('dwThreadId',  DWORD),
   ]

# typedef struct _STARTUPINFO {
#     DWORD   cb;
#     LPSTR   lpReserved;
#     LPSTR   lpDesktop;
#     LPSTR   lpTitle;
#     DWORD   dwX;
#     DWORD   dwY;
#     DWORD   dwXSize;
#     DWORD   dwYSize;
#     DWORD   dwXCountChars;
#     DWORD   dwYCountChars;
#     DWORD   dwFillAttribute;
#     DWORD   dwFlags;
#     WORD    wShowWindow;
#     WORD    cbReserved2;
#     LPBYTE  lpReserved2;
#     HANDLE  hStdInput;
#     HANDLE  hStdOutput;
#     HANDLE  hStdError;
# } STARTUPINFO, *LPSTARTUPINFO;
class STARTUPINFO(Structure):
   _pack_   = 1
   _fields_ = [
       ('cb',              DWORD),
       ('lpReserved',      DWORD),     # LPSTR
       ('lpDesktop',       LPSTR),
       ('lpTitle',         LPSTR),
       ('dwX',             DWORD),
       ('dwY',             DWORD),
       ('dwXSize',         DWORD),
       ('dwYSize',         DWORD),
       ('dwXCountChars',   DWORD),
       ('dwYCountChars',   DWORD),
       ('dwFillAttribute', DWORD),
       ('dwFlags',         DWORD),
       ('wShowWindow',     WORD),
       ('cbReserved2',     WORD),
       ('lpReserved2',     DWORD),     # LPBYTE
       ('hStdInput',       DWORD),
       ('hStdOutput',      DWORD),
       ('hStdError',       DWORD),
   ]

# BOOL WINAPI CreateProcessWithLogonW(
#   __in         LPCWSTR lpUsername,
#   __in_opt     LPCWSTR lpDomain,
#   __in         LPCWSTR lpPassword,
#   __in         DWORD dwLogonFlags,
#   __in_opt     LPCWSTR lpApplicationName,
#   __inout_opt  LPWSTR lpCommandLine,
#   __in         DWORD dwCreationFlags,
#   __in_opt     LPVOID lpEnvironment,
#   __in_opt     LPCWSTR lpCurrentDirectory,
#   __in         LPSTARTUPINFOW lpStartupInfo,
#   __out        LPPROCESS_INFORMATION lpProcessInfo
# );
def CreateProcessWithLogonW(lpUsername = None, lpDomain = None, lpPassword =
None, dwLogonFlags = 0, lpApplicationName = None, lpCommandLine = None,
dwCreationFlags = 0, lpEnvironment = None, lpCurrentDirectory = None,
lpStartupInfo = None):
   if not lpUsername:
       lpUsername          = NULL
   else:
       lpUsername          = ctypes.c_wchar_p(lpUsername)
   if not lpDomain:
       lpDomain            = NULL
   else:
       lpDomain            = ctypes.c_wchar_p(lpDomain)
   if not lpPassword:
       lpPassword          = NULL
   else:
       lpPassword          = ctypes.c_wchar_p(lpPassword)
   if not lpApplicationName:
       lpApplicationName   = NULL
   else:
       lpApplicationName   = ctypes.c_wchar_p(lpApplicationName)
   if not lpCommandLine:
       lpCommandLine       = NULL
   else:
       lpCommandLine       = ctypes.create_unicode_buffer(lpCommandLine)
   if not lpEnvironment:
       lpEnvironment       = NULL
   else:
       lpEnvironment       = ctypes.c_wchar_p(lpEnvironment)
   if not lpCurrentDirectory:
       lpCurrentDirectory  = NULL
   else:
       lpCurrentDirectory  = ctypes.c_wchar_p(lpCurrentDirectory)
   if not lpStartupInfo:
       lpStartupInfo              = STARTUPINFO()
       lpStartupInfo.cb           = sizeof(STARTUPINFO)
       lpStartupInfo.lpReserved   = 0
       lpStartupInfo.lpDesktop    = 0
       lpStartupInfo.lpTitle      = 0
       lpStartupInfo.dwFlags      = 0
       lpStartupInfo.cbReserved2  = 0
       lpStartupInfo.lpReserved2  = 0
   lpProcessInformation              = PROCESS_INFORMATION()
   lpProcessInformation.hProcess     = INVALID_HANDLE_VALUE
   lpProcessInformation.hThread      = INVALID_HANDLE_VALUE
   lpProcessInformation.dwProcessId  = 0
   lpProcessInformation.dwThreadId   = 0
   success = ctypes.windll.advapi32.CreateProcessWithLogonW(lpUsername,
lpDomain, lpPassword, dwLogonFlags, lpApplicationName,
ctypes.byref(lpCommandLine), dwCreationFlags, lpEnvironment,
lpCurrentDirectory, ctypes.byref(lpStartupInfo),
ctypes.byref(lpProcessInformation))
   if success == FALSE:
       raise ctypes.WinError()
   #A raw_input or other blocking function here will prevent python from crashing until continuing
   return lpProcessInformation #Happens whether or not this is returned

CreateProcessWithLogonW("User", "Domain", "Password", 0, None, "C:\\Windows\\notepad.exe")
print("Test") #This will never be reached

正如我在代码中所说的,如果阻止函数的结尾被到达,则不会发生崩溃。范围返回函数外部后的任何内容都将无法访问,并且python.exe会崩溃的。在

我尝试过的一种解决方法是在函数末尾使用taskkill来终止python.exe通过其PID进行处理。这确实防止了错误消息按预期发生,但并不理想,因为它还会杀死任何子进程(包括成功启动的进程)。我无法找出完成函数调用会导致Python崩溃的任何原因。Python2.7和3.x中都会出现这种情况,如有任何建议,我们将不胜感激。在


Tags: innoneifinformationnotctypesnullhandle
1条回答
网友
1楼 · 发布于 2024-10-04 01:33:04

在64位Windows上,对HANDLE使用32位DWORD或任何其他指针类型是不正确的。ctypes.wintypes模块定义可在32位和64位窗口上工作的类型。如果它缺少特定类型,您可能可以在Windows Data Types中找到定义。在

设置_pack_ = 1错误地使用1字节对齐,而不是使用本机对齐填充。另外,STARTUPINFOW应该使用LPWSTR,而不是{}。在

尝试重写:

import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)

CREATE_NEW_CONSOLE         = 0x00000010
CREATE_NO_WINDOW           = 0x08000000
DETACHED_PROCESS           = 0x00000008
CREATE_NEW_PROCESS_GROUP   = 0x00000200
CREATE_UNICODE_ENVIRONMENT = 0x00000400

if not hasattr(wintypes, 'LPBYTE'):
    wintypes.LPBYTE = ctypes.POINTER(wintypes.BYTE)

class HANDLE(wintypes.HANDLE):

    def detach(self):
        handle, self.value = self.value, None
        return wintypes.HANDLE(handle)

    def close(self, CloseHandle=kernel32.CloseHandle):
        if self:
            CloseHandle(self.detach())

    def __del__(self):
        self.close()

class PROCESS_INFORMATION(ctypes.Structure):
    """http://msdn.microsoft.com/en-us/library/ms684873"""
    _fields_ = (('hProcess',    HANDLE),
                ('hThread',     HANDLE),
                ('dwProcessId', wintypes.DWORD),
                ('dwThreadId',  wintypes.DWORD))

LPPROCESS_INFORMATION = ctypes.POINTER(PROCESS_INFORMATION)

class STARTUPINFOW(ctypes.Structure):
    """http://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',     wintypes.LPBYTE),
                ('hStdInput',       wintypes.HANDLE),
                ('hStdOutput',      wintypes.HANDLE),
                ('hStdError',       wintypes.HANDLE))

    def __init__(self, *args, **kwds):
        self.cb = ctypes.sizeof(self)
        super(STARTUPINFOW, self).__init__(*args, **kwds)

LPSTARTUPINFOW = ctypes.POINTER(STARTUPINFOW)

def _check_bool(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

# http://msdn.microsoft.com/en-us/library/ms682431
advapi32.CreateProcessWithLogonW.errcheck = _check_bool
advapi32.CreateProcessWithLogonW.argtypes = (
    wintypes.LPCWSTR,      # lpUsername
    wintypes.LPCWSTR,      # lpDomain
    wintypes.LPCWSTR,      # lpPassword
    wintypes.DWORD,        # dwLogonFlags
    wintypes.LPCWSTR,      # lpApplicationName
    wintypes.LPWSTR,       # lpCommandLine (inout)
    wintypes.DWORD,        # dwCreationFlags
    wintypes.LPCWSTR,      # lpEnvironment  (force Unicode)
    wintypes.LPCWSTR,      # lpCurrentDirectory
    LPSTARTUPINFOW,        # lpStartupInfo
    LPPROCESS_INFORMATION) # lpProcessInfo (out)

^{pr2}$
if __name__ == '__main__':
    import os
    import getpass
    username = input('username: ')
    password = getpass.getpass('password: ')
    exe = os.environ['ComSpec']
    cflags = CREATE_NEW_CONSOLE
    hProcess, hThread, pid, tid = CreateProcessWithLogonW(
            username, password, executable=exe, creationflags=cflags)
    print('PID: %d' % pid)

相关问题 更多 >