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

Warnings

This object is not meant to be constructed directly. Use Trace.context_before, Trace.context_after, Transition.context_before or Transition.context_after instead.

Examples

>>> # 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
Method ossi Property: OSSI information related to the context
Method 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 __eq__ Undocumented
Method __ne__ Undocumented
Method __lt__ Undocumented
Method __le__ Undocumented
Method __gt__ Undocumented
Method __ge__ Undocumented
Method __add__ Undocumented
Method __sub__ Undocumented
Method _trace Undocumented
Method _read_size Undocumented
Method _read_as Undocumented
Method _read_raw Undocumented
Method _read_st_register Undocumented
Method _read_register Undocumented
Method _rvn Undocumented
def __init__(self, trace, _data_source, _ossi_data_source, context_id):
Undocumented
@property
def _trace(self):
Undocumented
def transition_before(self):

Get Transition that led to this context

>>> Transition Before -> This context

Information

ReturnsA Transition.
RaisesIndexErrorif called on the context before the first transition
def transition_after(self):

Get Transition that will execute right after this

>>> This context -> Transition After

Information

ReturnsA Transition.
RaisesIndexErrorif called on the context after the last transition
@property
def ossi(self):

Property: OSSI information related to the context

Examples

>>> # the current symbol
>>> print(context.ossi.location())
'ntoskrnl!KiIsrLinkage+0x10'

Information

ReturnsA reven2.ossi.OssiContext.
@property
def stack(self):

Property: The active stack linked to the context.

Examples

>>> # the active stack
>>> print(context.stack.backtrace)
[0] #2753249448 - ntoskrnl!KeZeroPages
[1] #2753249199 - ntoskrnl!MiZeroPhysicalPage
[2] #2753248836 - ntoskrnl!MiResolveDemandZeroFault
[3] #2753248607 - ntoskrnl!MmAccessFault
[4] #2753248552 - ntoskrnl!KiPageFault
[5] ??? - ntoskrnl!KiSystemCall64+0x15

Information

ReturnsA reven2.stack.Stack.
def is64b(self):
Undocumented
def physical_memory_regions(self):

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.

Examples

>>> for (start, size) in ctx.physical_memory_regions():
>>>     print("{} - {}".format(start, start + size))
phy:0x0 - phy:0x80000000
phy:0xfd000000 - phy:0xfe000000

Informations

ReturnsA generator of tuples composed of the start physical address of a region and its size.
def read(self, source, *args, **kwargs):

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

Examples

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'

Information

ParameterssourceFrom where the bytes are read. Can be an address (virtual or physical) or a Register.
typeA reven2.types.Type. See the reven2.types package documentation for more information on types.
sizeThe byte size to read. If no 'size' and 'source' is a reven2.arch.register.Register, then the Register.size_bytes is used.
rawForce the return type to be a raw buffer of 'size' bytes.
RaisesTypeErrorif 'source' is not supported.
TypeErrorif 'type' is not a Type.
ValueErrorif 'source' is an address and 'size' or 'type' are not provided.
ValueErrorif 'source' is a Register and 'size' is bigger than the register byte size.
RuntimeErrorif 'source' is an unavailable register.
RuntimeErrorif 'source' is a virtual address and is not mapped in the current context.
RuntimeErrorif 'source' is a physical address and is outside the physical memory.
def deref(self, source, ptr_ty):

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:

>>> 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:

>>> addr1 = self.read(source, Pointer(Pointer(U64)))
>>> addr2 = self.read(addr1, Pointer(U64))
>>> return self.read(addr2, U64)

Example

Reading the stack pointer:

>>> hex(context.deref(reven2.arch.x64.rsp, types.Pointer(types.USize)))
'0xfffff801653ff072L'

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']

Information

ParameterssourceThe source where to read the address of the pointer. Can be an address (virtual or physical) or a register.
ptr_tyA reven2.types.Pointer.
ReturnsThe data interpreted as the requested type. If the pointer points to an unmapped memory, None is returned.
RaisesTypeErrorif 'source' is not supported.
TypeErrorif 'ptr_ty' is not a Pointer.
ValueErrorif 'source' is a Register and there is not enough bytes to read the pointer address in it.
RuntimeErrorif 'source' is an unavailable register.
def find_register_change(self, register, is_forward=True, fetch_count=10000):

Find the next/previous context in which the content of the register is modified.

Information

Parametersregisterreven2.arch.register.Register
is_forwardIf True return next context. Otherwise return previous context.
fetch_countTechnical parameter indicating how many contexts the server should handle per query. Modifying this parameter allows to fine-tune performance:
  • A large value leads to better performance but may cause the script to block longer while waiting for the server response without being interruptible.
  • A small value leads to a lot of server requests and so reduces performance but ensures the script will not block.
  • The default value should provide sufficient performance in most cases.

NOTE: Modifying this parameter does not modify the results of the query

ReturnsA reven2.trace.Context or None if no context was found.
def search_in_memory(self, pattern, address, size, is_forward=True):

Iterate the search range looking for the specified pattern. Search range is:

  • [address, address + size[ in forward direction
  • [address - size, address[ in backward direction

This method returns a generator of addresses corresponding to the addresses where the searched pattern matches.

Information

ParameterspatternA str or bytearray. The pattern to look for in memory. Note: str pattern is converted to bytearray using ascci encoding.
addressa 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.
sizean Integer representing the size, in bytes, of the search range.
is_forwardbool, True to search in forward direction and False to search in backward direction
Returnsa generator of addresses corresponding to the addresses where the searched pattern matches.
RaisesTypeErrorif address is not a Integer or one of the address classes on reven2.address.
RunTimeErrorIf the address is a virtual address that is not aligned to its corresponding physical address.
def _read_size(self, source, size, raw):
Undocumented
def _read_as(self, source, ty):
Undocumented
def _read_raw(self, source, size):
Undocumented
def _read_st_register(self, register, size):
Undocumented
def _read_register(self, register, size):
Undocumented
def __str__(self):
Undocumented
def __repr__(self):
Undocumented
def __eq__(self, other):
Undocumented
def __ne__(self, other):
Undocumented
def __lt__(self, other):
Undocumented
def __le__(self, other):
Undocumented
def __gt__(self, other):
Undocumented
def __ge__(self, other):
Undocumented
def __add__(self, other):
Undocumented
def __sub__(self, other):
Undocumented
@property
def _rvn(self):
Undocumented
API Documentation for reven2, generated by pydoctor at 2020-09-17 15:57:19.