summaryrefslogtreecommitdiffstats
path: root/sploit/payload/payload_entry.py
blob: 2f8dbdd07cdea033dfd169e031fbc684f4553409 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
from sploit.arch import arch, itob
from sploit.types.index_entry import IndexEntry

_PLACEHOLDER_MAGIC = b"\xef"

class PayloadEntry(IndexEntry):
    """Base class for dynamic Payload entries"""

    def __repr__(self):
        """Return human-readable entry description."""
        return f"{self.__class__.__name__}{self.__dict__}"

    def payload_insert(self, payload):
        """
        Called on insert into a payload object.

        Override this method to perform any initialization which requires a
        reference to the payload object.  self.base is set to the insertion
        location.
        """
        pass

    def payload_len(self, payload):
        """
        Called to compute size of this entry.

        Implement this method to calculate the length of this dynamic payload
        entry.  self.base is set to the current entry address or offset.
        """
        raise NotImplementedError

    def payload_bytes(self, payload):
        """
        Called to generate bytes for this entry.

        Implement this method to generate the binary output for this dynamic
        payload entry.  self.base is set to the current entry address or offset.
        """
        raise NotImplementedError

# Concrete payload entry definitions

class pointer(PayloadEntry):
    """Generate an integer which tracks the address of another payload field."""

    def __init__(self, target=None, math=None):
        self.target = target
        self.math = math

    def payload_len(self, payload):
        return arch.wordsize

    def payload_bytes(self, payload):
        if self.target is None:
            addr = self.base
        else:
            addr = payload[self.target]
        if callable(self.math):
            addr = self.math(addr)
        return itob(addr)

class padlen(PayloadEntry):
    """Generate padding to reach a target payload length."""

    def __init__(self, size, data=None):
        self.size = size
        self.data = data

    def payload_len(self, payload):
        return self.size - (self.base - payload.base)

    def payload_bytes(self, payload):
        size = self.payload_len(payload)
        data = self.data or arch.nopcode
        if size < 0:
            raise ValueError("padding: Available space is negative")
        if (size := size / len(data)) != int(size):
            raise ValueError("padding: Element does not divide the space evenly")
        return data * int(size)

class padabs(padlen):
    """Generate padding to reach a target absolute address."""

    def payload_len(self, payload):
        return self.size - self.base

class padrel(padlen):
    """Generate a fixed length of padding (aka: length relative to self)."""

    def payload_len(self, payload):
        return self.size

class padalign(padlen):
    """Generate padding to reach next aligned address."""

    def __init__(self, size=None, data=None, reference=0):
        self.size = size
        self.data = data
        self.reference = reference

    def payload_len(self, payload):
        size = self.size or arch.alignment
        return (self.reference - self.base) % size

class placeholder(padlen):
    """Generate fixed length of magic bytes, one word length by default."""

    def __init__(self, size=None):
        self.size = size
        self.data = _PLACEHOLDER_MAGIC

    def payload_len(self, payload):
        return self.size or arch.wordsize