class Context(object):
Entry point object for data related to a context.
A context represents the full state of the VM at a point in time. You can access contexts before or after a transition:
... -> Context Before #N -> Transition #N -> Context After #N -> ...
A context can usually be referenced as both a context before and a context after:
... -> Transition #N-1 -> Context After #N-1 / Before #N -> Transition #N -> ...
Except at the trace's begin and end:
Context Before #0 -> Transition #0 -> ... -> Transition #M -> Context After #M}
This object is not meant to be constructed directly. Use Trace.context_before
, Trace.context_after
, Transition.context_before
or Transition.context_after
instead.
>>> # From a transition >>> reven_server.trace.transition(id).context_before() >>> reven_server.trace.transition(id).context_after()
>>> # From a trace directly >>> reven_server.trace.context_before(transition_id) >>> reven_server.trace.context_after(transition_id)
>>> # From a context >>> ctx = reven_server.trace.context_before(transition_id) >>> next_ctx = ctx + 1 >>> prev_ctx = ctx - 1 >>> other_ctx = ctx + 10000
Method | __init__ |
Undocumented |
Method | transition_before |
Get Transition that led to this context: |
Method | transition_after |
Get Transition that will execute right after this context: |
Property | ossi |
Property: OSSI information related to the context |
Property | stack |
Property: The active stack linked to the context. |
Method | is64b |
Undocumented |
Method | physical_memory_regions |
Get all the physical memory regions that are accessible. |
Method | read |
read(register [, raw=False]) -> read bytes from a register read(source, size[, raw=False]) -> read bytes from a register or a memory read(source, type) -> read bytes from a register or a memory |
Method | deref |
Recursively dereferences a pointer and read the value read as a pointing type. |
Method | find_register_change |
Find the next/previous context in which the content of the register is modified. |
Method | search_in_memory |
No summary |
Method | __str__ |
Undocumented |
Method | __repr__ |
Undocumented |
Method | format_as_html |
This method gets an html formatting string representation for this class instance. |
Method | __eq__ |
Undocumented |
Method | __ne__ |
Undocumented |
Method | __lt__ |
Undocumented |
Method | __le__ |
Undocumented |
Method | __gt__ |
Undocumented |
Method | __ge__ |
Undocumented |
Method | __add__ |
Undocumented |
Method | __sub__ |
Undocumented |
Instance Variable | __trace |
Undocumented |
Instance Variable | _data_source |
Undocumented |
Instance Variable | _ossi_data_source |
Undocumented |
Instance Variable | _id |
Undocumented |
Instance Variable | _cpu_context |
Undocumented |
Property | _trace |
Undocumented |
Static Method | _next_stop_point |
Undocumented |
Method | _read_size |
Undocumented |
Method | _read_as |
Undocumented |
Method | _read_raw |
Undocumented |
Method | _read_st_register |
Undocumented |
Method | _read_register |
Undocumented |
Method | _repr_html_ |
Representation used by Jupyter Notebook when an instance of this class is displayed in a cell. |
Property | _rvn |
Undocumented |
Get Transition that led to this context:
Transition Before -> This context
Returns | A Transition . | |
Raises | IndexError | if called on the context before the first transition |
Get Transition that will execute right after this context:
This context -> Transition After
Returns | A Transition . | |
Raises | IndexError | if called on the context after the last transition |
Property: OSSI information related to the context
>>> # the current symbol >>> print(context.ossi.location()) 'ntoskrnl!KiIsrLinkage+0x10'
Returns | A reven2.ossi.OssiContext . |
Property: The active stack linked to the context.
>>> # the active stack >>> print(context.stack) [0] #2753249448 - ntoskrnl!KeZeroPages [1] #2753249199 - ntoskrnl!MiZeroPhysicalPage [2] #2753248836 - ntoskrnl!MiResolveDemandZeroFault [3] #2753248607 - ntoskrnl!MmAccessFault [4] #2753248552 - ntoskrnl!KiPageFault [5] ??? - ntoskrnl!KiSystemCall64+0x15
Returns | A reven2.stack.Stack . |
Get all the physical memory regions that are accessible.
These regions are assumed to not change during the entire trace.
Any physical read inside these regions is guaranteed to succeed.
>>> for (start, size) in ctx.physical_memory_regions(): ... print("{} - {}".format(start, start + size)) phy:0x0 - phy:0x80000000 phy:0xfd000000 - phy:0xfe000000
Returns | A generator of tuples composed of the start physical address of a region and its size. |
read(register [, raw=False]) -> read bytes from a register read(source, size[, raw=False]) -> read bytes from a register or a memory read(source, type) -> read bytes from a register or a memory
If 'size' in [1, 2, 4, 8], the bytes are interpreted as an unsigned int
. If 'raw' is True
, a raw buffer is returned even if 'size' is in [1, 2, 4, 8]. If 'type' is provided (a reven2.types.Type
), the bytes are interpreted as the given 'type'. In all other cases, a raw buffer is returned.
If 'source' is a virtual address, then [source; length] must be mapped in the current context, with `length == size` if 'size' was provided, or `length == type.size_bytes(self)` if `type` was provided
If 'source' is a physical address, then [source; length] must be in the available physical memory (see Context.physical_memory_regions
), with `length == size` if 'size' was provided, or `length == type.size_bytes(self)` if `type` was provided
Read rax without size:
>>> hex(context.read(arch.x64.rax)) '0xffffc000e9997ac0'
>>> # Get a raw buffer >>> context.read(arch.x64.rax, raw=True) bytearray(b'\xc0z\x99\xe9\x00\xc0\xff\xff')
Read rax with size:
>>> # size not in [1, 2, 4, 8] >>> context.read(arch.x64.rax, 6) bytearray(b'\xc0z\x99\xe9\x00\xc0')
>>> # size in [1, 2, 4, 8] >>> hex(context.read(arch.x64.rax, 4)) '0xe9997ac0'
>>> # Get a raw buffer >>> hex(context.read(arch.x64.rax, 4, raw=True)) bytearray(b'\xc0z\x99\xe9')
Read rax as a U64 integer:
>>> hex(context.read(arch.x64.rax, types.U64)) '0xffffc000e9997ac0'
Read rax as two U8 integers:
>>> context.read(arch.x64.rax, types.Array(types.U16, 2)) ListContainer([0xe999, 0x7ac0])
Read a buffer in memory at address ds:0x1234:
>>> address = address.LogicalAddress(0x1234)
>>> # size not in [1, 2, 4, 8] >>> context.read(address, 6) bytearray(b'\xc0z\x99\xe9\x00\xc0')
>>> # size in [1, 2, 4, 8] >>> hex(context.read(address, 8)) '0xffffc000e9997ac0'
>>> # Get a raw buffer >>> context.read(address, 8, raw=True) bytearray(b'\xc0z\x99\xe9\x00\xc0\xff\xff')
Read a string in memory at address ds:0x1234:
>>> address = address.LogicalAddress(0x1234) >>> WString1000 = types.CString(encoding=types.Encoding.Utf16, max_character_count=1000) >>> context.read(address, WString1000) 'Hello World'
Parameters | source | From where the bytes are read. Can be an address (virtual or physical) or a Register . |
args | Undocumented | |
kwargs | Undocumented | |
type | A reven2.types.Type . See the reven2.types package documentation for more information on types. | |
size | The byte size to read. If no 'size' and 'source' is a reven2.arch.register.Register , then the Register.size_bytes is used. | |
raw | Force the return type to be a raw buffer of 'size' bytes. | |
Raises | TypeError | if 'source' is not supported. |
TypeError | if 'type' is not a Type . | |
ValueError | if 'source' is an address and 'size' or 'type' are not provided. | |
ValueError | if 'source' is a Register and 'size' is bigger than the register byte size. | |
RuntimeError | if 'source' is an unavailable register. | |
RuntimeError | if 'source' is a virtual address and is not mapped in the current context. | |
RuntimeError | if 'source' is a physical address and is outside the physical memory. |
Recursively dereferences a pointer and read the value read as a pointing type.
This method allows to directly returns the pointed-to value when passed a pointer type and a source from which read the pointer address.
A (simplified) desugaring of this method can be thought of like the following:
>>> def deref_simple_case(self, source, ptr_ty): ... addr = self.read(source, ptr_ty) ... return self.read(addr, ptr_ty.elem_type)
Note, however that the actual implementation will recursively remove all levels of indirection, e.g. if the type is Pointer(Pointer(U64)), then the implementation will do the following:
>>> def deref_unrolled(self, source, ptr_ty): ... addr1 = self.read(source, Pointer(Pointer(U64))) ... addr2 = self.read(addr1, Pointer(U64)) ... return self.read(addr2, U64)
Reading the stack pointer:
>>> hex(context.deref(reven2.arch.x64.rsp, types.Pointer(types.USize))) '0xfffff801653ff072'
Looks like an address, let's try to dereference twice:
>>> hex(context.deref(reven2.arch.x64.rsp, types.Pointer(types.Pointer(types.USize)))) '0x7c894828247c894c'
Doesn't look like an address anymore, show raw:
>>> [hex(x) for x in context.deref(reven2.arch.x64.rsp, types.Pointer(types.Pointer(types.RawBuffer(8))))] ['0x4c', '0x89', '0x7c', '0x24', '0x28', '0x48', '0x89', '0x7c']
Parameters | source | The source where to read the address of the pointer. Can be an address (virtual or physical) or a register. |
ptr_ty | A reven2.types.Pointer . | |
Returns | The data interpreted as the requested type. If the pointer points to an unmapped memory, None is returned. | |
Raises | TypeError | if 'source' is not supported. |
TypeError | if 'ptr_ty' is not a Pointer . | |
ValueError | if 'source' is a Register and there is not enough bytes to read the pointer address in it. | |
RuntimeError | if 'source' is an unavailable register. |
Find the next/previous context in which the content of the register is modified.
In the current implementation, this function does not return changes that occur on the context right after the specified context.
Parameters | register | reven2.arch.register.Register |
is_forward | If True return next context. Otherwise return previous context. | |
fetch_count | Technical parameter indicating how many contexts the server should handle per query. Modifying this parameter allows to fine-tune performance:
NOTE: Modifying this parameter does not modify the results of the query | |
Returns | A reven2.trace.Context or None if no context was found. | |
Raises | ValueError | if fetch_count is not positive. |
Iterate the search range looking for the specified pattern. Search range is:
This method returns a generator of addresses corresponding to the addresses where the searched pattern matches.
Parameters | pattern | A str or bytearray . The pattern to look for in memory. Note: str pattern is converted to bytearray using ascci encoding. |
address | a class from reven2.address the address where the search will be started. an Integer represents the offset of the address where the search will be started. | |
size | an Integer representing the size, in bytes, of the search range. | |
is_forward | bool , True to search in forward direction and False to search in backward direction | |
Returns | a generator of addresses corresponding to the addresses where the searched pattern matches. | |
Raises | TypeError | if address is not a Integer or one of the address classes on reven2.address . |
RunTimeError | If the address is a virtual address that is not aligned to its corresponding physical address. |
This method gets an html formatting string representation for this class instance.
Returns | String |