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!
User contributions licensed under CC BY-SA 3.0