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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
from __future__ import absolute_import
from __future__ import division
import itertools
import os
import re
import six
import sys
from types import ModuleType
from pwnlib import constants
from pwnlib.context import context
from pwnlib.shellcraft import internal
from pwnlib.util import packing
class module(ModuleType):
_templates = []
def __init__(self, name, directory):
super(module, self).__init__(name)
# Insert nice properties
self.__dict__.update({
'__file__': __file__,
'__package__': __package__,
'__path__': __path__,
})
# Save the shellcode directory
self._dir = directory
# Find the absolute path of the directory
self._absdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', self._dir)
# Get the docstring
with open(os.path.join(self._absdir, "__doc__")) as fd:
self.__doc__ = fd.read()
# Insert into the module list
sys.modules[self.__name__] = self
def _get_source(self, template):
assert template in self.templates
return os.path.join(self._absdir, *template.split('.')) + '.asm'
def __lazyinit__(self):
# Create a dictionary of submodules
self._submodules = {}
self._shellcodes = {}
for name in os.listdir(self._absdir):
path = os.path.join(self._absdir, name)
if os.path.isdir(path):
self._submodules[name] = module(self.__name__ + '.' + name, os.path.join(self._dir, name))
elif os.path.isfile(path) and name != '__doc__' and name[0] != '.':
funcname, _ext = os.path.splitext(name)
if not re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', funcname):
raise ValueError("found illegal filename, %r" % name)
self._shellcodes[funcname] = name
# Put the submodules into toplevel
self.__dict__.update(self._submodules)
# These are exported
self.__all__ = sorted(itertools.chain(self._shellcodes.keys(), self._submodules.keys()))
# Make sure this is not called again
self.__lazyinit__ = None
def __getattr__(self, key):
self.__lazyinit__ and self.__lazyinit__()
# Maybe the lazyinit added it
if key in self.__dict__:
return self.__dict__[key]
# This function lazy-loads the shellcodes
if key in self._shellcodes:
real = internal.make_function(key, self._shellcodes[key], self._dir)
setattr(self, key, real)
return real
for m in self._context_modules():
try:
return getattr(m, key)
except AttributeError:
pass
raise AttributeError("'module' object has no attribute '%s'" % key)
def __dir__(self):
# This function lists the available submodules, available shellcodes
# and potentially shellcodes available in submodules that should be
# avilable because of the context
self.__lazyinit__ and self.__lazyinit__()
result = list(self._submodules.keys())
result.extend(('__file__', '__package__', '__path__',
'__all__', '__name__'))
result.extend(self.__shellcodes__())
return result
def _context_modules(self):
self.__lazyinit__ and self.__lazyinit__()
for k, m in self._submodules.items():
if k in [context.arch, context.os, 'syscalls']:
yield m
def __shellcodes__(self):
self.__lazyinit__ and self.__lazyinit__()
result = list(self._shellcodes.keys())
for m in self._context_modules():
result.extend(m.__shellcodes__())
return result
@property
def templates(self):
if self._templates:
return self._templates
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
templates = []
for root, _, files in os.walk(template_dir, followlinks=True):
for file in filter(lambda x: x.endswith('.asm'), files):
value = os.path.splitext(file)[0]
value = os.path.join(root, value)
value = value.replace(template_dir, '')
value = value.replace(os.path.sep, '.')
value = value.lstrip('.')
templates.append(value)
templates = sorted(templates)
self._templates = templates
return templates
def eval(self, item):
if isinstance(item, six.integer_types):
return item
return constants.eval(item)
def pretty(self, n, comment=True):
if isinstance(n, (str, bytes, list, tuple, dict)):
r = repr(n)
if not comment: # then it can be inside a comment!
r = r.replace('*/', r'\x2a/')
return r
if not isinstance(n, six.integer_types):
return n
if isinstance(n, constants.Constant):
if comment: return '%s /* %s */' % (n,self.pretty(int(n)))
else: return '%s (%s)' % (n,self.pretty(int(n)))
elif abs(n) < 10:
return '%d' % n
else:
return '%#x' % n
def okay(self, s, *a, **kw):
if isinstance(s, six.integer_types):
s = packing.pack(s, *a, **kw)
return b'\0' not in s and b'\n' not in s
from pwnlib.shellcraft import registers
# To prevent garbage collection
tether = sys.modules[__name__]
# Create the module structure
shellcraft = module(__name__, '')
class LazyImporter:
def find_module(self, fullname, path=None):
if not fullname.startswith('pwnlib.shellcraft.'):
return None
parts = fullname.split('.')[2:]
cur = shellcraft
for part in parts:
cur = getattr(cur, part, None)
if not isinstance(cur, ModuleType):
return None
return self
def load_module(self, fullname):
return sys.modules[fullname]
sys.meta_path.append(LazyImporter())
|