Class that manages memory access for gef.
| 10135 | |
| 10136 | |
| 10137 | class GefMemoryManager(GefManager): |
| 10138 | """Class that manages memory access for gef.""" |
| 10139 | def __init__(self) -> None: |
| 10140 | self.reset_caches() |
| 10141 | return |
| 10142 | |
| 10143 | def reset_caches(self) -> None: |
| 10144 | super().reset_caches() |
| 10145 | self.__maps = None |
| 10146 | return |
| 10147 | |
| 10148 | def write(self, address: int, buffer: ByteString, length: int = 0x10) -> None: |
| 10149 | """Write `buffer` at address `address`.""" |
| 10150 | gdb.selected_inferior().write_memory(address, buffer, length) |
| 10151 | |
| 10152 | def read(self, addr: int, length: int = 0x10) -> bytes: |
| 10153 | """Return a `length` long byte array with the copy of the process memory at `addr`.""" |
| 10154 | return gdb.selected_inferior().read_memory(addr, length).tobytes() |
| 10155 | |
| 10156 | def read_integer(self, addr: int) -> int: |
| 10157 | """Return an integer read from memory.""" |
| 10158 | sz = gef.arch.ptrsize |
| 10159 | mem = self.read(addr, sz) |
| 10160 | unpack = u32 if sz == 4 else u64 |
| 10161 | return unpack(mem) |
| 10162 | |
| 10163 | def read_cstring(self, |
| 10164 | address: int, |
| 10165 | max_length: int = GEF_MAX_STRING_LENGTH, |
| 10166 | encoding: Optional[str] = None) -> str: |
| 10167 | """Return a C-string read from memory.""" |
| 10168 | encoding = encoding or "unicode-escape" |
| 10169 | length = min(address | (DEFAULT_PAGE_SIZE-1), max_length+1) |
| 10170 | |
| 10171 | try: |
| 10172 | res_bytes = self.read(address, length) |
| 10173 | except gdb.error: |
| 10174 | err(f"Can't read memory at '{address}'") |
| 10175 | return "" |
| 10176 | try: |
| 10177 | with warnings.catch_warnings(): |
| 10178 | # ignore DeprecationWarnings (see #735) |
| 10179 | warnings.simplefilter("ignore") |
| 10180 | res = res_bytes.decode(encoding, "strict") |
| 10181 | except UnicodeDecodeError: |
| 10182 | # latin-1 as fallback due to its single-byte to glyph mapping |
| 10183 | res = res_bytes.decode("latin-1", "replace") |
| 10184 | |
| 10185 | res = res.split("\x00", 1)[0] |
| 10186 | ustr = res.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t") |
| 10187 | if max_length and len(res) > max_length: |
| 10188 | return f"{ustr[:max_length]}[...]" |
| 10189 | return ustr |
| 10190 | |
| 10191 | def read_ascii_string(self, address: int) -> Optional[str]: |
| 10192 | """Read an ASCII string from memory""" |
| 10193 | cstr = self.read_cstring(address) |
| 10194 | if isinstance(cstr, str) and cstr and all(x in string.printable for x in cstr): |
no outgoing calls
no test coverage detected