kernel32.CreateProcessW:Python在尝试访问进程信息结构时成功启动后崩溃

kernel32.CreateProcessW:Python在尝试访问进程信息结构时成功启动后崩溃,python,python-3.x,ctypes,Python,Python 3.x,Ctypes,经过相当长的一段时间,我试图运行一些解释调试工作原理的代码。这本书(“灰帽Python”)非常古老,是为32位系统和Python 2.7编写的 我正在使用Python3.4在Windows 8 64位上进行尝试。进程启动成功,但当我试图访问进程信息结构时,Python崩溃了。我在Windows7 64位上试过,它也崩溃了 在Eclipse中,我没有收到错误消息(在我的Windows 7计算机上也没有收到错误消息,Python.exe只是停止工作),但在Windows 8上我收到了错误消息(在Po

经过相当长的一段时间,我试图运行一些解释调试工作原理的代码。这本书(“灰帽Python”)非常古老,是为32位系统和Python 2.7编写的

我正在使用Python3.4在Windows 8 64位上进行尝试。进程启动成功,但当我试图访问
进程信息
结构时,Python崩溃了。我在Windows7 64位上试过,它也崩溃了

在Eclipse中,我没有收到错误消息(在我的Windows 7计算机上也没有收到错误消息,Python.exe只是停止工作),但在Windows 8上我收到了错误消息(在Powershell中):

电话一响就停了

我已经将问题中的更改应用于下面的代码,但没有效果

以下是我的定义:

from ctypes import *
from ctypes.wintypes import *

# Let's map the Microsoft types to ctypes for clarity
LPBYTE  = POINTER(BYTE)

# Constants
DEBUG_PROCESS = 0x00000001
CREATE_NEW_CONSOLE = 0x00000010

# Structures for CreateProcessA() function
class STARTUPINFOW(Structure):
    _fields = [
               ("cb",               DWORD),
               ("lpReserved",       LPWSTR),
               ("lpDesktop",        LPWSTR),
               ("lpTitle",          LPWSTR),
               ("dwX",              DWORD),
               ("dwY",              DWORD),
               ("dwXSize",          DWORD),
               ("dwYSize",          DWORD),
               ("dwXCountChars",    DWORD),
               ("dwYCountChars",    DWORD),
               ("dwFillAtrribute",  DWORD),
               ("dwFlags",          DWORD),
               ("wShowWindow",      WORD),
               ("cbReserved2",      WORD),
               ("lpReserved2",      LPBYTE),
               ("hStdInput",        HANDLE),
               ("hStdOutput",       HANDLE),
               ("hStdError",        HANDLE),
              ]
LPSTARTUPINFOW = POINTER(STARTUPINFOW)


class PROCESS_INFORMATION(Structure):
    _fields = [
               ("hProcess",         HANDLE),
               ("hThread",          HANDLE),
               ("dwProcessId",      DWORD),
               ("dwThreadId",       DWORD),
              ]
LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
以下是主要代码:

kernel32 = windll.kernel32

class Debugger():

    def __init__(self):
        '''
        Constructor
        '''
        pass

    def load(self, path_to_exe):

        # dwCreation flag determines how to create the process
        # set creation_flags = CREATE_NEW_CONSOLE if you want
        # to see the calculator GUI
        creation_flags = DEBUG_PROCESS

        # instantiate the structs
        startupinfo         = STARTUPINFOW()
        process_information = PROCESS_INFORMATION()

        # The following two optiions allow the started process
        # to be shown as a seperate window. This also illustrates
        # how different settings in the STARTUPINFO struct can affect
        # the debuggee.
        startupinfo.dwFlags     = 0x1
        startupinfo.wShowWindow = 0x0

        # We then initialize the cb variable in the STARTUPINFO struct
        # which is just the size of the struct itself
        startupinfo.cb = sizeof(startupinfo)

        print("[*] PROCESS_INFORMATION object: %s" % process_information)
        for count, field in enumerate(process_information._fields):
            print("[*] Field %d: %s" % (count, field))
        if kernel32.CreateProcessW(path_to_exe,
                                   None,
                                   None,
                                   None,
                                   None,
                                   creation_flags,
                                   None,
                                   None,
                                   byref(startupinfo),
                                   byref(process_information)):
            print("[*] We have successfully launched the process!")
            print("[*] PROCESS_INFORMATION object: %s" % process_information)
            for count, field in enumerate(process_information._fields):
                print("[*] Field %d: %s" % (count, field))
        else:
            print("[*] Error: 0x%08x." % kernel32.GetLastError())

        print("[*] Debugger finished.")
它的简称是:

import my_debugger

debugger = my_debugger.Debugger()

debugger.load("C:\\Windows\\System32\\calc.exe")
我承认我不适合这里,但你必须从某个地方开始。正如您从输出中看到的,在
CreateProcessW()
之前,我可以很好地访问该结构,但是在 成功启动流程后,结构似乎已损坏

为什么我的
流程信息
结构被破坏

我担心在看了几个小时之后,我就看不到一个打字错误了


非常感谢您的支持

您的结构定义指定给
\u字段
,而不是正确的属性名
\u字段
。要帮助捕获这样的输入错误,请定义
\uuuuuu slots\uuuu='\uuuuuu weakref\uuuu'
。这可以防止实例获取
\uuuu dict\uuuu
,但它保留了创建弱引用的能力。当然,如果您在
\uuuuu slots\uuuuuu>定义本身中有一个输入错误,那么这仍然是一个问题,因此一个较大的项目应该使用一个工厂函数来最小化由于输入错误而导致的错误,这些错误会悄悄地传递,直到进程神秘地崩溃

元类
\u ctypes.PyCStructType
在创建
结构
子类时为
\u字段
中的名称添加描述符,因此实例通常不需要
dict
。如果您意外地在属性名称中使用了
\u字段
或其他打字错误,则不会添加任何描述符。在这种情况下,访问字段将引发
AttributeError
。使用
\uuuuuuuuuu插槽\uuuuuuuu
还可以防止字段名中的键入错误创建实例属性

from ctypes import *

class Good(Structure):
    __slots__ = '__weakref__'
    _fields_ = [('a', c_int), 
                ('b', c_int)]

class Bad(Structure):
    __slots__ = '__weakref__'
    _fields = [('a', c_int), 
               ('b', c_int)]

>>> g = Good()
>>> g.a = 1
>>> g.c = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Good' object has no attribute 'c'

>>> b = Bad()
>>> b.a = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Bad' object has no attribute 'a'
从ctypes导入*
班级良好(结构):
__插槽\uuuuu='\uuuuu weakref\uuuuuuu'
_字段\=[('a',c_int),
('b',c_int)]
类别错误(结构):
__插槽\uuuuu='\uuuuu weakref\uuuuuuu'
_字段=[('a',c_int),
('b',c_int)]
>>>g=好()
>>>g.a=1
>>>g.c=1
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:“Good”对象没有属性“c”
>>>b=坏()
>>>b.a=1
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:“坏”对象没有属性“a”

注意:

  • bInheritHandles
    应该是
    0
    而不是
    None
    。如果定义了
    CreateProcessW.argtypes
    ,则传递
    None
    将是
    ArgumentError
    ,因为
    BOOL
    不是指针
  • CreationFlags
    应包括
    CREATE\u UNICODE\u环境
    。您正在为
    lpEnvironment
    传递
    NULL
    ,因此新进程继承了Python的unicode环境
  • 您可以
    raise WinError()
    ,而不是打印错误代码。这将引发一个
    OSError
    ,其中包含来自
    FormatError(GetLastError())
    的格式化错误消息

感谢您将我的问题重新编排为更易于阅读的格式,NorthCat!下次我问问题时,我会记得函数调用和填充的灰色背景。它是
\u字段
打字错误。非常感谢&对此感到抱歉。我可以把这个问题作为一个打字错误来结束吗?或者一个mod可以帮我完成吗?尽管命令行中的python和eclipse中的python在代码的不同部分停止工作,但这仍然让我感到困惑。我将把您的其他建议也应用到我的代码中,并将深入研究文档以了解每个参数的确切作用。我不知道如何在eclipse下工作。通常,在Windows ctypes中,在调用本机函数之前设置结构化异常处理程序。这将通过引发
OSError
来处理Windows异常,甚至是VC++异常。非常感谢您的帮助。
import my_debugger

debugger = my_debugger.Debugger()

debugger.load("C:\\Windows\\System32\\calc.exe")
from ctypes import *

class Good(Structure):
    __slots__ = '__weakref__'
    _fields_ = [('a', c_int), 
                ('b', c_int)]

class Bad(Structure):
    __slots__ = '__weakref__'
    _fields = [('a', c_int), 
               ('b', c_int)]

>>> g = Good()
>>> g.a = 1
>>> g.c = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Good' object has no attribute 'c'

>>> b = Bad()
>>> b.a = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Bad' object has no attribute 'a'