1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2009-2014, Mario Vilas 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions are met: 9# 10# * Redistributions of source code must retain the above copyright notice, 11# this list of conditions and the following disclaimer. 12# * Redistributions in binary form must reproduce the above copyright 13# notice,this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# * Neither the name of the copyright holder nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29# POSSIBILITY OF SUCH DAMAGE. 30 31""" 32CONTEXT structure for i386. 33""" 34 35__revision__ = "$Id$" 36 37from winappdbg.win32.defines import * 38from winappdbg.win32.version import ARCH_I386 39 40#============================================================================== 41# This is used later on to calculate the list of exported symbols. 42_all = None 43_all = set(vars().keys()) 44#============================================================================== 45 46#--- CONTEXT structures and constants ----------------------------------------- 47 48# The following values specify the type of access in the first parameter 49# of the exception record when the exception code specifies an access 50# violation. 51EXCEPTION_READ_FAULT = 0 # exception caused by a read 52EXCEPTION_WRITE_FAULT = 1 # exception caused by a write 53EXCEPTION_EXECUTE_FAULT = 8 # exception caused by an instruction fetch 54 55CONTEXT_i386 = 0x00010000 # this assumes that i386 and 56CONTEXT_i486 = 0x00010000 # i486 have identical context records 57 58CONTEXT_CONTROL = (CONTEXT_i386 | long(0x00000001)) # SS:SP, CS:IP, FLAGS, BP 59CONTEXT_INTEGER = (CONTEXT_i386 | long(0x00000002)) # AX, BX, CX, DX, SI, DI 60CONTEXT_SEGMENTS = (CONTEXT_i386 | long(0x00000004)) # DS, ES, FS, GS 61CONTEXT_FLOATING_POINT = (CONTEXT_i386 | long(0x00000008)) # 387 state 62CONTEXT_DEBUG_REGISTERS = (CONTEXT_i386 | long(0x00000010)) # DB 0-3,6,7 63CONTEXT_EXTENDED_REGISTERS = (CONTEXT_i386 | long(0x00000020)) # cpu specific extensions 64 65CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) 66 67CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | \ 68 CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | \ 69 CONTEXT_EXTENDED_REGISTERS) 70 71SIZE_OF_80387_REGISTERS = 80 72MAXIMUM_SUPPORTED_EXTENSION = 512 73 74# typedef struct _FLOATING_SAVE_AREA { 75# DWORD ControlWord; 76# DWORD StatusWord; 77# DWORD TagWord; 78# DWORD ErrorOffset; 79# DWORD ErrorSelector; 80# DWORD DataOffset; 81# DWORD DataSelector; 82# BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; 83# DWORD Cr0NpxState; 84# } FLOATING_SAVE_AREA; 85class FLOATING_SAVE_AREA(Structure): 86 _pack_ = 1 87 _fields_ = [ 88 ('ControlWord', DWORD), 89 ('StatusWord', DWORD), 90 ('TagWord', DWORD), 91 ('ErrorOffset', DWORD), 92 ('ErrorSelector', DWORD), 93 ('DataOffset', DWORD), 94 ('DataSelector', DWORD), 95 ('RegisterArea', BYTE * SIZE_OF_80387_REGISTERS), 96 ('Cr0NpxState', DWORD), 97 ] 98 99 _integer_members = ('ControlWord', 'StatusWord', 'TagWord', 'ErrorOffset', 'ErrorSelector', 'DataOffset', 'DataSelector', 'Cr0NpxState') 100 101 @classmethod 102 def from_dict(cls, fsa): 103 'Instance a new structure from a Python dictionary.' 104 fsa = dict(fsa) 105 s = cls() 106 for key in cls._integer_members: 107 setattr(s, key, fsa.get(key)) 108 ra = fsa.get('RegisterArea', None) 109 if ra is not None: 110 for index in compat.xrange(0, SIZE_OF_80387_REGISTERS): 111 s.RegisterArea[index] = ra[index] 112 return s 113 114 def to_dict(self): 115 'Convert a structure into a Python dictionary.' 116 fsa = dict() 117 for key in self._integer_members: 118 fsa[key] = getattr(self, key) 119 ra = [ self.RegisterArea[index] for index in compat.xrange(0, SIZE_OF_80387_REGISTERS) ] 120 ra = tuple(ra) 121 fsa['RegisterArea'] = ra 122 return fsa 123 124PFLOATING_SAVE_AREA = POINTER(FLOATING_SAVE_AREA) 125LPFLOATING_SAVE_AREA = PFLOATING_SAVE_AREA 126 127# typedef struct _CONTEXT { 128# DWORD ContextFlags; 129# DWORD Dr0; 130# DWORD Dr1; 131# DWORD Dr2; 132# DWORD Dr3; 133# DWORD Dr6; 134# DWORD Dr7; 135# FLOATING_SAVE_AREA FloatSave; 136# DWORD SegGs; 137# DWORD SegFs; 138# DWORD SegEs; 139# DWORD SegDs; 140# DWORD Edi; 141# DWORD Esi; 142# DWORD Ebx; 143# DWORD Edx; 144# DWORD Ecx; 145# DWORD Eax; 146# DWORD Ebp; 147# DWORD Eip; 148# DWORD SegCs; 149# DWORD EFlags; 150# DWORD Esp; 151# DWORD SegSs; 152# BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; 153# } CONTEXT; 154class CONTEXT(Structure): 155 arch = ARCH_I386 156 157 _pack_ = 1 158 159 # Context Frame 160 # 161 # This frame has a several purposes: 1) it is used as an argument to 162 # NtContinue, 2) is is used to constuct a call frame for APC delivery, 163 # and 3) it is used in the user level thread creation routines. 164 # 165 # The layout of the record conforms to a standard call frame. 166 167 _fields_ = [ 168 169 # The flags values within this flag control the contents of 170 # a CONTEXT record. 171 # 172 # If the context record is used as an input parameter, then 173 # for each portion of the context record controlled by a flag 174 # whose value is set, it is assumed that that portion of the 175 # context record contains valid context. If the context record 176 # is being used to modify a threads context, then only that 177 # portion of the threads context will be modified. 178 # 179 # If the context record is used as an IN OUT parameter to capture 180 # the context of a thread, then only those portions of the thread's 181 # context corresponding to set flags will be returned. 182 # 183 # The context record is never used as an OUT only parameter. 184 185 ('ContextFlags', DWORD), 186 187 # This section is specified/returned if CONTEXT_DEBUG_REGISTERS is 188 # set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT 189 # included in CONTEXT_FULL. 190 191 ('Dr0', DWORD), 192 ('Dr1', DWORD), 193 ('Dr2', DWORD), 194 ('Dr3', DWORD), 195 ('Dr6', DWORD), 196 ('Dr7', DWORD), 197 198 # This section is specified/returned if the 199 # ContextFlags word contains the flag CONTEXT_FLOATING_POINT. 200 201 ('FloatSave', FLOATING_SAVE_AREA), 202 203 # This section is specified/returned if the 204 # ContextFlags word contains the flag CONTEXT_SEGMENTS. 205 206 ('SegGs', DWORD), 207 ('SegFs', DWORD), 208 ('SegEs', DWORD), 209 ('SegDs', DWORD), 210 211 # This section is specified/returned if the 212 # ContextFlags word contains the flag CONTEXT_INTEGER. 213 214 ('Edi', DWORD), 215 ('Esi', DWORD), 216 ('Ebx', DWORD), 217 ('Edx', DWORD), 218 ('Ecx', DWORD), 219 ('Eax', DWORD), 220 221 # This section is specified/returned if the 222 # ContextFlags word contains the flag CONTEXT_CONTROL. 223 224 ('Ebp', DWORD), 225 ('Eip', DWORD), 226 ('SegCs', DWORD), # MUST BE SANITIZED 227 ('EFlags', DWORD), # MUST BE SANITIZED 228 ('Esp', DWORD), 229 ('SegSs', DWORD), 230 231 # This section is specified/returned if the ContextFlags word 232 # contains the flag CONTEXT_EXTENDED_REGISTERS. 233 # The format and contexts are processor specific. 234 235 ('ExtendedRegisters', BYTE * MAXIMUM_SUPPORTED_EXTENSION), 236 ] 237 238 _ctx_debug = ('Dr0', 'Dr1', 'Dr2', 'Dr3', 'Dr6', 'Dr7') 239 _ctx_segs = ('SegGs', 'SegFs', 'SegEs', 'SegDs', ) 240 _ctx_int = ('Edi', 'Esi', 'Ebx', 'Edx', 'Ecx', 'Eax') 241 _ctx_ctrl = ('Ebp', 'Eip', 'SegCs', 'EFlags', 'Esp', 'SegSs') 242 243 @classmethod 244 def from_dict(cls, ctx): 245 'Instance a new structure from a Python dictionary.' 246 ctx = Context(ctx) 247 s = cls() 248 ContextFlags = ctx['ContextFlags'] 249 setattr(s, 'ContextFlags', ContextFlags) 250 if (ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS: 251 for key in s._ctx_debug: 252 setattr(s, key, ctx[key]) 253 if (ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT: 254 fsa = ctx['FloatSave'] 255 s.FloatSave = FLOATING_SAVE_AREA.from_dict(fsa) 256 if (ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS: 257 for key in s._ctx_segs: 258 setattr(s, key, ctx[key]) 259 if (ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER: 260 for key in s._ctx_int: 261 setattr(s, key, ctx[key]) 262 if (ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL: 263 for key in s._ctx_ctrl: 264 setattr(s, key, ctx[key]) 265 if (ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS: 266 er = ctx['ExtendedRegisters'] 267 for index in compat.xrange(0, MAXIMUM_SUPPORTED_EXTENSION): 268 s.ExtendedRegisters[index] = er[index] 269 return s 270 271 def to_dict(self): 272 'Convert a structure into a Python native type.' 273 ctx = Context() 274 ContextFlags = self.ContextFlags 275 ctx['ContextFlags'] = ContextFlags 276 if (ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS: 277 for key in self._ctx_debug: 278 ctx[key] = getattr(self, key) 279 if (ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT: 280 ctx['FloatSave'] = self.FloatSave.to_dict() 281 if (ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS: 282 for key in self._ctx_segs: 283 ctx[key] = getattr(self, key) 284 if (ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER: 285 for key in self._ctx_int: 286 ctx[key] = getattr(self, key) 287 if (ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL: 288 for key in self._ctx_ctrl: 289 ctx[key] = getattr(self, key) 290 if (ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS: 291 er = [ self.ExtendedRegisters[index] for index in compat.xrange(0, MAXIMUM_SUPPORTED_EXTENSION) ] 292 er = tuple(er) 293 ctx['ExtendedRegisters'] = er 294 return ctx 295 296PCONTEXT = POINTER(CONTEXT) 297LPCONTEXT = PCONTEXT 298 299class Context(dict): 300 """ 301 Register context dictionary for the i386 architecture. 302 """ 303 304 arch = CONTEXT.arch 305 306 def __get_pc(self): 307 return self['Eip'] 308 def __set_pc(self, value): 309 self['Eip'] = value 310 pc = property(__get_pc, __set_pc) 311 312 def __get_sp(self): 313 return self['Esp'] 314 def __set_sp(self, value): 315 self['Esp'] = value 316 sp = property(__get_sp, __set_sp) 317 318 def __get_fp(self): 319 return self['Ebp'] 320 def __set_fp(self, value): 321 self['Ebp'] = value 322 fp = property(__get_fp, __set_fp) 323 324#--- LDT_ENTRY structure ------------------------------------------------------ 325 326# typedef struct _LDT_ENTRY { 327# WORD LimitLow; 328# WORD BaseLow; 329# union { 330# struct { 331# BYTE BaseMid; 332# BYTE Flags1; 333# BYTE Flags2; 334# BYTE BaseHi; 335# } Bytes; 336# struct { 337# DWORD BaseMid :8; 338# DWORD Type :5; 339# DWORD Dpl :2; 340# DWORD Pres :1; 341# DWORD LimitHi :4; 342# DWORD Sys :1; 343# DWORD Reserved_0 :1; 344# DWORD Default_Big :1; 345# DWORD Granularity :1; 346# DWORD BaseHi :8; 347# } Bits; 348# } HighWord; 349# } LDT_ENTRY, 350# *PLDT_ENTRY; 351 352class _LDT_ENTRY_BYTES_(Structure): 353 _pack_ = 1 354 _fields_ = [ 355 ('BaseMid', BYTE), 356 ('Flags1', BYTE), 357 ('Flags2', BYTE), 358 ('BaseHi', BYTE), 359 ] 360 361class _LDT_ENTRY_BITS_(Structure): 362 _pack_ = 1 363 _fields_ = [ 364 ('BaseMid', DWORD, 8), 365 ('Type', DWORD, 5), 366 ('Dpl', DWORD, 2), 367 ('Pres', DWORD, 1), 368 ('LimitHi', DWORD, 4), 369 ('Sys', DWORD, 1), 370 ('Reserved_0', DWORD, 1), 371 ('Default_Big', DWORD, 1), 372 ('Granularity', DWORD, 1), 373 ('BaseHi', DWORD, 8), 374 ] 375 376class _LDT_ENTRY_HIGHWORD_(Union): 377 _pack_ = 1 378 _fields_ = [ 379 ('Bytes', _LDT_ENTRY_BYTES_), 380 ('Bits', _LDT_ENTRY_BITS_), 381 ] 382 383class LDT_ENTRY(Structure): 384 _pack_ = 1 385 _fields_ = [ 386 ('LimitLow', WORD), 387 ('BaseLow', WORD), 388 ('HighWord', _LDT_ENTRY_HIGHWORD_), 389 ] 390 391PLDT_ENTRY = POINTER(LDT_ENTRY) 392LPLDT_ENTRY = PLDT_ENTRY 393 394############################################################################### 395 396# BOOL WINAPI GetThreadSelectorEntry( 397# __in HANDLE hThread, 398# __in DWORD dwSelector, 399# __out LPLDT_ENTRY lpSelectorEntry 400# ); 401def GetThreadSelectorEntry(hThread, dwSelector): 402 _GetThreadSelectorEntry = windll.kernel32.GetThreadSelectorEntry 403 _GetThreadSelectorEntry.argtypes = [HANDLE, DWORD, LPLDT_ENTRY] 404 _GetThreadSelectorEntry.restype = bool 405 _GetThreadSelectorEntry.errcheck = RaiseIfZero 406 407 ldt = LDT_ENTRY() 408 _GetThreadSelectorEntry(hThread, dwSelector, byref(ldt)) 409 return ldt 410 411# BOOL WINAPI GetThreadContext( 412# __in HANDLE hThread, 413# __inout LPCONTEXT lpContext 414# ); 415def GetThreadContext(hThread, ContextFlags = None, raw = False): 416 _GetThreadContext = windll.kernel32.GetThreadContext 417 _GetThreadContext.argtypes = [HANDLE, LPCONTEXT] 418 _GetThreadContext.restype = bool 419 _GetThreadContext.errcheck = RaiseIfZero 420 421 if ContextFlags is None: 422 ContextFlags = CONTEXT_ALL | CONTEXT_i386 423 Context = CONTEXT() 424 Context.ContextFlags = ContextFlags 425 _GetThreadContext(hThread, byref(Context)) 426 if raw: 427 return Context 428 return Context.to_dict() 429 430# BOOL WINAPI SetThreadContext( 431# __in HANDLE hThread, 432# __in const CONTEXT* lpContext 433# ); 434def SetThreadContext(hThread, lpContext): 435 _SetThreadContext = windll.kernel32.SetThreadContext 436 _SetThreadContext.argtypes = [HANDLE, LPCONTEXT] 437 _SetThreadContext.restype = bool 438 _SetThreadContext.errcheck = RaiseIfZero 439 440 if isinstance(lpContext, dict): 441 lpContext = CONTEXT.from_dict(lpContext) 442 _SetThreadContext(hThread, byref(lpContext)) 443 444#============================================================================== 445# This calculates the list of exported symbols. 446_all = set(vars().keys()).difference(_all) 447__all__ = [_x for _x in _all if not _x.startswith('_')] 448__all__.sort() 449#============================================================================== 450