调用CreateProcessWithLogonW后,Python崩溃 [英] Python Crashes After Call to CreateProcessWithLogonW
问题描述
使用在此处找到的代码,以备用用户身份启动应用程序.但是,启动该应用程序后,Python崩溃,并且Windows显示"python.exe已停止工作".它似乎仅在函数完成调用后才发生,但似乎不是由函数中的任何内容引起的.
Using the code found here one can successfully launch an application as an alternate user. However, after the application is launched Python crashes, and Windows displays "python.exe has stopped working". It seems to only happen after the function has been finished calling, but does not seem to be caused by anything within the function.
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将崩溃.
As I commented in the code, if you prevent the end of the function from being reached the crash does not occur. Anything after the scope returns to outside of the function will not be reached and python.exe will crash.
我尝试过的一种解决方法是在函数末尾使用taskkill来通过其PID杀死python.exe进程.这确实防止了错误消息的出现,但并不理想,因为它还会杀死所有子进程(包括成功启动的子进程).我无法弄清楚完成函数调用会导致Python崩溃的任何原因.在Python 2.7和3.x中都会发生这种情况.任何建议都将不胜感激.
A workaround that I have tried is to use taskkill at the end of the function to kill the python.exe process by its PID. This did prevent the error message from occurring as expected, but less than ideal as it also kills any child processes (including the one that successfully launches). I cannot figure out any reason why completing the function call would cause Python to crash. This occurs both in Python 2.7 and 3.x. Any suggestions are greatly appreciated.
推荐答案
在32位 DWORD
中使用 HANDLE
或任何其他指针类型,在64位Windows. ctypes.wintypes
模块定义可在32位和64位Windows上运行的类型.如果缺少特定类型,则可以在 Windows数据类型.
Using a 32-bit DWORD
for a HANDLE
, or any other pointer type, is incorrect on 64-bit Windows. The ctypes.wintypes
module defines types that work on both 32-bit and 64-bit Windows. If it lacks a particular type, you can probably find the definition in Windows Data Types.
设置 _pack_ = 1
会错误地使用1字节对齐方式,而不是使用本机对齐方式进行填充.另外, STARTUPINFOW
应该使用 LPWSTR
而不是 LPSTR
.
Setting _pack_ = 1
incorrectly uses 1-byte alignment instead of padding with native alignment. Also, STARTUPINFOW
should use LPWSTR
instead of LPSTR
.
尝试重写:
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)
def CreateProcessWithLogonW(username, password, domain=None, logonflags=0,
executable=None, commandline=None, creationflags=0,
env=None, cwd=None, startupinfo=None):
if commandline is not None:
commandline = ctypes.create_unicode_buffer(commandline)
creationflags |= CREATE_UNICODE_ENVIRONMENT
if startupinfo is None:
startupinfo = STARTUPINFOW()
pi = PROCESS_INFORMATION()
advapi32.CreateProcessWithLogonW(username, domain, password, logonflags,
executable, commandline, creationflags,
env, cwd, ctypes.byref(startupinfo),
ctypes.byref(pi))
return pi.hProcess, pi.hThread, pi.dwProcessId, pi.dwThreadId
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)
这篇关于调用CreateProcessWithLogonW后,Python崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!