|
| 1 | +# |
| 2 | +# This file is part of libdestruct (https://github.com/mrindeciso/libdestruct). |
| 3 | +# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved. |
| 4 | +# Licensed under the MIT license. See LICENSE file in the project root for details. |
| 5 | +# |
| 6 | + |
| 7 | +from __future__ import annotations |
| 8 | + |
| 9 | +from typing import TYPE_CHECKING |
| 10 | + |
| 11 | +from libdestruct.backing.resolver import Resolver |
| 12 | + |
| 13 | + |
| 14 | +class FakeResolver(Resolver): |
| 15 | + """A class that can resolve elements in a simulated memory storage.""" |
| 16 | + |
| 17 | + def __init__(self: FakeResolver, memory: dict | None = None, address: int | None = 0) -> FakeResolver: |
| 18 | + """Initializes a basic fake resolver.""" |
| 19 | + self.memory = memory if memory is not None else {} |
| 20 | + self.address = address |
| 21 | + self.parent = None |
| 22 | + self.offset = None |
| 23 | + |
| 24 | + def resolve_address(self: FakeResolver) -> int: |
| 25 | + """Resolves self's address, mainly used by children to determine their own address.""" |
| 26 | + if self.address is not None: |
| 27 | + return self.address |
| 28 | + |
| 29 | + return self.parent.resolve_address() + self.offset |
| 30 | + |
| 31 | + def relative_from_own(self: FakeResolver, address_offset: int, _: int) -> FakeResolver: |
| 32 | + """Creates a resolver that references a parent, such that a change in the parent is propagated on the child.""" |
| 33 | + new_resolver = FakeResolver(self.memory, None) |
| 34 | + new_resolver.parent = self |
| 35 | + new_resolver.offset = address_offset |
| 36 | + return new_resolver |
| 37 | + |
| 38 | + def absolute_from_own(self: FakeResolver, address: int) -> FakeResolver: |
| 39 | + """Creates a resolver that has an absolute reference to an object, from the parent's view.""" |
| 40 | + return FakeResolver(self.memory, address) |
| 41 | + |
| 42 | + def resolve(self: FakeResolver, size: int, _: int) -> bytes: |
| 43 | + """Resolves itself, providing the bytes it references for the specified size and index.""" |
| 44 | + address = self.resolve_address() |
| 45 | + # We store data in the dictionary as 4K pages |
| 46 | + page_address = address & ~0xFFF |
| 47 | + page_offset = address & 0xFFF |
| 48 | + |
| 49 | + result = b"" |
| 50 | + |
| 51 | + while size: |
| 52 | + page = self.memory.get(page_address, b"\x00" * (0x1000 - page_offset)) |
| 53 | + page_size = min(size, 0x1000 - page_offset) |
| 54 | + result += page[page_offset : page_offset + page_size] |
| 55 | + size -= page_size |
| 56 | + page_address += 0x1000 |
| 57 | + page_offset = 0 |
| 58 | + |
| 59 | + return result |
| 60 | + |
| 61 | + def modify(self: FakeResolver, size: int, _: int, value: bytes) -> None: |
| 62 | + """Modifies itself in memory.""" |
| 63 | + address = self.resolve_address() |
| 64 | + # We store data in the dictionary as 4K pages |
| 65 | + page_address = address & ~0xFFF |
| 66 | + page_offset = address & 0xFFF |
| 67 | + |
| 68 | + while size: |
| 69 | + page = self.memory.get(page_address, b"\x00" * 0x1000) |
| 70 | + page_size = min(size, 0x1000 - page_offset) |
| 71 | + page = page[:page_offset] + value[:page_size] + page[page_offset + page_size :] |
| 72 | + self.memory[page_address] = page |
| 73 | + size -= page_size |
| 74 | + value = value[page_size:] |
| 75 | + page_address += 0x1000 |
| 76 | + page_offset = 0 |
0 commit comments