Source code for windows.winobject.exception

import ctypes
import windows
from windows.generated_def.winstructs import *
import windows.generated_def.windef as windef

EXCEPTION_CONTINUE_SEARCH = (0x0)
EXCEPTION_CONTINUE_EXECUTION = (0xffffffff)

exception_type = [
    "EXCEPTION_ACCESS_VIOLATION",
    "EXCEPTION_DATATYPE_MISALIGNMENT",
    "EXCEPTION_BREAKPOINT",
    "EXCEPTION_SINGLE_STEP",
    "EXCEPTION_ARRAY_BOUNDS_EXCEEDED",
    "EXCEPTION_FLT_DENORMAL_OPERAND",
    "EXCEPTION_FLT_DIVIDE_BY_ZERO",
    "EXCEPTION_FLT_INEXACT_RESULT",
    "EXCEPTION_FLT_INVALID_OPERATION",
    "EXCEPTION_FLT_OVERFLOW",
    "EXCEPTION_FLT_STACK_CHECK",
    "EXCEPTION_FLT_UNDERFLOW",
    "EXCEPTION_INT_DIVIDE_BY_ZERO",
    "EXCEPTION_INT_OVERFLOW",
    "EXCEPTION_PRIV_INSTRUCTION",
    "EXCEPTION_IN_PAGE_ERROR",
    "EXCEPTION_ILLEGAL_INSTRUCTION",
    "EXCEPTION_NONCONTINUABLE_EXCEPTION",
    "EXCEPTION_STACK_OVERFLOW",
    "EXCEPTION_INVALID_DISPOSITION",
    "EXCEPTION_GUARD_PAGE",
    "EXCEPTION_INVALID_HANDLE",
    "EXCEPTION_POSSIBLE_DEADLOCK",
]

# x -> x dict may seems strange but useful to get the Flags (with name) from the int
# exception_name_by_value[0x80000001] -> EXCEPTION_GUARD_PAGE(0x80000001L)
exception_name_by_value = dict([(x, x) for x in [getattr(windows.generated_def.windef, name) for name in exception_type]])

class EEXCEPTION_RECORDBase(object):
        @property
        def ExceptionCode(self):
            """The Exception code

               :type: :class:`int`"""
            real_code = super(EEXCEPTION_RECORDBase, self).ExceptionCode
            return exception_name_by_value.get(real_code, windows.generated_def.windef.Flag("UNKNOW_EXCEPTION", real_code))

        @property
        def ExceptionAddress(self):
            """The Exception Address

            :type: :class:`int`"""
            x = super(EEXCEPTION_RECORDBase, self).ExceptionAddress
            if x is None:
                return 0x0
            return x

[docs]class EEXCEPTION_RECORD(EEXCEPTION_RECORDBase, EXCEPTION_RECORD): """Enhanced exception record""" fields = [f[0] for f in EXCEPTION_RECORD._fields_] """The fields of the structure"""
[docs]class EEXCEPTION_RECORD32(EEXCEPTION_RECORDBase, EXCEPTION_RECORD32): """Enhanced exception record (32bits)""" fields = [f[0] for f in EXCEPTION_RECORD32._fields_] """The fields of the structure"""
[docs]class EEXCEPTION_RECORD64(EEXCEPTION_RECORDBase, EXCEPTION_RECORD64): """Enhanced exception record (64bits)""" fields = [f[0] for f in EXCEPTION_RECORD64._fields_] """The fields of the structure"""
[docs]class EEXCEPTION_DEBUG_INFO32(ctypes.Structure): """Enhanced Debug info""" _fields_ = windows.utils.transform_ctypes_fields(EXCEPTION_DEBUG_INFO, {"ExceptionRecord": EEXCEPTION_RECORD32}) fields = [f[0] for f in _fields_] """The fields of the structure"""
[docs]class EEXCEPTION_DEBUG_INFO64(ctypes.Structure): """Enhanced Debug info""" _fields_ = windows.utils.transform_ctypes_fields(EXCEPTION_DEBUG_INFO, {"ExceptionRecord": EEXCEPTION_RECORD64}) fields = [f[0] for f in _fields_] """The fields of the structure"""
[docs]class EEflags(ctypes.Structure): "Flag view of the Eflags register" _fields_ = [("CF", DWORD, 1), ("RES_1", DWORD, 1), ("PF", DWORD, 1), ("RES_3", DWORD, 1), ("AF", DWORD, 1), ("RES_5", DWORD, 1), ("ZF", DWORD, 1), ("SF", DWORD, 1), ("TF", DWORD, 1), ("IF", DWORD, 1), ("DF", DWORD, 1), ("OF", DWORD, 1), ("IOPL_1", DWORD, 1), ("IOPL_2", DWORD, 1), ("NT", DWORD, 1), ("RES_15", DWORD, 1), ("RF", DWORD, 1), ("VM", DWORD, 1), ("AC", DWORD, 1), ("VIF", DWORD, 1), ("VIP", DWORD, 1), ("ID", DWORD, 1), ] fields = [f[0] for f in _fields_] """The fields of the structure""" def get_raw(self): x = DWORD.from_address(ctypes.addressof(self)) return x.value def set_raw(self, value): x = DWORD.from_address(ctypes.addressof(self)) x.value = value return None def dump(self): res = [] for name in [x[0] for x in self._fields_]: if name.startswith("RES_"): continue if getattr(self, name): res.append(name) return "|".join(res) def __repr__(self): return hex(self) def __hex__(self): if self.raw == 0: return "{0}({1})".format(type(self).__name__, hex(self.raw)) return "{0}({1}:{2})".format(type(self).__name__, hex(self.raw), self.dump()) raw = property(get_raw, set_raw) """Raw value of the eflags :type: :class:`int` """
[docs]class EDr7(ctypes.Structure): "Flag view of the DR7 register" _fields_ = [("L0", DWORD, 1), ("G0", DWORD, 1), ("L1", DWORD, 1), ("G1", DWORD, 1), ("L2", DWORD, 1), ("G2", DWORD, 1), ("L3", DWORD, 1), ("G3", DWORD, 1), ("LE", DWORD, 1), ("GE", DWORD, 1), ("RES_1", DWORD, 3), ("GD", DWORD, 1), ("RES_1", DWORD, 2), ("RW0", DWORD, 2), ("LEN0", DWORD, 2), ("RW1", DWORD, 2), ("LEN1", DWORD, 2), ("RW2", DWORD, 2), ("LEN2", DWORD, 2), ("RW3", DWORD, 2), ("LEN3", DWORD, 2), ] fields = [f[0] for f in _fields_] """The fields of the structure"""
class ECONTEXTBase(object): """DAT CONTEXT""" default_dump = () pc_reg = '' sp_reg = '' func_result_reg = '' special_reg_type = {} def regs(self, to_dump=None): """Return the name and values of the registers :returns: [(reg_name, value)] -- A :class:`list` of :class:`tuple`""" res = [] if to_dump is None: to_dump = self.default_dump for name in to_dump: value = getattr(self, name) if name in self.special_reg_type: value = self.special_reg_type[name](value) res.append((name, value)) return res def dump(self, to_dump=None): """Dump (print) the current context""" regs = self.regs() for name, value in regs: print("{0} -> {1}".format(name, hex(value))) return None def get_pc(self): return getattr(self, self.pc_reg) def set_pc(self, value): return setattr(self, self.pc_reg, value) def get_sp(self): return getattr(self, self.sp_reg) def set_sp(self, value): return setattr(self, self.sp_reg, value) def get_func_result(self): return getattr(self, self.func_result_reg) def set_func_result(self, value): return setattr(self, self.func_result_reg, value) pc = property(get_pc, set_pc, None, "Program Counter register (EIP or RIP)") sp = property(get_sp, set_sp, None, "Stack Pointer register (ESP or RSP)") func_result = property(get_func_result, set_func_result, None, "Function Resultat register (EAX or RAX)") @property def EEFlags(self): """Enhanced view of the Eflags (you also have ``EFlags`` for the raw value) :type: :class:`EEflags` """ off = type(self).EFlags.offset x = EEflags.from_address(ctypes.addressof(self) + off) x.self = self return x @property def EDr7(self): """Enhanced view of the DR7 register (you also have ``Dr7`` for the raw value) :type: :class:`EDr7` """ off = type(self).Dr7.offset x = EDr7.from_address(ctypes.addressof(self) + off) x.self = self return x
[docs]class ECONTEXT32(ECONTEXTBase, CONTEXT32): default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') pc_reg = 'Eip' sp_reg = 'Esp' func_result_reg = 'Eax' fields = [f[0] for f in CONTEXT32._fields_] """The fields of the structure"""
[docs]class ECONTEXTWOW64(ECONTEXTBase, WOW64_CONTEXT): default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') pc_reg = 'Eip' sp_reg = 'Esp' func_result_reg = 'Eax' fields = [f[0] for f in WOW64_CONTEXT._fields_] """The fields of the structure"""
[docs]class ECONTEXT64(ECONTEXTBase, CONTEXT64): default_dump = ('Rip', 'Rsp', 'Rax', 'Rbx', 'Rcx', 'Rdx', 'Rbp', 'Rdi', 'Rsi', 'R8', 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'EFlags') pc_reg = 'Rip' sp_reg = 'Rsp' func_result_reg = 'Rax' fields = [f[0] for f in CONTEXT64._fields_] """The fields of the structure"""
[docs] @classmethod def new_aligned(cls): """Return a new :class:`ECONTEXT64` aligned on 16 bits temporary workaround or horrible hack ? choose your side """ size = ctypes.sizeof(cls) nb_qword = int((size + 8) / ctypes.sizeof(ULONGLONG)) buffer = (nb_qword * ULONGLONG)() struct_address = ctypes.addressof(buffer) if (struct_address & 0xf) not in [0, 8]: raise ValueError("ULONGLONG array not aligned on 8") if (struct_address & 0xf) == 8: struct_address += 8 self = cls.from_address(struct_address) # Keep the raw buffer alive self._buffer = buffer return self
def bitness(): """Return 32 or 64""" import platform bits = platform.architecture()[0] return int(bits[:2]) if bitness() == 32: ECONTEXT = ECONTEXT32 else: ECONTEXT = ECONTEXT64
[docs]class EEXCEPTION_POINTERS(ctypes.Structure): _fields_ = [ ("ExceptionRecord", ctypes.POINTER(EEXCEPTION_RECORD)), ("ContextRecord", ctypes.POINTER(ECONTEXT)), ]
[docs] def dump(self): """Dump (print) the EEXCEPTION_POINTERS""" record = self.ExceptionRecord[0] print("Dumping Exception: ") print(" ExceptionCode = {0} at {1}".format(record.ExceptionCode, hex(record.ExceptionAddress))) regs = self.ContextRecord[0].regs() for name, value in regs: print(" {0} -> {1}".format(name, hex(value)))
[docs]class VectoredException(object): """A decorator that create a callable which can be passed to :func:`AddVectoredExceptionHandler`""" func_type = ctypes.WINFUNCTYPE(ctypes.c_uint, ctypes.POINTER(EEXCEPTION_POINTERS)) def __new__(cls, func): self = object.__new__(cls) self.func = func v = self.func_type(self.decorator) v.self = self return v def decorator(self, exception_pointers): try: return self.func(exception_pointers) except BaseException as e: import traceback print("Ignored Python Exception in Vectored Exception: {0}".format(e)) traceback.print_exc() return windef.EXCEPTION_CONTINUE_SEARCH
class VectoredExceptionHandler(object): def __init__(self, pos, handler): self.handler = VectoredException(handler) self.pos = pos def __enter__(self): self.value = windows.winproxy.AddVectoredExceptionHandler(self.pos, self.handler) return self def __exit__(self, exc_type, exc_value, traceback): windows.winproxy.RemoveVectoredExceptionHandler(self.value) return False class DumpContextOnException(VectoredExceptionHandler): def __init__(self, exit=False): self.exit = exit super(DumpContextOnException, self).__init__(self.print_context_result) def print_context_result(self, exception_pointers): except_record = exception_pointers[0].ExceptionRecord[0] exception_pointers[0].dump() sys.stdout.flush() if self.exit: windows.current_process.exit() return 0