summaryrefslogtreecommitdiffstats
path: root/sploit/payload/gadhint.py
diff options
context:
space:
mode:
authorMalfurious <m@lfurio.us>2025-01-01 06:51:10 -0500
committerMalfurious <m@lfurio.us>2025-01-01 06:51:10 -0500
commitf01ec45e773291c3659a1dcaf8cd9a51ece19823 (patch)
tree0db3ef432a6f3b06c07060bdb0dd61c7fd164ad2 /sploit/payload/gadhint.py
parent3f5532857807d628a5dadaf5c30a384f873878ea (diff)
parent221742f7c5c89dc50ec4374bed5d2ccc0d7534bf (diff)
downloadnsploit-f01ec45e773291c3659a1dcaf8cd9a51ece19823.tar.gz
nsploit-f01ec45e773291c3659a1dcaf8cd9a51ece19823.zip
Merge branch 'pkg-reorg'
This branch is a rework of nsploit's intended package imports. User scripts need only import a given nsploit subpackage to obtain that package's full collection of classes, functions, etc. This is the new intended style for exploit scripts. Along the way, some modules are reorganized into different packages, the "builder" package is renamed to "payload", and some unnecessary files are consolidated. * pkg-reorg: main: Automatically provide top-level sploit modules to user scripts sploit: Expose modules' contents through package Remove extra "main.py" file comm: Promote from module to package log: Move to sploit.util package util: Promote from module to package builder: Rename package to payload and expose contents rev: Expose modules' contents through package Remove outer __init__.py file
Diffstat (limited to 'sploit/payload/gadhint.py')
-rw-r--r--sploit/payload/gadhint.py109
1 files changed, 109 insertions, 0 deletions
diff --git a/sploit/payload/gadhint.py b/sploit/payload/gadhint.py
new file mode 100644
index 0000000..9b077fe
--- /dev/null
+++ b/sploit/payload/gadhint.py
@@ -0,0 +1,109 @@
+from dataclasses import dataclass, field
+from sploit.rev.gadget import Gadget
+
+@dataclass
+class GadHint:
+ """
+ User-annotated gadget description object
+
+ gadget (Gadget|int): The gadget being annotated. May be a Gadget object or
+ an offset as an int.
+
+ pops (list[str]): The registers popped by this gadget, in order of
+ occurrence.
+
+ movs (dict{str:str}): The register-to-register moves made by this gadget.
+ Keys are destination register names, values are source register names. The
+ order given is insignificant.
+
+ imms (dict{str:int}): The immediate-to-register loads made by this gadget.
+ Keys are destination register names, values are immediate values. The order
+ given is insignificant.
+
+ writes (dict{str:str}): The register-to-memory moves (stores) made by this
+ gadget. Keys are destination register names (expected to hold memory
+ locations), values are source register names (expected to hold direct
+ values). The order given is insignificant.
+
+ requirements (dict{str:int}): The register state that is required before
+ this gadget should be executed. Keys are register names, values are the
+ required register values.
+
+ stack (list[int]): A list of words to append to the stack following this
+ gadget. The first element given is nearest to the top of the stack and the
+ rest follow in order.
+
+ align (bool): If True, this gadget expects the stack to be aligned prior
+ to entry.
+
+ syscall (bool): If True, this gadget contains a syscall instruction.
+
+ spm (int): "Stack pointer move" - The amount the stack pointer is adjusted
+ by this gadget. The effect of executing a terminating "return" instruction
+ should not be accounted for. A value of zero is taken as "unspecified".
+ """
+
+ gadget: int = 0
+ pops: list = field(default_factory=list)
+ movs: dict = field(default_factory=dict)
+ imms: dict = field(default_factory=dict)
+ writes: dict = field(default_factory=dict)
+ requirements: dict = field(default_factory=dict)
+ stack: list = field(default_factory=list)
+ align: bool = False
+ syscall: bool = False
+ spm: int = 0
+
+ @property
+ def offset(self):
+ """Return gadget offset as an integer."""
+ return int(self.gadget)
+
+ def __index__(self):
+ """Convert object to integer using offset value."""
+ return self.offset
+
+ def __add__(self, x):
+ """Return new object with adjusted offset."""
+ return GadHint(self.gadget + x, self.pops, self.movs, self.imms,
+ self.writes, self.requirements, self.stack, self.align,
+ self.syscall, self.spm)
+
+ def __sub__(self, x):
+ """Return new object with adjusted offset."""
+ return self + (-x)
+
+ def with_requirements(self, reqs):
+ """Return new object with additional requirements."""
+ for k, v in reqs.items():
+ if self.requirements.get(k, v) != v:
+ raise ValueError(
+ f"GadHint: Conflicting gadget requirements: "
+ f"{self.requirements}, {reqs}")
+
+ return GadHint(self.gadget, self.pops, self.movs, self.imms,
+ self.writes, self.requirements | reqs, self.stack,
+ self.align, self.syscall, self.spm)
+
+ def __repr__(self):
+ """Return human-readable GadHint."""
+ def fmt(name, prop):
+ if len(prop) > 0:
+ return f", {name}={prop}"
+ return ""
+
+ s = hex(self.gadget)
+ s = f"Gadget({s})" if type(self.gadget) is Gadget else s
+ s += fmt("pops", self.pops)
+ s += fmt("movs", self.movs)
+ s += fmt("imms", self.imms)
+ s += fmt("writes", self.writes)
+ s += fmt("requirements", self.requirements)
+ s += fmt("stack", self.stack)
+ if self.align:
+ s += ", align"
+ if self.syscall:
+ s += ", syscall"
+ if self.spm > 0:
+ s += f", spm={self.spm}"
+ return f"GadHint({s})"