在python中将ctypes结构传递给win32 API时出现memeory访问冲突错误

时间:2017-09-02 09:09:05

标签: python winapi ctypes

我在python中编写了一个简单的命令行应用程序,它通过调用win32 API创建一个新进程,当使用ctypes包装器调用函数CreateProcess时,应用程序退出并抛出内存访问冲突错误,代码如下: / p>

from ctypes import windll, byref, POINTER, GetLastError, Structure, sizeof,Union,pointer
from ctypes.wintypes import (
  LPCWSTR, LPWSTR, WCHAR, DWORD, HANDLE, BOOL,LPCVOID,ULONG,BYTE,WORD
)
import sys
import time
class STARTUPINFO(Structure):
    _field_=[("cb",DWORD),
    ("lpReserved",LPWSTR),
    ("lpDesktop",LPWSTR),
    ("lpTitle",LPWSTR),
    ("dwX",DWORD),
    ("dwY",DWORD),
    ("dwXSize",DWORD),
    ("dwYSize",DWORD),
    ("dwXCountChars",DWORD),
    ("dwYCountChars",DWORD),
    ("dwFillAttribute",DWORD),
    ("dwFlags",DWORD),
    ("wShowWindow",WORD),
    ("cbReserved2",WORD),
    ("lpReserved2",POINTER(BYTE)),
    ("hStdInput",HANDLE),
    ("hStdOutput",HANDLE),
    ("hStdError",HANDLE)]
class PROCESS_INFORMATION(Structure):
    _field_=[("hProcess",HANDLE),
    ("hThread",HANDLE),
    ("dwProcessId",DWORD),
    ("dwThreadId",DWORD)]
class SECURITY_ATTRIBUTES(Structure):
    _field_=[("nLength",DWORD),("lpSecurityDescriptor",LPCVOID)]

HANDLE_FLAG_INHERIT=0x1
STARTF_USESTDHANDLES=0x100
CreatePipe=windll.Kernel32.CreatePipe
CreatePipe.argtype=[POINTER(HANDLE),POINTER(HANDLE),POINTER(SECURITY_ATTRIBUTES),DWORD]
CreatePipe.restype=BOOL
SetHandleInformation=windll.Kernel32.SetHandleInformation
SetHandleInformation.argtype=[HANDLE,DWORD,DWORD]
SetHandleInformation.restype=BOOL
CloseHandle = windll.Kernel32.CloseHandle
CloseHandle.argtypes = [HANDLE]
CloseHandle.restype = BOOL
CreateProcess=windll.Kernel32.CreateProcessW
CreateProcess.argtypes=[LPCWSTR,LPWSTR,POINTER(SECURITY_ATTRIBUTES),POINTER(SECURITY_ATTRIBUTES),BOOL,DWORD,LPCVOID,LPCWSTR,POINTER(STARTUPINFO),POINTER(PROCESS_INFORMATION)]
CreateProcess.restype=BOOL
class test(object):
    def __init__(self):
        self.g_hChildStd_OUT_Rd=HANDLE()
        self.g_hChildStd_IN_Rd=HANDLE()
        self.g_hChildStd_OUT_Wr=HANDLE()
        self.g_hChildStd_IN_Wr=HANDLE()
    def CreateChildProcess(self):
        szCmdline = "c:\\windows\\System32\\cmd.exe"
        saAttr = SECURITY_ATTRIBUTES()
        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES)
        saAttr.bInheritHandle = True
        saAttr.lpSecurityDescriptor = None
        # Create a pipe for the child process's STDOUT.
        if not CreatePipe(byref(self.g_hChildStd_OUT_Rd), byref(self.g_hChildStd_OUT_Wr), byref(saAttr), 0):
            raise Exception("failed to create console process.")
        if not SetHandleInformation(self.g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0):
            raise Exception("failed to create console process.")
        # Create a pipe for the child process's STDIN.
        if not CreatePipe(byref(self.g_hChildStd_IN_Rd), byref(self.g_hChildStd_IN_Wr), byref(saAttr), 0):
            raise Exception("failed to create console process.")
        if not SetHandleInformation(self.g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0):
            raise Exception("failed to create console process.")
        piProcInfo = PROCESS_INFORMATION()
        siStartInfo = STARTUPINFO()
        siStartInfo.cb = sizeof(STARTUPINFO);
        siStartInfo.hStdError = self.g_hChildStd_OUT_Wr
        siStartInfo.hStdOutput = self.g_hChildStd_OUT_Wr
        siStartInfo.hStdInput = self.g_hChildStd_IN_Rd
        siStartInfo.dwFlags = STARTF_USESTDHANDLES
        piProcInfo.hProcess = None
        piProcInfo.hThread = None
        piProcInfo.dwProcessId = 0
        piProcInfo.dwThreadId = 0
        bSuccess = CreateProcess(szCmdline,  # executable name
                                 None,  # command line name
                                 None,  # primary process security attributes
                                 None,  # primary thread security attributes
                                 True,  # handles are inherited
                                 0,  # creation flags
                                 None,  # use parent's environment
                                 None,  # use parent's current directory
                                 byref(siStartInfo),  # STARTUPINFO pointer
                                 pointer(piProcInfo)) # child process's information.  piProcInfo struct won't be modified and not contain the child process infomation after this call if I use byref here. 
        if not bSuccess:
            rc = GetLastError()
            raise Exception("failed to create console process. error code %u" % rc)
        else:
            """// Close handles to the child process and its primary thread.
      // Some applications might keep these handles to monitor the status
      // of the child process, for example."""
            CloseHandle(piProcInfo.hProcess)
            CloseHandle(piProcInfo.hThread)
            print "[Info] Create cmd process successfully"
            #follows some codes to write to and read from pipes
if __name__=="__main__":
    obj=test()
    obj.CreateChildProcess()

stacktrace messeages是以下

Traceback (most recent call last):
  File "test01.py", line 104, in <module>
    obj.CreateChildProcess()
  File "test01.py", line 90, in CreateChildProcess
    pointer(piProcInfo)) # child process's information
WindowsError: exception: access violation reading 0x00000001

我猜这个错误信息的原因是参数piProcInfo对win32 API不可变,windows函数不能修改内存结构piProcInfo并且失败但是我不太确定我的猜测而且我不知道如何初始化一个可变的内存结构并将其作为参数传递给Windows API,任何人都可以帮我解决这个问题吗?

另外,我试图将byref(piProcInfo)作为参数传递,但是piProcInfo结构中的子进程信息没有改变,我需要这些信息以便进一步的步骤。

0 个答案:

没有答案