首页 > 解决方案 > 使用 python / ctypes 调用 GetThreadContext winapi

问题描述

我目前正在开发一个 Python/Winapi 项目。
我想用 Python 和 ctypes 调用 Get- 和 SetThreadContext。
我的设置是 Windows10 64 位和 Python 64 位。API 应该适用于 32 位和 64 位进程。

通过使用 WOW64Context 调用 Wow64GetThreadContext,它确实适用于 32 位进程。
但是,对于 64 位进程和 Get/SetThreadContex,它不起作用。

GetLastError 确实显示 87(参数不正确。)
可能我的 Context64 的实现是错误的,但我找不到错误。
我还使用https://github.com/MarioVilas/winappdbg
的实现进行了尝试, 这两个实现都使用 ctypes.sizeof(ctx) 显示了 1232 的大小。

我当前对 x64 的 CONTEXT 实现:

WORD        = ctypes.c_ushort
BYTE        = ctypes.c_ubyte
DWORD64     = ctypes.c_ulonglong

CONTEXT_AMD64           = 0x00100000
CONTEXT_CONTROL         = (CONTEXT_AMD64 | 0x00000001)
CONTEXT_INTEGER         = (CONTEXT_AMD64 | 0x00000002)
CONTEXT_SEGMENTS        = (CONTEXT_AMD64 | 0x00000004)
CONTEXT_FLOATING_POINT  = (CONTEXT_AMD64 | 0x00000008)
CONTEXT_DEBUG_REGISTERS = (CONTEXT_AMD64 | 0x00000010)
CONTEXT_MMX_REGISTERS   = CONTEXT_FLOATING_POINT
CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS |
                CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
CONTEXT_EXCEPTION_ACTIVE    = 0x0000000008000000
CONTEXT_SERVICE_ACTIVE      = 0x0000000010000000
CONTEXT_EXCEPTION_REQUEST   = 0x0000000040000000
CONTEXT_EXCEPTION_REPORTING = 0x0000000080000000


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

class XMM_SAVE_AREA32(ctypes.Structure):
    _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(ctypes.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(ctypes.Union):
    _fields_=[
              ("FltSave", XMM_SAVE_AREA32),
              ("DummyStruct", DUMMYSTRUCTNAME)
              ]

class CONTEXT64(ctypes.Structure):
    _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)
]

我的代码实现:

KERNEL32 = ctypes.windll.kernel32
ctx = constants.CONTEXT64()
ctx.ContextFlags = constants.CONTEXT_FULL
_GetThreadContext = KERNEL32.GetThreadContext
_GetThreadContext.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
_GetThreadContext.restype = ctypes.c_uint
_SetThreadContext = KERNEL32.SetThreadContext
_SetThreadContext.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
_SetThreadContext.restype = ctypes.c_uint

if KERNEL32.SuspendThread(thandle) == -1:
   print("[!] Failed to suspend thread, exit...")
   print("[!] Last error code: " + str(KERNEL32.GetLastError()))
   sys.exit(0)
if not _GetThreadContext(thandle, ctypes.byref(ctx)):
   print("[!] Failed to get thread context, exit...")
   print("[!] Last error code: " + str(KERNEL32.GetLastError()))
   sys.exit(0)

注意:我使用记事本进行测试,因为目标进程(也尝试使用 puttyx64)
thdle 已经过测试,并且可以与其他调用和挂起一起使用。
thandle 确实具有以下权限 (0x0400 | 0x0010 | 0x0020 | 0x0008 | 0x0002 | 0x0040 | 0x0800)。
没有 Python 错误

我在这里做错了什么?

谢谢

编辑:最小(不)工作示例(notepad.exe 必须运行)

import ctypes
import time
import sys

WORD = ctypes.c_ushort
BYTE = ctypes.c_ubyte
DWORD64 = ctypes.c_ulonglong
DWORD = ctypes.c_uint
ULONG = ctypes.c_ulong
LONG = ctypes.c_long
CHAR = ctypes.c_char

CONTEXT_AMD64           = 0x00100000
CONTEXT_CONTROL         = (CONTEXT_AMD64 | 0x00000001)
CONTEXT_INTEGER         = (CONTEXT_AMD64 | 0x00000002)
CONTEXT_SEGMENTS        = (CONTEXT_AMD64 | 0x00000004)
CONTEXT_FLOATING_POINT  = (CONTEXT_AMD64 | 0x00000008)
CONTEXT_DEBUG_REGISTERS = (CONTEXT_AMD64 | 0x00000010)
CONTEXT_MMX_REGISTERS   = CONTEXT_FLOATING_POINT
CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS |
                CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
CONTEXT_EXCEPTION_ACTIVE    = 0x0000000008000000
CONTEXT_SERVICE_ACTIVE      = 0x0000000010000000
CONTEXT_EXCEPTION_REQUEST   = 0x0000000040000000
CONTEXT_EXCEPTION_REPORTING = 0x0000000080000000


class PROCESSENTRY32(ctypes.Structure):
    _fields_ = [
        ('dwSize',              DWORD),
        ('cntUsage',            DWORD),
        ('th32ProcessID',       DWORD),
        ('th32DefaultHeapID',   ctypes.POINTER(ULONG)),
        ('th32ModuleID',        DWORD),
        ('cntThreads',          DWORD),
        ('th32ParentProcessID', DWORD),
        ('pcPriClassBase',      LONG),
        ('dwFlags',             DWORD),
        ('szExeFile',           CHAR * 260)
    ]

class THREADENTRY32(ctypes.Structure):
    _fields_ = [
        ('dwSize',              DWORD),
        ('cntUsage',            DWORD),
        ('th32ThreadID',        DWORD),
        ('th32OwnerProcessID',  DWORD),
        ('tpBasePri',           DWORD),
        ('tpDeltaPri',          DWORD),
        ('dwFlags',             DWORD)
    ]


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

class XMM_SAVE_AREA32(ctypes.Structure):
    _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(ctypes.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(ctypes.Union):
    _fields_=[
              ("FltSave", XMM_SAVE_AREA32),
              ("DummyStruct", DUMMYSTRUCTNAME)
              ]

class CONTEXT64(ctypes.Structure):
    _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)
]

KERNEL32 = ctypes.WinDLL('kernel32', use_last_error=True)
PSAPI = ctypes.WinDLL('psapi', use_last_error=True)
name = "notepad.exe"

hSnapshot = KERNEL32.CreateToolhelp32Snapshot(0x00000002 | 0x00000004, 0)
pe32 = PROCESSENTRY32()
pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
processes = []
if KERNEL32.Process32First(hSnapshot, ctypes.byref(pe32)):
    while True:
        processes.append({'pid': pe32.th32ProcessID, 'name': pe32.szExeFile})
        if not KERNEL32.Process32Next(hSnapshot, ctypes.byref(pe32)):
            break

for n in processes:
    if n['name'] == bytes(name, "utf-8"):
        pid = n['pid']
if not pid:
    sys.exit(0)

te32 = THREADENTRY32()
te32.dwSize = ctypes.sizeof(THREADENTRY32)
threads = []
if KERNEL32.Thread32First(hSnapshot, ctypes.byref(te32)):
    while True:
        if te32.th32OwnerProcessID == pid:
            threads.append(te32.th32ThreadID)
        if not KERNEL32.Thread32Next(hSnapshot, ctypes.byref(te32)):
            break

access = (0x0400 | 0x0010 | 0x0020 | 0x0008 | 0x0002 | 0x0040 | 0x0800)
thandle = KERNEL32.OpenThread(access, 0, threads[0])
ctx = CONTEXT64()
ctx.ContextFlags = CONTEXT_FULL
_GetThreadContext = KERNEL32.GetThreadContext
_GetThreadContext.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
_GetThreadContext.restype = ctypes.c_uint
_SetThreadContext = KERNEL32.SetThreadContext
_SetThreadContext.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
_SetThreadContext.restype = ctypes.c_uint
if KERNEL32.SuspendThread(thandle) == -1:
    print("[!] Failed to suspend thread, exit...")
    print("[!] Last error code: " + str(ctypes.get_last_error()))
    sys.exit(0)
if not _GetThreadContext(thandle, ctypes.byref(ctx)):
    print("[!] Failed to get thread context, exit...")
    print("[!] Last error code: " + str(ctypes.get_last_error()))
    sys.exit(0)
if not _SetThreadContext(thandle, ctypes.byref(ctx)):
    print("[!] Failed to set thread context, exit...")
    print("[!] Last error code: " + str(ctypes.get_last_error()))
    sys.exit(0)

标签: pythonwindowswinapi64-bitctypes

解决方案


推荐阅读