From f525e902b574d23d3b80a16a84c55818fabb8144 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Sun, 16 Mar 2025 22:11:28 -0400 Subject: symtbl: Move to types package Move Symtbl to the types subpackage, where the other IndexTbl modules reside. This is a more logical home for this module since it represents more of a pure data storage type. Signed-off-by: Malfurious --- nsploit/__init__.py | 1 - nsploit/rev/r2.py | 2 +- nsploit/symtbl.py | 160 ---------------------------------------------- nsploit/types/__init__.py | 1 + nsploit/types/symtbl.py | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 162 deletions(-) delete mode 100644 nsploit/symtbl.py create mode 100644 nsploit/types/symtbl.py diff --git a/nsploit/__init__.py b/nsploit/__init__.py index aef38c4..024fca1 100644 --- a/nsploit/__init__.py +++ b/nsploit/__init__.py @@ -1,5 +1,4 @@ from nsploit.arch import * -from nsploit.symtbl import * from nsploit.until import * # Shout out: https://stackoverflow.com/questions/67085041 diff --git a/nsploit/rev/r2.py b/nsploit/rev/r2.py index 5f20f0a..f4f2a5e 100644 --- a/nsploit/rev/r2.py +++ b/nsploit/rev/r2.py @@ -1,6 +1,6 @@ from nsploit.arch import arch from nsploit.rev.gadget import Gadget -from nsploit.symtbl import Symtbl +from nsploit.types.symtbl import Symtbl from nsploit.util.cmd import run_cmd_cached from nsploit.util.log import ilog diff --git a/nsploit/symtbl.py b/nsploit/symtbl.py deleted file mode 100644 index e171986..0000000 --- a/nsploit/symtbl.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -Symtbl data structure - -A Symtbl (symbol table) is an associative data container intended to model -arbitrary memory layouts, such as structure definitions or memory-mapped -objects. Elements may be accessed via subscript or attribute notation. - -A Symtbl is essentially a dictionary, in which each key (symbol name string) -is associated with an offset value. A special key "base" represents the -base or starting address of the overall table in memory. Whenever offset -values are accessed, they are adjusted relative to the table's base value. -This enables the primary function of Symtbl objects: the ability to resolve -mapped, or absolute, addresses of objects in memory. - -Therefore, even though a Symtbl internally tracks symbol offsets, the apparent -value of any symbol will always be its offset plus the table's base address. -The table's base address will also be subtracted from values being stored in -the table, as the provided value is assumed to be mapped in the same manner as -the table itself. - - s = Symtbl() - s.a = 10 - s.b = 20 - print(s.a, s.b) # "10 20" - s.base = 100 - print(s.a, s.b) # "110 120" - s.c = 150 - s.base = 10 - print(s.a, s.b, s.c) # "20 30 60" - -A Symtbl's base value may be changed at any time, and this will affect the -interpretation of offsets as described above. However, one may also create a -remapped version of a Symtbl (without modifying the original) using the '@' -operator. This new object will have the base value given on the right hand -side of the '@' and its collection of symbols is referentially linked to the -source object, meaning changes to symbol entries will be visible in both -objects. - - s1 = Symtbl() - s1.a = 10 - s2 = s1 @ 1000 - print(s1.a, s2.a) # "10 1010" - s2.b = 1234 - print(s1.b, s2.b) # "234 1234" - -Symtbl's are also nestable, to support modeling composite memory layouts. If -a symbol's value is assigned to another Symtbl object, rather than an integer -offset, the child object's base value serves as its offset in the parent -Symtbl. Symbols on the child object may then be accessed recursively from the -parent's scope. If the parent has a non-zero base, it adjusts the offsets -interpreted in the child. - - child = Symtbl() - child.a = 1 - child.b = 2 - parent = Symtbl() - parent.nested = child @ 70 - print(parent.nested.a, parent.nested.b) # "71 72" - -A Symtbl will allow you to uniformly adjust all offsets contained, while leaving -the base value the same, using the '<<' and '>>' operators. A custom -"rebase" operation is also available via the "%" operator. A rebase applies -a uniform shift, such that the right hand side offset operand ends up coinciding -with the Symtbl base address. - - s = Symtbl() - s.a = 1 - s.b = 2 - s.c = 3 - s.d = 4 - s.base = 1000 - s %= s.c # rebase at symbol 'c' - print(s.a, s.b, s.c, s.d) # "998 999 1000 1001" -""" - -from nsploit.types.indextbl import IndexTbl -from nsploit.types.index_entry import IndexEntry - -def Symtbl(*, base=0, **symbols): - """ - Create a new Symtbl object. - - Return an empty Symtbl or, optionally, one initialized with the given - symbol values. Arguments must be keyword arguments. - - Users should call this function instead of attempting to construct the - Symtbl class. Construction is implemented via a normal function to prevent - any argument name from conflicting with __init__'s bound instance parameter. - """ - self = SymtblImpl(base, 0, dict()) - for k, v in symbols.items(): - self[k] = v - return self - -class SymtblImpl(IndexTbl): - """Symtbl implementation class""" - - def __init__(self, base, adjust, entries): - """Construct Symtbl from instance data.""" - super().__init__(base) - object.__setattr__(self, "__adjust__", adjust) - object.__setattr__(self, "__entries__", entries) - - def __repr__(self): - """Return human-readable Symtbl.""" - FMT = "\n{:<20} {:<20}" - s = f"{len(self)} symbols @ {hex(self)}" - - if len(self) > 0: - s += FMT.format("ADDRESS", "SYMBOL") - - for key, value in self: - key = f"[{key}]" if isinstance(value, IndexEntry) else key - s += FMT.format(hex(value), key) - - return s - - def __rshift__(self, offset): - """Return symbol-adjusted version of object.""" - adjust = self.__adjust__ + int(offset) - return SymtblImpl(self.base, adjust, self.__entries__) - - def __lshift__(self, offset): - """Return symbol-adjusted version of object.""" - return self >> (-offset) - - def __mod__(self, offset): - """Return symbol-rebased version of object.""" - return self >> (self.base - offset) - - # IndexTbl abstract methods - - def __copy__(self): - """Return copy of object with shared symbol entries.""" - return SymtblImpl(self.base, self.__adjust__, self.__entries__) - - def __iter__(self): - """Iterate over table items, sorted by offsets.""" - it = { k: self[k] for k in self.__entries__}.items() - return iter(sorted(it, key=lambda x: int(x[1]))) - - def __len__(self): - """Return number of defined symbols.""" - return len(self.__entries__) - - def __getindex__(self, index): - """Return symbol value or translated offset.""" - if isinstance(index, (int, IndexEntry)): offset = index - else: offset = self.__entries__[index] - return offset + (self.base + self.__adjust__) - - def __setindex__(self, index, value): - """Set symbol value.""" - if isinstance(index, (int, IndexEntry)): - raise TypeError(f"Symtbl: Unsupported key type: {type(index)}") - self.__entries__[index] = value - (self.base + self.__adjust__) - - def __delindex__(self, index): - """Delete symbol.""" - del self.__entries__[index] diff --git a/nsploit/types/__init__.py b/nsploit/types/__init__.py index 9f2fb30..1e32208 100644 --- a/nsploit/types/__init__.py +++ b/nsploit/types/__init__.py @@ -3,3 +3,4 @@ from .index_entry import * from .lict import * from .payload import * from .payload_entry import * +from .symtbl import * diff --git a/nsploit/types/symtbl.py b/nsploit/types/symtbl.py new file mode 100644 index 0000000..e171986 --- /dev/null +++ b/nsploit/types/symtbl.py @@ -0,0 +1,160 @@ +""" +Symtbl data structure + +A Symtbl (symbol table) is an associative data container intended to model +arbitrary memory layouts, such as structure definitions or memory-mapped +objects. Elements may be accessed via subscript or attribute notation. + +A Symtbl is essentially a dictionary, in which each key (symbol name string) +is associated with an offset value. A special key "base" represents the +base or starting address of the overall table in memory. Whenever offset +values are accessed, they are adjusted relative to the table's base value. +This enables the primary function of Symtbl objects: the ability to resolve +mapped, or absolute, addresses of objects in memory. + +Therefore, even though a Symtbl internally tracks symbol offsets, the apparent +value of any symbol will always be its offset plus the table's base address. +The table's base address will also be subtracted from values being stored in +the table, as the provided value is assumed to be mapped in the same manner as +the table itself. + + s = Symtbl() + s.a = 10 + s.b = 20 + print(s.a, s.b) # "10 20" + s.base = 100 + print(s.a, s.b) # "110 120" + s.c = 150 + s.base = 10 + print(s.a, s.b, s.c) # "20 30 60" + +A Symtbl's base value may be changed at any time, and this will affect the +interpretation of offsets as described above. However, one may also create a +remapped version of a Symtbl (without modifying the original) using the '@' +operator. This new object will have the base value given on the right hand +side of the '@' and its collection of symbols is referentially linked to the +source object, meaning changes to symbol entries will be visible in both +objects. + + s1 = Symtbl() + s1.a = 10 + s2 = s1 @ 1000 + print(s1.a, s2.a) # "10 1010" + s2.b = 1234 + print(s1.b, s2.b) # "234 1234" + +Symtbl's are also nestable, to support modeling composite memory layouts. If +a symbol's value is assigned to another Symtbl object, rather than an integer +offset, the child object's base value serves as its offset in the parent +Symtbl. Symbols on the child object may then be accessed recursively from the +parent's scope. If the parent has a non-zero base, it adjusts the offsets +interpreted in the child. + + child = Symtbl() + child.a = 1 + child.b = 2 + parent = Symtbl() + parent.nested = child @ 70 + print(parent.nested.a, parent.nested.b) # "71 72" + +A Symtbl will allow you to uniformly adjust all offsets contained, while leaving +the base value the same, using the '<<' and '>>' operators. A custom +"rebase" operation is also available via the "%" operator. A rebase applies +a uniform shift, such that the right hand side offset operand ends up coinciding +with the Symtbl base address. + + s = Symtbl() + s.a = 1 + s.b = 2 + s.c = 3 + s.d = 4 + s.base = 1000 + s %= s.c # rebase at symbol 'c' + print(s.a, s.b, s.c, s.d) # "998 999 1000 1001" +""" + +from nsploit.types.indextbl import IndexTbl +from nsploit.types.index_entry import IndexEntry + +def Symtbl(*, base=0, **symbols): + """ + Create a new Symtbl object. + + Return an empty Symtbl or, optionally, one initialized with the given + symbol values. Arguments must be keyword arguments. + + Users should call this function instead of attempting to construct the + Symtbl class. Construction is implemented via a normal function to prevent + any argument name from conflicting with __init__'s bound instance parameter. + """ + self = SymtblImpl(base, 0, dict()) + for k, v in symbols.items(): + self[k] = v + return self + +class SymtblImpl(IndexTbl): + """Symtbl implementation class""" + + def __init__(self, base, adjust, entries): + """Construct Symtbl from instance data.""" + super().__init__(base) + object.__setattr__(self, "__adjust__", adjust) + object.__setattr__(self, "__entries__", entries) + + def __repr__(self): + """Return human-readable Symtbl.""" + FMT = "\n{:<20} {:<20}" + s = f"{len(self)} symbols @ {hex(self)}" + + if len(self) > 0: + s += FMT.format("ADDRESS", "SYMBOL") + + for key, value in self: + key = f"[{key}]" if isinstance(value, IndexEntry) else key + s += FMT.format(hex(value), key) + + return s + + def __rshift__(self, offset): + """Return symbol-adjusted version of object.""" + adjust = self.__adjust__ + int(offset) + return SymtblImpl(self.base, adjust, self.__entries__) + + def __lshift__(self, offset): + """Return symbol-adjusted version of object.""" + return self >> (-offset) + + def __mod__(self, offset): + """Return symbol-rebased version of object.""" + return self >> (self.base - offset) + + # IndexTbl abstract methods + + def __copy__(self): + """Return copy of object with shared symbol entries.""" + return SymtblImpl(self.base, self.__adjust__, self.__entries__) + + def __iter__(self): + """Iterate over table items, sorted by offsets.""" + it = { k: self[k] for k in self.__entries__}.items() + return iter(sorted(it, key=lambda x: int(x[1]))) + + def __len__(self): + """Return number of defined symbols.""" + return len(self.__entries__) + + def __getindex__(self, index): + """Return symbol value or translated offset.""" + if isinstance(index, (int, IndexEntry)): offset = index + else: offset = self.__entries__[index] + return offset + (self.base + self.__adjust__) + + def __setindex__(self, index, value): + """Set symbol value.""" + if isinstance(index, (int, IndexEntry)): + raise TypeError(f"Symtbl: Unsupported key type: {type(index)}") + self.__entries__[index] = value - (self.base + self.__adjust__) + + def __delindex__(self, index): + """Delete symbol.""" + del self.__entries__[index] -- cgit v1.2.3