diff options
-rw-r--r-- | pyproject.toml | 2 | ||||
-rw-r--r-- | sploit/builder/__init__.py | 1 | ||||
-rw-r--r-- | sploit/builder/gadhint.py | 109 |
3 files changed, 111 insertions, 1 deletions
diff --git a/pyproject.toml b/pyproject.toml index d4aa8b3..041ee3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "sploit" description = "sploit is a process interaction automation tool with software exploitation focused utilities." readme = "README.txt" -requires-python = ">=3.8" +requires-python = ">=3.9" license = "Unlicense" license-files.paths = ["UNLICENSE"] authors = [ diff --git a/sploit/builder/__init__.py b/sploit/builder/__init__.py index 54e5fd5..f4638af 100644 --- a/sploit/builder/__init__.py +++ b/sploit/builder/__init__.py @@ -1,3 +1,4 @@ from . import ( + gadhint, payload, ) diff --git a/sploit/builder/gadhint.py b/sploit/builder/gadhint.py new file mode 100644 index 0000000..9b077fe --- /dev/null +++ b/sploit/builder/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})" |