Source code for malduck.procmem.region

# Copyright (C) 2018 Jurriaan Bremer.
# This file is part of Roach - https://github.com/jbremer/roach.
# See the file 'docs/LICENSE.txt' for copying permission.
from typing import Dict, Optional, Union

__all__ = [
    "Region",
    "PAGE_READONLY",
    "PAGE_READWRITE",
    "PAGE_WRITECOPY",
    "PAGE_EXECUTE",
    "PAGE_EXECUTE_READ",
    "PAGE_EXECUTE_READWRITE",
    "PAGE_EXECUTE_WRITECOPY",
]

PAGE_READONLY = 0x00000002
PAGE_READWRITE = 0x00000004
PAGE_WRITECOPY = 0x00000008
PAGE_EXECUTE = 0x00000010
PAGE_EXECUTE_READ = 0x00000020
PAGE_EXECUTE_READWRITE = 0x00000040
PAGE_EXECUTE_WRITECOPY = 0x00000080

page_access = {
    PAGE_READONLY: "r",
    PAGE_READWRITE: "rw",
    PAGE_WRITECOPY: "rwc",
    PAGE_EXECUTE: "rx",
    PAGE_EXECUTE_READ: "rx",
    PAGE_EXECUTE_READWRITE: "rwx",
    PAGE_EXECUTE_WRITECOPY: "rwxc",
}


[docs]class Region: """Represents single mapped region in :class:`ProcessMemory`""" def __init__( self, addr: int, size: int, state: int, type_: int, protect: int, offset: int ) -> None: self.addr = addr self.size = size self.state = state self.type_ = type_ self.protect = protect self.offset = offset
[docs] def to_json(self) -> Dict[str, Union[int, Optional[str]]]: """ Returns JSON-like dict representation """ return { "addr": "0x%08x" % self.addr, "end": "0x%08x" % (self.addr + self.size), "size": self.size, "state": self.state, "type": self.type_, "protect": page_access.get(self.protect), "offset": self.offset, }
@property def end(self) -> int: """ Virtual address of region end (first unmapped byte) """ return self.addr + self.size @property def end_offset(self) -> int: """ Offset of region end (first unmapped byte) """ return self.offset + self.size @property def last(self) -> int: """ Virtual address of last region byte """ return self.addr + self.size - 1 @property def last_offset(self) -> int: """ Offset of last region byte """ return self.offset + self.size - 1
[docs] def v2p(self, addr: int) -> int: """ Virtual address to physical offset translation. Assumes that address is valid within Region. :param addr: Virtual address :return: Physical offset """ return self.offset + addr - self.addr
[docs] def p2v(self, off: int) -> int: """ Physical offset to translation. Assumes that offset is valid within Region. :param off: Physical offset :return: Virtual address """ return self.addr + off - self.offset
[docs] def contains_offset(self, offset: int) -> bool: """ Checks whether region contains provided physical offset """ return self.offset <= offset < self.offset + self.size
[docs] def contains_addr(self, addr: int) -> bool: """ Checks whether region contains provided virtual address """ return self.addr <= addr < self.end
[docs] def intersects_range(self, addr: int, length: int) -> bool: """ Checks whether region mapping intersects with provided range """ return self.addr < addr + length and addr < self.end
[docs] def trim_range(self, addr: int, length: Optional[int] = None) -> Optional["Region"]: """ Returns region intersection with provided range :param addr: Virtual address of starting point :param length: Length of range (optional) :rtype: :class:`Region` """ new_addr = max(self.addr, addr) new_end = min(self.end, addr + length) if length is not None else self.end if new_end <= new_addr: return None new_offset = self.v2p(new_addr) return Region( new_addr, new_end - new_addr, self.state, self.type_, self.protect, new_offset, )
def __eq__(self, other: object) -> bool: if not isinstance(other, Region): raise ValueError("Not a region object!") return ( self.addr == other.addr and self.size == other.size and self.state == other.state and self.type_ == other.type_ and self.protect == other.protect and self.offset == other.offset )