4

I'm working on a Windows 7 64 bit machine (I have admin privs).

I'm using Python 2.7 (64-bit) with PyDev ctypes for Eclipse to try and read the values of registers in all threads associated with a particular PID (tried both PIDs of processes running in 64 and 32 bit modes), but when I do this, the values for the registers are all zeroe'd out. When I use Wow64GetThreadContext, the call fails with GetLastError returning 0x00000057 ('invalid parameters' according to MSDN)

I attach to the process successfully, enumerate the threads (via CreateToolhelp32Snapshot), find the threads that are owned by the process with the appropriate PID, and attempt to get the thread context. Here is my code for opening the thread and getting the thread context:

Opening a thread:

def open_thread(self, thread_id):
    h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)

Getting context:

def get_thread_context(self, thread_id = None, h_thread = None):

    context = CONTEXT()
    context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS

    #alternatively, for 64
    context64 = WOW64_CONTEXT()
    context64.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS

    #Obtain a handle to the thread
    if h_thread is None:
        self.h_thread = self.open_thread(thread_id)

    kernel32.SuspendThread(self.h_thread)

    if kernel32.GetThreadContext(self.h_thread, byref(context)):
        kernel32.ResumeThread(self.h_thread)
        return context
    else:
        kernel32.ResumeThread(self.h_thread)
        return False

I call this code using:

debugger.attach(int(pid))

#debugger.run()

list = debugger.enumerate_threads()

for thread in list:
thread_context = debugger.get_thread_context(thread)

    if thread_context == False:
        print "[*] Thread context is false..."
    else:
        print "[*] Dumping registers for thread ID: 0x%08x" % thread
        print "[**] Eip: 0x%016x" % thread_context.Eip
        print "[**] Esp: 0x%016x" % thread_context.Esp
        print "[**] Ebp: 0x%016x" % thread_context.Ebp
        print "[**] Eax: 0x%016x" % thread_context.Eax
        print "[**] Ebx: 0x%016x" % thread_context.Ebx
        print "[**] Ecx: 0x%016x" % thread_context.Ecx
        print "[**] Edx: 0x%016x" % thread_context.Edx
        print "[*] End DUMP"

debugger.detach()

When I run this code using GetThreadContext with the CONTEXT structure, I get the context object back for each thread, but the register values are all zero.

I have tried replacing GetThreadContext with Wow64GetThreadContext (and respectively, SuspendThread with Wow64SuspendThread), but when I do this, the call fails with error 'invalid parameters'. The arguments I give to Wow64GetThreadContext are the same as those I give to GetThreadContext, other than the name of the variables in the code I provided (this is because when I looked at their definitions in WinNT.h, they were equivalent (unless I missed something). I've defined these structures the following way:

class WOW64_CONTEXT(Structure):
_fields_ = [

    ("ContextFlags", DWORD),
    ("Dr0", DWORD),
    ("Dr1", DWORD),
    ("Dr2", DWORD),
    ("Dr3", DWORD),
    ("Dr6", DWORD),
    ("Dr7", DWORD),
    ("FloatSave", WOW64_FLOATING_SAVE_AREA),
    ("SegGs", DWORD),
    ("SegFs", DWORD),
    ("SegEs", DWORD),
    ("SegDs", DWORD),
    ("Edi", DWORD),
    ("Esi", DWORD),
    ("Ebx", DWORD),
    ("Edx", DWORD),
    ("Ecx", DWORD),
    ("Eax", DWORD),
    ("Ebp", DWORD),
    ("Eip", DWORD),
    ("SegCs", DWORD),
    ("EFlags", DWORD),
    ("Esp", DWORD),
    ("SegSs", DWORD),
    ("ExtendedRegisters", BYTE * 512),
]

class WOW64_FLOATING_SAVE_AREA(Structure):
_fields_ = [

    ("ControlWord", DWORD),
    ("StatusWord", DWORD),
    ("TagWord", DWORD),
    ("ErrorOffset", DWORD),
    ("ErrorSelector", DWORD),
    ("DataOffset", DWORD),
    ("DataSelector", DWORD),
    ("RegisterArea", BYTE * 80),
    ("Cr0NpxState", DWORD),
]

class CONTEXT(Structure):
_fields_ = [

    ("ContextFlags", DWORD),
    ("Dr0", DWORD),
    ("Dr1", DWORD),
    ("Dr2", DWORD),
    ("Dr3", DWORD),
    ("Dr6", DWORD),
    ("Dr7", DWORD),
    ("FloatSave", FLOATING_SAVE_AREA),
    ("SegGs", DWORD),
    ("SegFs", DWORD),
    ("SegEs", DWORD),
    ("SegDs", DWORD),
    ("Edi", DWORD),
    ("Esi", DWORD),
    ("Ebx", DWORD),
    ("Edx", DWORD),
    ("Ecx", DWORD),
    ("Eax", DWORD),
    ("Ebp", DWORD),
    ("Eip", DWORD),
    ("SegCs", DWORD),
    ("EFlags", DWORD),
    ("Esp", DWORD),
    ("SegSs", DWORD),
    ("ExtendedRegisters", BYTE * 512),
]

class FLOATING_SAVE_AREA(Structure):
_fields_ = [

    ("ControlWord", DWORD),
    ("StatusWord", DWORD),
    ("TagWord", DWORD),
    ("ErrorOffset", DWORD),
    ("ErrorSelector", DWORD),
    ("DataOffset", DWORD),
    ("DataSelector", DWORD),
    ("RegisterArea", BYTE * 80),
    ("Cr0NpxState", DWORD),
]

I've done a fair amount of googling on this issue, and have tried the following to no avail:

  • According to a comment on the MSDN: CONTEXT_FULL should be CONTEXT_AMD64 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT to be used with Win64 properly.

  • I've tried renaming the registers inside my CONTEXT and WOW_64CONTEXT structures by replacing the 'E' in the register names with 'R' (Eax -> Rax, etc.)

Has anyone else used Python with ctypes to successfully get the context of a 64-bit thread on Windows?

4

3 回答 3

5

您的主要问题是 WOW64 实际上是 32 位上下文,而不是 64 位。您需要实现一个 64 位结构,类似于以下内容:

class CONTEXT64(Structure):
_pack_ = 16
_fields_ = [
    ("P1Home", DWORD64),
    ("P2Home", DWORD64),
    ("P3Home", DWORD64),
    ("P4Home", DWORD64),
    ("P5Home", DWORD64),
    ("P6Home", DWORD64),

    ("ContextFlags", DWORD),
    ("MxCsr", DWORD),

    ("SegCs", WORD),
    ("SegDs", WORD),
    ("SegEs", WORD),
    ("SegFs", WORD),
    ("SegGs", WORD),
    ("SegSs", WORD),
    ("EFlags", DWORD),

    ("Dr0", DWORD64),
    ("Dr1", DWORD64),
    ("Dr2", DWORD64),
    ("Dr3", DWORD64),
    ("Dr6", DWORD64),
    ("Dr7", DWORD64),

    ("Rax", DWORD64),
    ("Rcx", DWORD64),
    ("Rdx", DWORD64),
    ("Rbx", DWORD64),
    ("Rsp", DWORD64),
    ("Rbp", DWORD64),
    ("Rsi", DWORD64),
    ("Rdi", DWORD64),
    ("R8", DWORD64),
    ("R9", DWORD64),
    ("R10", DWORD64),
    ("R11", DWORD64),
    ("R12", DWORD64),
    ("R13", DWORD64),
    ("R14", DWORD64),
    ("R15", DWORD64),
    ("Rip", DWORD64),

    ("DebugControl", DWORD64),
    ("LastBranchToRip", DWORD64),
    ("LastBranchFromRip", DWORD64),
    ("LastExceptionToRip", DWORD64),
    ("LastExceptionFromRip", DWORD64),

    ("DUMMYUNIONNAME", DUMMYUNIONNAME),

    ("VectorRegister", M128A * 26),
    ("VectorControl", DWORD64)
]

注意:此定义位于 WinNT.h 中——如果您安装了 VC++,它将位于安装它的 /include 目录中。

一旦谁建立了这个结构,你就可以使用它而不是你已经建立的 CONTEXT / WOW64 CONTEXT。您还必须显然将寄存器更改为 RAX 等。

(注意:您还必须在 Python ctypes 中实现 4 个其他内容:DWORD64、M128A、DUMMYUNIONNAME、DUMMYSTRUCTNAME 和 XMM_SAVE_AREA32。为简洁起见,我已将它们排除在外,但您可以在以下位置找到它们的定义来构建他们自己:

DWORD64:只是一个 c_ulonglong

DUMMYUNIONNAME、DUMMYSTRUCTNAME:在 WinNT.h 中的 _CONTEXT 结构中

M128A:http ://winappdbg.sourceforge.net/doc/v1.3/winappdbg.win32.defines.M128A-class.html

XMM_SAVE_AREA32:http ://winappdbg.sourceforge.net/doc/v1.3/winappdbg.win32.context_amd64.XMM_SAVE_AREA32-class.html

于 2013-09-04T19:25:00.230 回答
2

我也有这个问题,我现在有这个工作,我假设这是来自 Grey Hat python 书,经过大量谷歌搜索后,Wow64GetThreadContext 似乎用于在 64 位系统上检索 32 位线程上下文,我使用了原始的 GetThreadContext 函数但我给它传递了一个定义如下的 Wow64Context 结构:

class M128A(Structure):
    _fields_ = [
            ("Low", DWORD64),
            ("High", DWORD64)
            ] 

class XMM_SAVE_AREA32(Structure):
    _pack_ = 1 
    _fields_ = [  
                ('ControlWord', WORD), 
                ('StatusWord', WORD), 
                ('TagWord', BYTE), 
                ('Reserved1', BYTE), 
                ('ErrorOpcode', WORD), 
                ('ErrorOffset', DWORD), 
                ('ErrorSelector', WORD), 
                ('Reserved2', WORD), 
                ('DataOffset', DWORD), 
                ('DataSelector', WORD), 
                ('Reserved3', WORD), 
                ('MxCsr', DWORD), 
                ('MxCsr_Mask', DWORD), 
                ('FloatRegisters', M128A * 8), 
                ('XmmRegisters', M128A * 16), 
                ('Reserved4', BYTE * 96)
                ] 

class DUMMYSTRUCTNAME(Structure):
    _fields_=[
              ("Header", M128A * 2),
              ("Legacy", M128A * 8),
              ("Xmm0", M128A),
              ("Xmm1", M128A),
              ("Xmm2", M128A),
              ("Xmm3", M128A),
              ("Xmm4", M128A),
              ("Xmm5", M128A),
              ("Xmm6", M128A),
              ("Xmm7", M128A),
              ("Xmm8", M128A),
              ("Xmm9", M128A),
              ("Xmm10", M128A),
              ("Xmm11", M128A),
              ("Xmm12", M128A),
              ("Xmm13", M128A),
              ("Xmm14", M128A),
              ("Xmm15", M128A)
              ]


class DUMMYUNIONNAME(Union):
    _fields_=[
              ("FltSave", XMM_SAVE_AREA32),
              ("DummyStruct", DUMMYSTRUCTNAME)
              ]

class CONTEXT64(Structure):
    _pack_ = 16
    _fields_ = [
                ("P1Home", DWORD64),
                ("P2Home", DWORD64),
                ("P3Home", DWORD64),
                ("P4Home", DWORD64),
                ("P5Home", DWORD64),
                ("P6Home", DWORD64),
                ("ContextFlags", DWORD),
                ("MxCsr", DWORD),
                ("SegCs", WORD),
                ("SegDs", WORD),
                ("SegEs", WORD),
                ("SegFs", WORD),
                ("SegGs", WORD),
                ("SegSs", WORD),
                ("EFlags", DWORD),
                ("Dr0", DWORD64),
                ("Dr1", DWORD64),
                ("Dr2", DWORD64),
                ("Dr3", DWORD64),
                ("Dr6", DWORD64),
                ("Dr7", DWORD64),
                ("Rax", DWORD64),
                ("Rcx", DWORD64),
                ("Rdx", DWORD64),
                ("Rbx", DWORD64),
                ("Rsp", DWORD64),
                ("Rbp", DWORD64),
                ("Rsi", DWORD64),
                ("Rdi", DWORD64),
                ("R8", DWORD64),
                ("R9", DWORD64),
                ("R10", DWORD64),
                ("R11", DWORD64),
                ("R12", DWORD64),
                ("R13", DWORD64),
                ("R14", DWORD64),
                ("R15", DWORD64),
                ("Rip", DWORD64),
                ("DebugControl", DWORD64),
                ("LastBranchToRip", DWORD64),
                ("LastBranchFromRip", DWORD64),
                ("LastExceptionToRip", DWORD64),
                ("LastExceptionFromRip", DWORD64),
                ("DUMMYUNIONNAME", DUMMYUNIONNAME),
                ("VectorRegister", M128A * 26),
                ("VectorControl", DWORD64)
]

当然,我还没有检查寄存器中返回的值是正确的还是只是垃圾,但是值在那里而不是 0x00000000 或错误 0x57 的事实令人放心。

访问寄存器仍然是通过 thread_context.Rip 等完成,而不是 eip

于 2013-09-15T16:10:09.507 回答
1

检查 ContextFlags 常量的值。我从 python 模块 win32con 获得的值错过了与架构相关的位。这是我的 WinNT.h 的摘录(来自 Windows SDK Server2003SP1):

#define CONTEXT_AMD64   0x100000

// end_wx86

#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L)
#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L)
#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L)
#define CONTEXT_FLOATING_POINT  (CONTEXT_AMD64 | 0x8L)
#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L)

#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)

#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)

[...]

#define CONTEXT_i386    0x00010000    // this assumes that i386 and
#define CONTEXT_i486    0x00010000    // i486 have identical context records

// end_wx86

#define CONTEXT_CONTROL         (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
#define CONTEXT_INTEGER         (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
#define CONTEXT_SEGMENTS        (CONTEXT_i386 | 0x00000004L) // DS, ES, FS, GS
#define CONTEXT_FLOATING_POINT  (CONTEXT_i386 | 0x00000008L) // 387 state
#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) // DB 0-3,6,7
#define CONTEXT_EXTENDED_REGISTERS  (CONTEXT_i386 | 0x00000020L) // cpu specific extensions

#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER |\
                      CONTEXT_SEGMENTS)

#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS)

如果它不适合您,请检查您的 Windows 版本的 WinNT.h。

于 2013-09-22T12:35:16.523 回答