• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 13600950642

01 Mar 2025 04:10AM UTC coverage: 74.211% (+3.2%) from 71.055%
13600950642

Pull #2546

github

web-flow
Merge 77df40314 into 60cff2437
Pull Request #2546: ssh: Allow passing `disabled_algorithms` keyword argument from `ssh` to paramiko

3812 of 6380 branches covered (59.75%)

0 of 1 new or added line in 1 file covered. (0.0%)

1243 existing lines in 37 files now uncovered.

13352 of 17992 relevant lines covered (74.21%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.06
/pwnlib/shellcraft/__init__.py
1
from __future__ import absolute_import
1✔
2
from __future__ import division
1✔
3

4
import itertools
1✔
5
import os
1✔
6
import re
1✔
7
import sys
1✔
8
from types import ModuleType
1✔
9

10
from pwnlib import constants
1✔
11
from pwnlib.context import context
1✔
12
from pwnlib.shellcraft import internal
1✔
13
from pwnlib.util import packing
1✔
14

15

16
class module(ModuleType):
1✔
17
    _templates = []
1✔
18

19
    def __init__(self, name, directory):
1✔
20
        super(module, self).__init__(name)
1✔
21

22
        # Insert nice properties
23
        self.__dict__.update({
1✔
24
            '__file__':    __file__,
25
            '__package__': __package__,
26
            '__path__':    __path__,
27
        })
28

29
        # Save the shellcode directory
30
        self._dir = directory
1✔
31

32
        # Find the absolute path of the directory
33
        self._absdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', self._dir)
1✔
34

35
        # Get the docstring
36
        with open(os.path.join(self._absdir, "__doc__")) as fd:
1✔
37
            self.__doc__ = fd.read()
1✔
38

39
        # Insert into the module list
40
        sys.modules[self.__name__] = self
1✔
41

42
    def _get_source(self, template):
1✔
43
        assert template in self.templates
1✔
44
        return os.path.join(self._absdir, *template.split('.')) + '.asm'
1✔
45

46
    def __lazyinit__(self):
1✔
47

48
        # Create a dictionary of submodules
49
        self._submodules = {}
1✔
50
        self._shellcodes = {}
1✔
51
        for name in os.listdir(self._absdir):
1✔
52
            path = os.path.join(self._absdir, name)
1✔
53
            if os.path.isdir(path):
1✔
54
                self._submodules[name] = module(self.__name__ + '.' + name, os.path.join(self._dir, name))
1✔
55
            elif os.path.isfile(path) and name != '__doc__' and name[0] != '.':
1✔
56
                funcname, _ext = os.path.splitext(name)
1✔
57
                if not re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', funcname):
1!
UNCOV
58
                    raise ValueError("found illegal filename, %r" % name)
×
59
                self._shellcodes[funcname] = name
1✔
60

61
        # Put the submodules into toplevel
62
        self.__dict__.update(self._submodules)
1✔
63

64
        # These are exported
65
        self.__all__ = sorted(itertools.chain(self._shellcodes.keys(), self._submodules.keys()))
1✔
66

67
        # Make sure this is not called again
68
        self.__lazyinit__ = None
1✔
69

70
    def __getattr__(self, key):
1✔
71
        self.__lazyinit__ and self.__lazyinit__()
1✔
72

73
        # Maybe the lazyinit added it
74
        if key in self.__dict__:
1✔
75
            return self.__dict__[key]
1✔
76

77
        # This function lazy-loads the shellcodes
78
        if key in self._shellcodes:
1✔
79
            real = internal.make_function(key, self._shellcodes[key], self._dir)
1✔
80
            setattr(self, key, real)
1✔
81
            return real
1✔
82

83
        for m in self._context_modules():
1✔
84
            try:
1✔
85
                return getattr(m, key)
1✔
86
            except AttributeError:
1✔
87
                pass
1✔
88

89
        raise AttributeError("'module' object has no attribute '%s'" % key)
1✔
90

91
    def __dir__(self):
1✔
92
        # This function lists the available submodules, available shellcodes
93
        # and potentially shellcodes available in submodules that should be
94
        # avilable because of the context
95
        self.__lazyinit__ and self.__lazyinit__()
1✔
96

97
        result = list(self._submodules.keys())
1✔
98
        result.extend(('__file__', '__package__', '__path__',
1✔
99
                       '__all__',  '__name__'))
100
        result.extend(self.__shellcodes__())
1✔
101

102
        return result
1✔
103

104
    def _context_modules(self):
1✔
105
        self.__lazyinit__ and self.__lazyinit__()
1✔
106
        for k, m in self._submodules.items():
1✔
107
            if k in [context.arch, context.os, 'syscalls']:
1✔
108
                yield m
1✔
109

110
    def __shellcodes__(self):
1✔
111
        self.__lazyinit__ and self.__lazyinit__()
1✔
112
        result = list(self._shellcodes.keys())
1✔
113
        for m in self._context_modules():
1✔
114
            result.extend(m.__shellcodes__())
1✔
115
        return result
1✔
116

117
    @property
1✔
118
    def templates(self):
1✔
119
        if self._templates:
1✔
120
            return self._templates
1✔
121

122
        template_dir = os.path.join(os.path.dirname(__file__), 'templates')
1✔
123
        templates    = []
1✔
124

125
        for root, _, files in os.walk(template_dir, followlinks=True):
1✔
126
            for file in filter(lambda x: x.endswith('.asm'), files):
1✔
127
                value = os.path.splitext(file)[0]
1✔
128
                value = os.path.join(root, value)
1✔
129
                value = value.replace(template_dir, '')
1✔
130
                value = value.replace(os.path.sep, '.')
1✔
131
                value = value.lstrip('.')
1✔
132
                templates.append(value)
1✔
133

134
        templates = sorted(templates)
1✔
135
        self._templates = templates
1✔
136
        return templates
1✔
137

138
    def eval(self, item):
1✔
139
        if isinstance(item, int):
1✔
140
            return item
1✔
141
        return constants.eval(item)
1✔
142

143
    def pretty(self, n, comment=True):
1✔
144
        if isinstance(n, (str, bytes, list, tuple, dict)):
1✔
145
            r = repr(n)
1✔
146
            if not comment:  # then it can be inside a comment!
1✔
147
                r = r.replace('*/', r'\x2a/')
1✔
148
            return r
1✔
149
        if not isinstance(n, int):
1!
UNCOV
150
            return n
×
151
        if isinstance(n, constants.Constant):
1✔
152
            if comment: return '%s /* %s */' % (n,self.pretty(int(n)))
1✔
153
            else:       return '%s (%s)'     % (n,self.pretty(int(n)))
1✔
154
        elif abs(n) < 10:
1✔
155
            return '%d' % n
1✔
156
        else:
157
            return '%#x' % n
1✔
158

159
    def okay(self, s, *a, **kw):
1✔
160
        if isinstance(s, int):
1✔
161
            s = packing.pack(s, *a, **kw)
1✔
162
        return b'\0' not in s and b'\n' not in s
1✔
163

164
    from pwnlib.shellcraft import registers
1✔
165

166
# To prevent garbage collection
167
tether = sys.modules[__name__]
1✔
168

169
# Create the module structure
170
shellcraft = module(__name__, '')
1✔
171

172
class LazyImporter:
1✔
173
    def find_module(self, fullname, path=None):
1✔
174
        if not fullname.startswith('pwnlib.shellcraft.'):
1!
175
            return None
1✔
176

UNCOV
177
        parts = fullname.split('.')[2:]
×
178
        cur = shellcraft
×
179
        for part in parts:
×
180
            cur = getattr(cur, part, None)
×
181
            if not isinstance(cur, ModuleType):
×
182
                return None
×
183

UNCOV
184
        return self
×
185

186
    def load_module(self, fullname):
1✔
UNCOV
187
        return sys.modules[fullname]
×
188

189
sys.meta_path.append(LazyImporter())
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc