from sploit.arch import arch, itob
from sploit.mem import Symtbl
# Users can set this to the (absolute) address of a 'ret' ROP gadget. Some
# features may require it.
RETGADGET : int = None
class Placeholder(bytearray):
def __init__(self, text='_unnamed_'):
self += bytearray(itob(0))
self.text = text
class Payload:
def __init__(self, size=0, base=0, **kwargs):
self.payload = b''
self.size = size
self.alignstart = None
self.tab = Symtbl(base=base, **kwargs)
def __len__(self):
return len(self.payload)
def __getattr__(self, sym):
return getattr(self.tab, sym)
def data(self, x, sym='_'):
off = len(self)
self.payload += x
setattr(self.tab, sym, off)
return getattr(self.tab, sym)
def value(self, x, sym='_', signed=False):
return self.data(itob(x, signed=signed), sym=sym)
def ret(self, x, sym='_'):
self.align()
return self.value(x, sym=sym)
def stuff(self, x, size, sym='_', *, explain=''):
if size >= 0:
if (size := size / len(x)) == int(size):
if size == 0 or not isinstance(x, Placeholder):
return self.data(x * int(size), sym=sym)
raise Exception(explain+"Can not stuff payload: "
f"Placeholder for {x.text} detected")
raise Exception(explain+"Can not stuff payload: "
"Element does not divide the space evenly")
raise Exception(explain+"Can not stuff payload: "
"Available space is negative")
def pad(self, x=None, sym='_'):
size = self.size - len(self)
return self.stuff((x or arch.nopcode), size, sym=sym,
explain='Error padding payload: ')
def align(self, x=None, sym='_'):
if self.alignstart is None:
self.alignstart = len(self)
retgad = (itob(RETGADGET) if RETGADGET else Placeholder('ret gadget'))
size = (self.alignstart - len(self)) % arch.alignment
return self.stuff((x or retgad), size, sym=sym,
explain='Error aligning payload: ')