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

Gallopsled / pwntools / d10b954719aa7fc23a2d293ce0622df3c910d98a-PR-2221

pending completion
d10b954719aa7fc23a2d293ce0622df3c910d98a-PR-2221

Pull #2221

github-actions

web-flow
Merge b6d25b636 into 9c83fa109
Pull Request #2221: Add shellcraft.sleep template wrapping SYS_nanosleep

3639 of 6419 branches covered (56.69%)

11701 of 16706 relevant lines covered (70.04%)

0.7 hits per line

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

16.67
/pwnlib/term/key.py
1
from __future__ import absolute_import
1✔
2
from __future__ import division
1✔
3

4
import errno
1✔
5
import os
1✔
6
import select
1✔
7
import six
1✔
8
import string
1✔
9
import sys
1✔
10

11
from pwnlib.term import keyconsts as kc
1✔
12
from pwnlib.term import termcap
1✔
13

14
__all__ = ['getch', 'getraw', 'get', 'unget']
1✔
15

16
# When set, convert keypad codes into regular key presses, e.g. "+" instead of
17
# `<kp plus>`
18
FLAG_CONVERTKP = True
1✔
19

20
try:    _fd = sys.stdin.fileno()
1✔
21
except Exception: _fd = os.open(os.devnull, os.O_RDONLY)
×
22

23
def getch(timeout = 0):
1✔
24
    while True:
×
25
        try:
×
26
            rfds, _wfds, _xfds = select.select([_fd], [], [], timeout)
×
27
            if rfds:
×
28
                c = os.read(_fd, 1)
×
29
                return ord(c) if c else None
×
30
            else:
31
                return None
×
32
        except select.error as e:
×
33
            if e.args[0] == errno.EINTR:
×
34
                continue
×
35
            raise
×
36

37
def getraw(timeout = None):
1✔
38
    '''Get list of raw key codes corresponding to zero or more key presses'''
39
    cs = []
×
40
    c = getch(timeout)
×
41
    while c is not None: # timeout
×
42
        cs.append(c)
×
43
        if c is None: # EOF
×
44
            break
×
45
        c = getch()
×
46
    return cs
×
47

48
class Matcher:
1✔
49
    def __init__(self, desc):
1✔
50
        self._desc = desc
1✔
51
        desc = desc.split('-')
1✔
52
        mods = desc[:-1]
1✔
53
        k = desc[-1]
1✔
54
        if k == '<space>':
1!
55
            k = ' '
×
56
        m = kc.MOD_NONE
1✔
57
        if 'S' in mods:
1!
58
            m |= kc.MOD_SHIFT
×
59
        if 'M' in mods:
1✔
60
            m |= kc.MOD_ALT
1✔
61
        if 'C' in mods:
1✔
62
            m |= kc.MOD_CTRL
1✔
63
        if   len(k) == 1:
1✔
64
            t = kc.TYPE_UNICODE
1✔
65
            c = k
1✔
66
            h = ord(k)
1✔
67
        elif k[0] == '<' and k in kc.KEY_NAMES_REVERSE:
1!
68
            t = kc.TYPE_KEYSYM
1✔
69
            c = kc.KEY_NAMES_REVERSE[k]
1✔
70
            h = c
1✔
71
        elif k[:2] == '<f' and k[-1] == '>' and k[2:-1].isdigit():
×
72
            t = kc.TYPE_FUNCTION
×
73
            c = int(k[2:-1])
×
74
            h = c
×
75
        else:
76
            raise ValueError('bad key description "%s"' % k)
×
77
        self._type = t
1✔
78
        self._code = c
1✔
79
        self._mods = m
1✔
80
        self._hash = h | (m << 6) | (t << 7)
1✔
81

82
    def __call__(self, k):
1✔
83
        if isinstance(k, Key):
×
84
            return all([k.type == self._type,
×
85
                        k.code == self._code,
86
                        k.mods == self._mods,
87
                        ])
88

89
    def __eq__(self, other):
1✔
90
        if   isinstance(other, Matcher):
1!
91
            return all([other._type == self._type,
1✔
92
                        other._code == self._code,
93
                        other._mods == self._mods,
94
                        ])
95
        elif isinstance(other, Key):
×
96
            return self.__call__(other)
×
97
        else:
98
            return False
×
99

100
    def __neq__(self, other):
1✔
101
        return not self == other
×
102

103
    def __hash__(self):
1✔
104
        return self._hash
1✔
105

106
    def __str__(self):
1✔
107
        return self._desc
×
108

109
class Key:
1✔
110
    def __init__(self, type, code = None, mods = kc.MOD_NONE):
1✔
111
        self.type = type
×
112
        self.code = code
×
113
        self.mods = mods
×
114
        self._str = None
×
115

116
    def __str__(self):
1✔
117
        if self._str:
×
118
            return self._str
×
119
        if   self.type == kc.TYPE_UNICODE:
×
120
            if self.code == ' ':
×
121
                s = '<space>'
×
122
            else:
123
                s = self.code
×
124
        elif self.type == kc.TYPE_KEYSYM:
×
125
            s = kc.KEY_NAMES.get(self.code, '<SYMNAME-%d>' % self.code)
×
126
        elif self.type == kc.TYPE_FUNCTION:
×
127
            s = '<f%d>' % self.code
×
128
        elif self.type == kc.TYPE_POSITION:
×
129
            s = 'Position(%d, %d)' % self.code
×
130
        elif self.type == kc.TYPE_EOF:
×
131
            s = 'EOF'
×
132
        else:
133
            s = '<UNKNOWN>'
×
134
        if self.mods & kc.MOD_SHIFT:
×
135
            s = 'S-' + s
×
136
        if self.mods & kc.MOD_ALT:
×
137
            s = 'M-' + s
×
138
        if self.mods & kc.MOD_CTRL:
×
139
            s = 'C-' + s
×
140
        self._str = s
×
141
        return s
×
142

143
    def __repr__(self):
1✔
144
        return self.__str__()
×
145

146
    def __eq__(self, other):
1✔
147
        if   isinstance(other, (six.text_type, six.binary_type)):
×
148
            return Matcher(other)(self)
×
149
        elif isinstance(other, Matcher):
×
150
            return other(self)
×
151
        elif isinstance(other, Key):
×
152
            return all([self.type == other.type,
×
153
                        self.code == other.code,
154
                        self.mods == other.mods,
155
                        ])
156
        else:
157
            return False
×
158

159
_cbuf = []
1✔
160
_kbuf = []
1✔
161

162
def _read(timeout = 0):
1✔
163
    _cbuf.extend(getraw(timeout))
×
164

165
def _peek():
1✔
166
    if _cbuf:
×
167
        return _peek_ti() or _peek_csi() or _peek_simple()
×
168

169
def get(timeout = None):
1✔
170
    if _kbuf:
×
171
        return _kbuf.pop(0)
×
172
    k = _peek()
×
173
    if k:
×
174
        return k
×
175
    _read(timeout)
×
176
    return _peek()
×
177

178
def unget(k):
1✔
179
    _kbuf.append(k)
×
180

181
# terminfo
182
def _name_to_key(fname):
1✔
183
    if   fname in kc.FUNCSYMS:
×
184
        k = Key(kc.TYPE_KEYSYM, *kc.FUNCSYMS[fname])
×
185
    elif fname[0] == 'f' and fname[1:].isdigit():
×
186
        k = Key(kc.TYPE_FUNCTION, int(fname[1:]))
×
187
    elif fname[0] == 's':
×
188
        k = _name_to_key(fname[1:])
×
189
        if k:
×
190
            k.mods |= kc.MOD_SHIFT
×
191
    else:
192
        return None
×
193
    return k
×
194

195
_ti_table = None
1✔
196

197
def _peek_ti():
1✔
198
    global _cbuf
199
    if _ti_table is None:
×
200
        _init_ti_table()
×
201
    # XXX: Faster lookup, plox
202
    for seq, key in _ti_table:
×
203
        if _cbuf[:len(seq)] == seq:
×
204
            _cbuf = _cbuf[len(seq):]
×
205
            return key
×
206

207
def _init_ti_table():
1✔
208
    global _ti_table
209
    _ti_table = []
×
210
    for fname, name in zip(kc.STRFNAMES, kc.STRNAMES):
×
211
        seq = termcap.get(name)
×
212
        if not seq:
×
213
            continue
×
214
        k = _name_to_key(fname)
×
215
        if k:
×
216
            _ti_table.append((list(bytearray(seq)), k))
×
217

218
# csi
219
def _parse_csi(offset):
1✔
220
    i = offset
×
221
    while i < len(_cbuf):
×
222
        c = _cbuf[i]
×
223
        if c >= 0x40 and c < 0x80:
×
224
            break
×
225
        i += 1
×
226
    if i >= len(_cbuf):
×
227
        return
×
228
    end = i
×
229
    cmd = [c, None, None]
×
230

231
    i = offset
×
232
    in_num = False
×
233
    args = []
×
234
    if _cbuf[i] >= ord('<') and _cbuf[i] <= ord('?'):
×
235
        cmd[1] = _cbuf[i]
×
236
        i += 1
×
237
    while i < end:
×
238
        c = _cbuf[i]
×
239
        if   c >= ord('0') and c <= ord('9'):
×
240
            if not in_num:
×
241
                args.append(c - ord('0'))
×
242
                in_num = True
×
243
            else:
244
                args[-1] = args[-1] * 10 + c - ord('0')
×
245
        elif c == ord(';'):
×
246
            if not in_num:
×
247
                args.append(None)
×
248
            in_num = False
×
249
            if len(args) > 16:
×
250
                break
×
251
        elif c >= 0x20 and c <= 0x2f:
×
252
            cmd[2] = c
×
253
            break
×
254

255
        i += 1
×
256

257
    return cmd, args, end + 1
×
258

259
def _csi_func(cmd, args):
1✔
260
    k = Key(kc.TYPE_UNKNOWN)
×
261
    if len(args) > 1 and args[1]:
×
262
        k.mods |= args[1] - 1
×
263

264
    if   args[0] == 0x1b and len(args) == 3:
×
265
        k.type = kc.TYPE_KEYSYM
×
266
        k.code = args[2]
×
267
        return k
×
268
    elif args[0] in _csi_funcs:
×
269
        f = _csi_funcs[args[0]]
×
270
        k.type = f[0]
×
271
        k.code = f[1]
×
272
        return k
×
273

274
def _csi_ss3(cmd, args):
1✔
275
    t, c = _csi_ss3s[chr(cmd[0])]
×
276
    k = Key(t, c)
×
277
    if len(args) > 1 and args[1]:
×
278
        k.mods |= args[1] - 1
×
279
    return k
×
280

281
def _csi_u(cmd, args):
1✔
282
    k = Key(kc.TYPE_UNICODE, six.unichr(args[0]))
×
283
    if len(args) > 1 and args[1]:
×
284
        k.mods |= args[1] - 1
×
285
    return k
×
286

287
def _csi_R(cmd, args):
1✔
288
    if cmd[0] == ord('R') and cmd[1] == ord('?'):
×
289
        if len(args) < 2:
×
290
            return
×
291
        return Key(kc.TYPE_POSITION, (args[1], args[0]))
×
292
    else:
293
        return _csi_ss3(cmd, args)
×
294

295
_csi_handlers = {
1✔
296
    '~' : _csi_func,
297
    'u' : _csi_u,
298
    'R' : _csi_R,
299
    }
300

301
_csi_ss3s = {
1✔
302
    'A': (kc.TYPE_KEYSYM, kc.KEY_UP),
303
    'B': (kc.TYPE_KEYSYM, kc.KEY_DOWN),
304
    'C': (kc.TYPE_KEYSYM, kc.KEY_RIGHT),
305
    'D': (kc.TYPE_KEYSYM, kc.KEY_LEFT),
306
    'E': (kc.TYPE_KEYSYM, kc.KEY_BEGIN),
307
    'F': (kc.TYPE_KEYSYM, kc.KEY_END),
308
    'H': (kc.TYPE_KEYSYM, kc.KEY_HOME),
309
    'P': (kc.TYPE_FUNCTION, 1),
310
    'Q': (kc.TYPE_FUNCTION, 2),
311
    'R': (kc.TYPE_FUNCTION, 3),
312
    'S': (kc.TYPE_FUNCTION, 4),
313
    'Z': (kc.TYPE_KEYSYM, kc.KEY_TAB),
314
}
315

316
_csi_ss3kp = {
1✔
317
    'M': (kc.TYPE_KEYSYM, kc.KEY_KPENTER , None),
318
    'X': (kc.TYPE_KEYSYM, kc.KEY_KPEQUALS, '='),
319
    'j': (kc.TYPE_KEYSYM, kc.KEY_KPMULT  , '*'),
320
    'k': (kc.TYPE_KEYSYM, kc.KEY_KPPLUS  , '+'),
321
    'l': (kc.TYPE_KEYSYM, kc.KEY_KPCOMMA , ','),
322
    'm': (kc.TYPE_KEYSYM, kc.KEY_KPMINUS , '-'),
323
    'n': (kc.TYPE_KEYSYM, kc.KEY_KPPERIOD, '.'),
324
    'o': (kc.TYPE_KEYSYM, kc.KEY_KPDIV   , '/'),
325
    'p': (kc.TYPE_KEYSYM, kc.KEY_KP0     , '0'),
326
    'q': (kc.TYPE_KEYSYM, kc.KEY_KP1     , '1'),
327
    'r': (kc.TYPE_KEYSYM, kc.KEY_KP2     , '2'),
328
    's': (kc.TYPE_KEYSYM, kc.KEY_KP3     , '3'),
329
    't': (kc.TYPE_KEYSYM, kc.KEY_KP4     , '4'),
330
    'u': (kc.TYPE_KEYSYM, kc.KEY_KP5     , '5'),
331
    'v': (kc.TYPE_KEYSYM, kc.KEY_KP6     , '6'),
332
    'w': (kc.TYPE_KEYSYM, kc.KEY_KP7     , '7'),
333
    'x': (kc.TYPE_KEYSYM, kc.KEY_KP8     , '8'),
334
    'y': (kc.TYPE_KEYSYM, kc.KEY_KP9     , '9'),
335
}
336

337
_csi_funcs = {
1✔
338
    1 : (kc.TYPE_KEYSYM, kc.KEY_FIND),
339
    2 : (kc.TYPE_KEYSYM, kc.KEY_INSERT),
340
    3 : (kc.TYPE_KEYSYM, kc.KEY_DELETE),
341
    4 : (kc.TYPE_KEYSYM, kc.KEY_SELECT),
342
    5 : (kc.TYPE_KEYSYM, kc.KEY_PAGEUP),
343
    6 : (kc.TYPE_KEYSYM, kc.KEY_PAGEDOWN),
344
    7 : (kc.TYPE_KEYSYM, kc.KEY_HOME),
345
    8 : (kc.TYPE_KEYSYM, kc.KEY_END),
346
    11: (kc.TYPE_FUNCTION, 1),
347
    12: (kc.TYPE_FUNCTION, 2),
348
    13: (kc.TYPE_FUNCTION, 3),
349
    14: (kc.TYPE_FUNCTION, 4),
350
    15: (kc.TYPE_FUNCTION, 5),
351
    17: (kc.TYPE_FUNCTION, 6),
352
    18: (kc.TYPE_FUNCTION, 7),
353
    19: (kc.TYPE_FUNCTION, 8),
354
    20: (kc.TYPE_FUNCTION, 9),
355
    21: (kc.TYPE_FUNCTION, 10),
356
    23: (kc.TYPE_FUNCTION, 11),
357
    24: (kc.TYPE_FUNCTION, 12),
358
    25: (kc.TYPE_FUNCTION, 13),
359
    26: (kc.TYPE_FUNCTION, 14),
360
    28: (kc.TYPE_FUNCTION, 15),
361
    29: (kc.TYPE_FUNCTION, 16),
362
    31: (kc.TYPE_FUNCTION, 17),
363
    32: (kc.TYPE_FUNCTION, 18),
364
    33: (kc.TYPE_FUNCTION, 19),
365
    34: (kc.TYPE_FUNCTION, 20),
366
    }
367

368
def _peekkey_csi(offset):
1✔
369
    global _cbuf
370
    ret = _parse_csi(offset)
×
371
    if not ret:
×
372
        _cbuf = _cbuf[offset:]
×
373
        return Key(kc.TYPE_UNICODE, u'[', kc.MOD_ALT)
×
374
    cmd, args, numb = ret
×
375
    # print(cmd, args, '\r')
376
    _cbuf = _cbuf[numb:]
×
377
    k = None
×
378
    if   chr(cmd[0]) in _csi_handlers:
×
379
        k = _csi_handlers[chr(cmd[0])](cmd, args)
×
380
    elif chr(cmd[0]) in _csi_ss3s:
×
381
        k = _csi_ss3(cmd, args)
×
382
        if k and chr(cmd[0]) == 'Z':
×
383
            k.mods |= kc.MOD_SHIFT
×
384

385
    if k:
×
386
        return k
×
387
    else:
388
        return Key(kc.TYPE_UNKNOWN_CSI, (cmd, args))
×
389

390
def _peekkey_ss3(offset):
1✔
391
    global _cbuf
392
    if len(_cbuf) <= offset:
×
393
        return Key(kc.TYPE_UNICODE, u'O', kc.MOD_ALT)
×
394
    cmd = _cbuf[offset]
×
395
    if cmd < 0x40 or cmd >= 0x80:
×
396
        return
×
397
    _cbuf = _cbuf[offset:]
×
398

399
    if chr(cmd) in _csi_ss3s:
×
400
        return Key(*_csi_ss3s[chr(cmd)])
×
401

402
    if chr(cmd) in _csi_ss3kp:
×
403
        t, c, a = _csi_ss3kp[chr(cmd)]
×
404
        if FLAG_CONVERTKP and a:
×
405
            return Key(kc.TYPE_UNICODE, a)
×
406
        else:
407
            return Key(t, c)
×
408

409
def _peek_csi():
1✔
410
    global _cbuf
411
    # print('csi', _cbuf, '\r')
412
    c0 = _cbuf[0]
×
413
    if   c0 == 0x1b and len(_cbuf) >= 2:
×
414
        c1 = _cbuf[1]
×
415
        if   c1 == ord('['):
×
416
            return _peekkey_csi(2)
×
417
        elif c1 == ord('O'):
×
418
            return _peekkey_ss3(2)
×
419
    elif c0 == 0x8f:
×
420
        return _peekkey_ss3(1)
×
421
    elif c0 == 0x9b:
×
422
        return _peekkey_csi(1)
×
423

424
def _peek_simple():
1✔
425
    global _cbuf
426
    # print('simple', _cbuf, '\r')
427
    if not _cbuf:
×
428
        return
×
429
    c0 = _cbuf.pop(0)
×
430
    if   c0 is None:
×
431
        _cbuf = []
×
432
        return Key(kc.TYPE_EOF)
×
433
    elif c0 == 0x1b:
×
434
        if _cbuf:
×
435
            k = _peek()
×
436
            # print(k)
437
            if k:
×
438
                # need to deep copy or we risk modifying keys in ti table
439
                return Key(k.type, k.code, k.mods | kc.MOD_ALT)
×
440
        else:
441
            return Key(kc.TYPE_KEYSYM, kc.KEY_ESCAPE)
×
442
    elif c0 < 0xa0:
×
443
        if   c0 < 0x20:
×
444
            if   c0 == 8:
×
445
                k = Key(kc.TYPE_KEYSYM, kc.KEY_BACKSPACE)
×
446
            elif c0 == 9:
×
447
                k = Key(kc.TYPE_KEYSYM, kc.KEY_TAB)
×
448
            elif c0 in (10, 13):
×
449
                k = Key(kc.TYPE_KEYSYM, kc.KEY_ENTER)
×
450
            else:
451
                k = Key(kc.TYPE_UNICODE)
×
452
                if   c0 == 0:
×
453
                    k.code = u' '
×
454
                elif chr(c0 + 0x40) in string.ascii_uppercase:
×
455
                    k.code = six.unichr(c0 + 0x60)
×
456
                else:
457
                    k.code = six.unichr(c0 + 0x40)
×
458
                k.mods |= kc.MOD_CTRL
×
459
        elif c0 == 0x7f:
×
460
            # print('del\r')
461
            k = Key(kc.TYPE_KEYSYM, kc.KEY_DEL)
×
462
        elif c0 >= 0x20 and c0 < 0x80:
×
463
            k = Key(kc.TYPE_UNICODE, six.unichr(c0))
×
464
        else:
465
            k = Key(kc.TYPE_UNICODE, six.unichr(c0 - 0x40), kc.MOD_CTRL | kc.MOD_ALT)
×
466
    else: # utf8
467
        n = 0
×
468
        if   c0 & 0b11100000 == 0b11000000:
×
469
            n = 2
×
470
        elif c0 & 0b11110000 == 0b11100000:
×
471
            n = 3
×
472
        elif c0 & 0b11111000 == 0b11110000:
×
473
            n = 4
×
474
        elif c0 & 0b11111100 == 0b11111000:
×
475
            n = 5
×
476
        elif c0 & 0b11111110 == 0b11111100:
×
477
            n = 6
×
478
        if n:
×
479
            c = [c0] + _cbuf[:n - 1]
×
480
            k = Key(kc.TYPE_UNICODE, bytearray(c).decode('utf8'))
×
481
            _cbuf = _cbuf[n - 1:]
×
482
        else:
483
            k = Key(kc.TYPE_UNKNOWN, _cbuf)
×
484
            _cbuf = []
×
485
    return k
×
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

© 2025 Coveralls, Inc