| 5204 | |
| 5205 | |
| 5206 | class ExternalStructureManager: |
| 5207 | class Structure: |
| 5208 | def __init__(self, manager: "ExternalStructureManager", mod_path: pathlib.Path, struct_name: str) -> None: |
| 5209 | self.manager = manager |
| 5210 | self.module_path = mod_path |
| 5211 | self.name = struct_name |
| 5212 | self.class_type = self.__get_structure_class() |
| 5213 | # if the symbol points to a class factory method and not a class |
| 5214 | if not hasattr(self.class_type, "_fields_") and callable(self.class_type): |
| 5215 | self.class_type = self.class_type(gef) |
| 5216 | return |
| 5217 | |
| 5218 | def __str__(self) -> str: |
| 5219 | return self.name |
| 5220 | |
| 5221 | def pprint(self) -> None: |
| 5222 | res = [] |
| 5223 | for _name, _type in self.class_type._fields_: |
| 5224 | size = ctypes.sizeof(_type) |
| 5225 | name = Color.colorify(_name, gef.config["pcustom.structure_name"]) |
| 5226 | type = Color.colorify(_type.__name__, gef.config["pcustom.structure_type"]) |
| 5227 | size = Color.colorify(hex(size), gef.config["pcustom.structure_size"]) |
| 5228 | offset = Color.boldify(f"{getattr(self.class_type, _name).offset:04x}") |
| 5229 | res.append(f"{offset} {name:32s} {type:16s} /* size={size} */") |
| 5230 | gef_print("\n".join(res)) |
| 5231 | return |
| 5232 | |
| 5233 | def __get_structure_class(self) -> Type: |
| 5234 | """Returns a tuple of (class, instance) if modname!classname exists""" |
| 5235 | fpath = self.module_path |
| 5236 | spec = importlib.util.spec_from_file_location(fpath.stem, fpath) |
| 5237 | module = importlib.util.module_from_spec(spec) |
| 5238 | sys.modules[fpath.stem] = module |
| 5239 | spec.loader.exec_module(module) |
| 5240 | _class = getattr(module, self.name) |
| 5241 | return _class |
| 5242 | |
| 5243 | def apply_at(self, address: int, max_depth: int, depth: int = 0) -> None: |
| 5244 | """Apply (recursively if possible) the structure format to the given address.""" |
| 5245 | if depth >= max_depth: |
| 5246 | warn("maximum recursion level reached") |
| 5247 | return |
| 5248 | |
| 5249 | # read the data at the specified address |
| 5250 | _structure = self.class_type() |
| 5251 | _sizeof_structure = ctypes.sizeof(_structure) |
| 5252 | |
| 5253 | try: |
| 5254 | data = gef.memory.read(address, _sizeof_structure) |
| 5255 | except gdb.MemoryError: |
| 5256 | err(f"{' ' * depth}Cannot read memory {address:#x}") |
| 5257 | return |
| 5258 | |
| 5259 | # deserialize the data |
| 5260 | length = min(len(data), _sizeof_structure) |
| 5261 | ctypes.memmove(ctypes.addressof(_structure), data, length) |
| 5262 | |
| 5263 | # pretty print all the fields (and call recursively if possible) |