unable to get thread context of an suspended process'

1

so, i am trying to write a script in python by which i can get the different register's value of a thread as well as also get the imagebase address and other different values which are related to process's PEB header. till now i wrote script by which i can create a process in suspended mode and passing the thread handle to GetThreadContext() function, but it returns ebx register's value 0. i've tried context structure for both x86 and x64 but no luck.

here is the code snippet:

from ctypes import *
from ctypes.wintypes import *
import os,sys

target_exe = 'c:\\windows\\system32\\calc.exe'

LPDWORD = POINTER(DWORD)
LPHANDLE = POINTER(HANDLE)
ULONG_PTR = POINTER(ULONG)

class SECURITY_ATTRIBUTES(Structure):
    _fields_ = [("nLength", DWORD),
                ("lpSecurityDescriptor", LPVOID),
                ("bInheritHandle", BOOL)]
LPSECURITY_ATTRIBUTES = POINTER(SECURITY_ATTRIBUTES)
DWORD64 = 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(Structure):
    _fields_ = [
            ("Low", DWORD64),
            ("High", DWORD64)
            ]

class XMM_SAVE_AREA32(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(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):
    _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)
]

SIZE_OF_80387_REGISTERS     = 80
MAXIMUM_SUPPORTED_EXTENSION = 512





class FLOATING_SAVE_AREA(Structure):
    _pack_ = 1
    _fields_ = [
        ('ControlWord',     DWORD),
        ('StatusWord',      DWORD),
        ('TagWord',         DWORD),
        ('ErrorOffset',     DWORD),
        ('ErrorSelector',   DWORD),
        ('DataOffset',      DWORD),
        ('DataSelector',    DWORD),
        ('RegisterArea',    BYTE * SIZE_OF_80387_REGISTERS),
        ('Cr0NpxState',     DWORD),
    ]
PFLOATING_SAVE_AREA = POINTER(FLOATING_SAVE_AREA)
LPFLOATING_SAVE_AREA = PFLOATING_SAVE_AREA
    
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),         # MUST BE SANITIZED
        ('EFlags',              DWORD),         # MUST BE SANITIZED
        ('Esp',                 DWORD),
        ('SegSs',               DWORD),
        ('ExtendedRegisters',   BYTE * MAXIMUM_SUPPORTED_EXTENSION),
    ]


class PROCESS_INFORMATION(Structure):
    _fields_ = [
                ('hProcess', c_void_p), 
                ('hThread', c_void_p), 
                ('dwProcessId', c_ulong), 
                ('dwThreadId', c_ulong)]

    

class STARTUPINFO(Structure):
    _fields_ = [
                ('cb', c_ulong), 
                ('lpReserved', c_char_p),    
                ('lpDesktop', c_char_p),
                ('lpTitle', c_char_p),
                ('dwX', c_ulong),
                ('dwY', c_ulong),
                ('dwXSize', c_ulong),
                ('dwYSize', c_ulong),
                ('dwXCountChars', c_ulong),
                ('dwYCountChars', c_ulong),
                ('dwFillAttribute', c_ulong),
                ('dwFlags', c_ulong),
                ('wShowWindow', c_ushort),
                ('cbReserved2', c_ushort),
                ('lpReserved2', c_ulong),    
                ('hStdInput', c_void_p),
                ('hStdOutput', c_void_p),
                ('hStdError', c_void_p)]

LPSTARTUPINFO = POINTER(STARTUPINFO)
LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
LPCONTEXT = POINTER(CONTEXT64)
kernel32 = WinDLL('kernel32', use_last_error=True)
#process_id = os.getpid()
try:

    CREATE_SUSPENDED = 0x00000004
    startupinfo = STARTUPINFO()
    startupinfo.cb = sizeof(STARTUPINFO)
    processinfo = PROCESS_INFORMATION()

    kernel32.CreateProcessA.argtypes = [LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCSTR,LPSTARTUPINFO,LPPROCESS_INFORMATION]
    kernel32.CreateProcessA.restype = BOOL
    if not kernel32.CreateProcessW(None,
                            target_exe,
                            None,
                            None,
                            True,
                            0x00000004,
                            None,
                            None,
                            byref(startupinfo),
                            byref(processinfo)):
            #kernel32.GetLastError()
            print ("Process creation [!]Error: " + FormatError(GetLastError()))
    #print(processinfo)
    hProcess = processinfo.hProcess
    hThread = processinfo.hThread
    print('process :',hProcess, ' thread: ',hThread)
    print('process_id :',processinfo.dwProcessId , 'thread_id :',processinfo.dwThreadId)

    
    if hProcess:
        print('handle created')
        kernel32.GetThreadContext.argtypes = [c_void_p,c_void_p]
        kernel32.GetThreadContext.restypes = c_uint

        cx = CONTEXT()
        cx2 = CONTEXT64()
        cx.ContextFlags = CONTEXT_FULL 
        cx2.ContextFlags = CONTEXT_FULL
        
        if kernel32.GetThreadContext(hThread, byref(cx)) == 0:
                print ("[!]Error: " + FormatError(GetLastError))
        
        print(cx, cx.Ebx, cx.Eax, cx.Edx, cx.Edi, cx.Ebp)

        if kernel32.GetThreadContext(hThread, byref(cx2)) == 0:
                print ("[!]Error: " + FormatError(GetLastError))
        
        print(cx2, cx2.Rbx, cx2.Rax, cx2.Rdx, cx2.Rdi, cx2.Rbp)


        kernel32.CloseHandle(hProcess)
    else:
        GetLastError()
        print('bad luck!!!')
        sys.exit()
    print('end of process')
    sys.exit()
except Exception as e:
    print(str(e))
    pass

output:

process : 476  thread:  472
process_id : 9116 thread_id : 9068
handle created
<__main__.CONTEXT object at 0x0000023604ACC640> 0 0 0 0 0
<__main__.CONTEXT64 object at 0x0000023604ACC6C0> 0 0 876891295744 0 0
end of process

for x64 structure, only getting the value of Rdx. for x86 structure everything is 0. here is the screenshot of the output: (screenshot of output)

could you guys tell me what is actually happening wrong or what i'm doing wrong.

**i know that it is comparatively easier to do in c++ but i really want to do in python, for much more better understanding of ctypes and grasp on ctypes. i did lots of googling and trail run but no luck till now.

testing environment: win 10.0.18363 N/A Build 18363 64bit vbox machine

thanks for your help in advance!

python
ctypes
asked on Stack Overflow Jan 14, 2021 by Soumik Mondol • edited Jan 15, 2021 by Soumik Mondol

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0