mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-08 01:58:16 -10:00
Compare commits
39
Commits
3.3.2
...
3.4.0beta4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
602efd2790 | ||
|
|
2f7f0de984 | ||
|
|
16b507e197 | ||
|
|
53f041a4d2 | ||
|
|
b2a5b76cf7 | ||
|
|
9c2f0f4e89 | ||
|
|
7ba3a1b32f | ||
|
|
d1edd275d9 | ||
|
|
cb4991c41d | ||
|
|
48616c633d | ||
|
|
f5e16d3db6 | ||
|
|
a2c67e5075 | ||
|
|
7ed118763b | ||
|
|
e997c17397 | ||
|
|
0acc8ee499 | ||
|
|
f14e0e5652 | ||
|
|
aaa83983ad | ||
|
|
1241073391 | ||
|
|
cfcd79e169 | ||
|
|
706a784904 | ||
|
|
70c96330de | ||
|
|
cae3cddc07 | ||
|
|
5373dcdeed | ||
|
|
5d4bf3db6c | ||
|
|
fbfa54ad61 | ||
|
|
b323264032 | ||
|
|
2c841eaa21 | ||
|
|
d2c6184a00 | ||
|
|
e5645e7b53 | ||
|
|
09dbe0a54d | ||
|
|
0bd0de78f9 | ||
|
|
546061e577 | ||
|
|
5ebc8b5bb7 | ||
|
|
b83a6c7db8 | ||
|
|
5d9792fb4c | ||
|
|
1c54e347f2 | ||
|
|
7545dafffb | ||
|
|
3acec5421f | ||
|
|
b441cf967a |
No files matched your search
+34
-3
@@ -11,7 +11,9 @@ The table below shows which release corresponds to each branch, and what date th
|
||||
| ---------------- | -------- | ---------------------- |
|
||||
| [3.5.0](#350) | `dev` | Mar 18, 2017 (planned)
|
||||
| [3.4.0](#340) | `beta` | Feb 4, 2017 (planned)
|
||||
| [3.3.2](#332) | `stable` | Jan 10, 2016
|
||||
| [3.3.4](#334) | `stable` | Jan 12, 2016
|
||||
| [3.3.3](#333) | | Jan 10, 2016
|
||||
| [3.3.2](#332) | | Jan 10, 2016
|
||||
| [3.3.1](#331) | | Jan 10, 2016
|
||||
| [3.3.0](#330) | | Dec 24, 2016
|
||||
| [3.2.1](#321) | | Dec 24, 2016
|
||||
@@ -33,11 +35,40 @@ To be released on Mar 18, 2017.
|
||||
|
||||
To be released on Feb 4, 2017.
|
||||
|
||||
- [#800][800] Add `shell=` option to `ssh.process()`
|
||||
- [5d9792f][5d9792f] Add `context.buffer_size` for fine-tuning `tube` performance
|
||||
+ Also adds `buffer_fill_size=` argument for all tubes
|
||||
- [b83a6c7][b83a6c7] Fix undocumented `process.leak` function
|
||||
- [546061e][546061e] Modify `coredump_filter` of all spawned processes, so that core dumps are more complete
|
||||
|
||||
|
||||
[800]: https://github.com/Gallopsled/pwntools/pull/800
|
||||
[5d9792f]: https://github.com/Gallopsled/pwntools/commit/5d9792f
|
||||
[b83a6c7]: https://github.com/Gallopsled/pwntools/commit/b83a6c7
|
||||
[546061e]: https://github.com/Gallopsled/pwntools/commit/546061e
|
||||
|
||||
## 3.3.4
|
||||
|
||||
- [#850][850] and [#846][846] fix issues with `hexdump` and the `phd` command-line utility, when using pipes (e.g. `echo foo | phd`)
|
||||
- [#852][852] Fixes register ordering in `regsort`
|
||||
- [#853][853] Fixes the registers restored in `shellcraft.amd64.popad`
|
||||
|
||||
[846]: https://github.com/gallopsled/pwntools/pull/846
|
||||
[850]: https://github.com/gallopsled/pwntools/pull/850
|
||||
[852]: https://github.com/gallopsled/pwntools/pull/852
|
||||
[853]: https://github.com/gallopsled/pwntools/pull/853
|
||||
|
||||
## 3.3.3
|
||||
|
||||
- [#843][843] fixed a bug in `amd64.mov`.
|
||||
|
||||
[843]: https://github.com/gallopsled/pwntools/pull/843
|
||||
|
||||
## 3.3.2
|
||||
|
||||
- [#840][840] Fixed a regression introduced by [#837][837].
|
||||
- [#840][840] fixed a regression introduced by [#837][837].
|
||||
|
||||
[840]: https://github.com/Gallopsled/pwntools/pull/840
|
||||
[840]: https://github.com/gallopsled/pwntools/pull/840
|
||||
|
||||
## 3.3.1
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||

|
||||
|
||||
[](https://docs.pwntools.com/)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://travis-ci.org/Gallopsled/pwntools)
|
||||
[](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
|
||||
[](https://twitter.com/pwntools)
|
||||
@@ -38,7 +38,7 @@ Most of the functionality of pwntools is self-contained and Python-only. You sh
|
||||
|
||||
```sh
|
||||
apt-get update
|
||||
apt-get install python2.7 python-pip python-dev git libssl-dev
|
||||
apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev
|
||||
pip install --upgrade pwntools
|
||||
```
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ pwntools is available as a ``pip`` package.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ apt-get install python2.7 python2.7-dev python-pip
|
||||
$ apt-get update
|
||||
$ apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev
|
||||
$ pip install --upgrade pwntools
|
||||
|
||||
Development
|
||||
|
||||
+147
-4
@@ -599,6 +599,150 @@ def write(path, data=''):
|
||||
misc.write(temp.name, data)
|
||||
push(temp.name, path)
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def mkdir(path):
|
||||
"""Create a directory on the target device.
|
||||
|
||||
Note:
|
||||
Silently succeeds if the directory already exists.
|
||||
|
||||
Arguments:
|
||||
path(str): Directory to create.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.mkdir('/')
|
||||
|
||||
>>> path = '/data/local/tmp/mkdir_test'
|
||||
>>> adb.exists(path)
|
||||
False
|
||||
>>> adb.mkdir(path)
|
||||
>>> adb.exists(path)
|
||||
True
|
||||
|
||||
>>> adb.mkdir('/init')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: mkdir failed for /init, File exists
|
||||
"""
|
||||
if not path.startswith('/'):
|
||||
log.error("Must provide an absolute path: %r" % path)
|
||||
|
||||
with Client() as c:
|
||||
st = c.stat(path)
|
||||
|
||||
# Don't re-create existing directories
|
||||
if st and stat.S_ISDIR(st['mode']):
|
||||
return
|
||||
|
||||
result = process(['mkdir', path]).recvall()
|
||||
|
||||
# Any output at all is an error
|
||||
if result:
|
||||
log.error(result)
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def makedirs(path):
|
||||
"""Create a directory and all parent directories on the target device.
|
||||
|
||||
Note:
|
||||
Silently succeeds if the directory already exists.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.makedirs('/data/local/tmp/this/is/a/directory/heirarchy')
|
||||
>>> adb.listdir('/data/local/tmp/this/is/a/directory')
|
||||
['heirarchy']
|
||||
"""
|
||||
if path != '/':
|
||||
makedirs(os.path.dirname(path))
|
||||
|
||||
mkdir(path)
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def exists(path):
|
||||
"""Return ``True`` if ``path`` exists on the target device.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.exists('/')
|
||||
True
|
||||
>>> adb.exists('/init')
|
||||
True
|
||||
>>> adb.exists('/does/not/exist')
|
||||
False
|
||||
"""
|
||||
with Client() as c:
|
||||
return bool(c.stat(path))
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def isdir(path):
|
||||
"""Return ``True`` if ``path`` is a on the target device.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.isdir('/')
|
||||
True
|
||||
>>> adb.isdir('/init')
|
||||
False
|
||||
>>> adb.isdir('/does/not/exist')
|
||||
False
|
||||
"""
|
||||
with Client() as c:
|
||||
st = c.stat(path)
|
||||
return bool(st and stat.S_ISDIR(st['mode']))
|
||||
|
||||
@context.quiet
|
||||
@with_device
|
||||
def unlink(path, recursive=False):
|
||||
"""Unlinks a file or directory on the target device.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> adb.unlink("/does/not/exist")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: Could not unlink '/does/not/exist': Does not exist
|
||||
|
||||
>>> filename = '/data/local/tmp/unlink-test'
|
||||
>>> adb.write(filename, 'hello')
|
||||
>>> adb.exists(filename)
|
||||
True
|
||||
>>> adb.unlink(filename)
|
||||
>>> adb.exists(filename)
|
||||
False
|
||||
|
||||
>>> adb.mkdir(filename)
|
||||
>>> adb.write(filename + '/contents', 'hello')
|
||||
>>> adb.unlink(filename)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: Cannot delete non-empty directory '/data/local/tmp/unlink-test' without recursive=True
|
||||
|
||||
>>> adb.unlink(filename, recursive=True)
|
||||
>>> adb.exists(filename)
|
||||
False
|
||||
"""
|
||||
with Client() as c:
|
||||
st = c.stat(path)
|
||||
if not st:
|
||||
log.error("Could not unlink %r: Does not exist" % path)
|
||||
|
||||
# If the directory is not empty, do not delete it
|
||||
if isdir(path) and c.list(path) and not recursive:
|
||||
log.error("Cannot delete non-empty directory %r without recursive=True" % path)
|
||||
|
||||
flags = '-rf' if recursive else '-r'
|
||||
|
||||
output = c.execute(['rm', flags, path]).recvall()
|
||||
|
||||
if output:
|
||||
log.error(output)
|
||||
|
||||
@with_device
|
||||
def process(argv, *a, **kw):
|
||||
"""Execute a process on the device.
|
||||
@@ -760,16 +904,15 @@ def listdir(directory='/'):
|
||||
"""
|
||||
return list(sorted(Client().list(directory)))
|
||||
|
||||
@with_device
|
||||
def fastboot(args, *a, **kw):
|
||||
"""Executes a fastboot command.
|
||||
|
||||
Returns:
|
||||
The command output.
|
||||
"""
|
||||
serial = context.device
|
||||
if not serial:
|
||||
log.error("Unknown device")
|
||||
return tubes.process.process(['fastboot', '-s', serial] + list(args), **kw).recvall()
|
||||
argv = ['fastboot', '-s', str(context.device)] + list(args)
|
||||
return tubes.process.process(argv, *a, **kw).recvall()
|
||||
|
||||
@with_device
|
||||
def fingerprint():
|
||||
|
||||
@@ -16,8 +16,8 @@ from . import scramble
|
||||
from . import shellcraft
|
||||
from . import unhex
|
||||
from . import update
|
||||
from .common import parser
|
||||
from ..context import context
|
||||
from .common import parser
|
||||
|
||||
commands = {
|
||||
'asm': asm.main,
|
||||
|
||||
@@ -21,7 +21,7 @@ p.add_argument('--pre', action='store_true', help='''
|
||||
def main(a):
|
||||
result = pwnlib.update.perform_check(prerelease=a.pre)
|
||||
if a.install:
|
||||
subprocess.check_call(result, shell=True)
|
||||
subprocess.check_call(result, shell=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.common.main(__file__)
|
||||
@@ -330,6 +330,7 @@ class ContextType(object):
|
||||
'aslr': True,
|
||||
'binary': None,
|
||||
'bits': 32,
|
||||
'buffer_size': 4096,
|
||||
'device': os.getenv('ANDROID_SERIAL', None) or None,
|
||||
'endian': 'little',
|
||||
'kernel': None,
|
||||
@@ -1146,6 +1147,15 @@ class ContextType(object):
|
||||
|
||||
return command
|
||||
|
||||
@_validator
|
||||
def buffer_size(self, size):
|
||||
"""Internal buffer size to use for ``tube`` objects.
|
||||
|
||||
This is not the maximum size of the buffer, but this is the amount of data
|
||||
which is passed to each raw ``read`` syscall (or equivalent).
|
||||
"""
|
||||
return int(size)
|
||||
|
||||
@property
|
||||
def cache_dir(self):
|
||||
"""Directory used for caching data.
|
||||
@@ -1185,7 +1195,6 @@ class ContextType(object):
|
||||
|
||||
return cache
|
||||
|
||||
|
||||
#*************************************************************************
|
||||
# ALIASES
|
||||
#*************************************************************************
|
||||
|
||||
@@ -7,6 +7,7 @@ import re
|
||||
import urllib
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from pwn import *
|
||||
|
||||
uas = set()
|
||||
|
||||
@@ -606,3 +606,14 @@ class MemLeak(object):
|
||||
return result
|
||||
|
||||
return MemLeak(string_wrapper)
|
||||
|
||||
# Aliases for convenience
|
||||
u64 = q
|
||||
u32 = d
|
||||
u16 = w
|
||||
u8 = b
|
||||
|
||||
p64 = setq
|
||||
p32 = setd
|
||||
p16 = setw
|
||||
p8 = setb
|
||||
+5
-1
@@ -224,6 +224,8 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
|
||||
('mov', 'b', 'c'),
|
||||
('mov', 'c', 'x'),
|
||||
('mov', 'x', '1')]
|
||||
>>> regsort({'a': 'b', 'b': 'c'}, ['a','b','c'], xchg=0)
|
||||
[('mov', 'a', 'b'), ('mov', 'b', 'c')]
|
||||
"""
|
||||
if randomize is None:
|
||||
randomize = context.randomize
|
||||
@@ -333,7 +335,9 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
|
||||
# If XCHG is expressly disabled, and there is no temporary register,
|
||||
# try to see if there is any register which can be used as a temp
|
||||
# register instead.
|
||||
if not (xchg or tmp):
|
||||
#
|
||||
# If there are no cycles, there's no need for a temporary register.
|
||||
if in_cycle and not (xchg or tmp):
|
||||
for reg in in_out:
|
||||
if not depends_on_cycle(reg, in_out, in_cycle):
|
||||
tmp = reg
|
||||
|
||||
@@ -61,17 +61,26 @@ Example:
|
||||
mov rax, 0x1010110dfac01fe
|
||||
xor [rsp], rax
|
||||
pop rax
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
xor eax, eax /* (SYS_read) */
|
||||
>>> with context.local(os = 'freebsd'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
push (SYS_read) /* 3 */
|
||||
pop rax
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip()
|
||||
push (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */
|
||||
pop rax
|
||||
>>> print shellcraft.amd64.mov('rax', 0xffffffff).rstrip()
|
||||
mov eax, 0xffffffff
|
||||
>>> print shellcraft.amd64.mov('rax', 0x7fffffff).rstrip()
|
||||
mov eax, 0x7fffffff
|
||||
>>> print shellcraft.amd64.mov('rax', 0x80010101).rstrip()
|
||||
mov eax, 0x80010101
|
||||
>>> print shellcraft.amd64.mov('rax', 0x80000000).rstrip()
|
||||
mov eax, 0x1010101 /* 2147483648 == 0x80000000 */
|
||||
xor eax, 0x81010101
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
xor eax, eax /* (SYS_read) */
|
||||
>>> with context.local(os = 'freebsd'):
|
||||
... print shellcraft.amd64.mov('eax', 'SYS_read').rstrip()
|
||||
push (SYS_read) /* 3 */
|
||||
pop rax
|
||||
>>> with context.local(os = 'linux'):
|
||||
... print shellcraft.amd64.mov('eax', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip()
|
||||
push (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */
|
||||
pop rax
|
||||
|
||||
Args:
|
||||
dest (str): The destination register.
|
||||
@@ -99,7 +108,6 @@ if get_register(src):
|
||||
if dest.size == 64 and src.size <= 32:
|
||||
dest = get_register(dest.native32)
|
||||
|
||||
src_size = src.size
|
||||
else:
|
||||
with ctx.local(arch = 'amd64'):
|
||||
src = eval(src)
|
||||
@@ -107,9 +115,9 @@ else:
|
||||
if not dest.fits(src):
|
||||
log.error("cannot mov %s, %r: dest is smaller than src" % (dest, src))
|
||||
|
||||
src_size = bits_required(src)
|
||||
orig_dest = dest
|
||||
|
||||
if dest.size == 64 and src_size <= 32:
|
||||
if dest.size == 64 and bits_required(src) <= 32:
|
||||
dest = get_register(dest.native32)
|
||||
|
||||
# Calculate the packed version
|
||||
@@ -117,7 +125,15 @@ else:
|
||||
|
||||
# Calculate the unsigned and signed versions
|
||||
srcu = packing.unpack(srcp, dest.size, sign=False)
|
||||
srcs = packing.unpack(srcp, dest.size, sign=True)
|
||||
|
||||
# N.B.: We may have downsized the register for e.g. mov('rax', 0xffffffff)
|
||||
# In this case, srcp is now a 4-byte packed value, which will expand
|
||||
# to "-1", which isn't correct.
|
||||
if orig_dest.size != dest.size:
|
||||
srcs = src
|
||||
else:
|
||||
srcs = packing.unpack(srcp, dest.size, sign=True)
|
||||
|
||||
%>\
|
||||
% if is_register(src):
|
||||
% if src == dest:
|
||||
|
||||
@@ -6,8 +6,8 @@ in the same order.
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
pop rsp
|
||||
pop rbp
|
||||
pop rbx /* add rsp, 8 */
|
||||
pop rbx
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
@@ -22,6 +22,7 @@ import threading
|
||||
import traceback
|
||||
|
||||
from . import termcap
|
||||
from ..context import ContextType
|
||||
|
||||
settings = None
|
||||
_graphics_mode = False
|
||||
@@ -127,6 +128,11 @@ def init():
|
||||
sys.stdout = Wrapper(sys.stdout)
|
||||
if sys.stderr.isatty():
|
||||
sys.stderr = Wrapper(sys.stderr)
|
||||
|
||||
console = ContextType.defaults['log_console']
|
||||
if console.isatty():
|
||||
ContextType.defaults['log_console'] = Wrapper(console)
|
||||
|
||||
# freeze all cells if an exception is thrown
|
||||
orig_hook = sys.excepthook
|
||||
def hook(*args):
|
||||
|
||||
+21
-2
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
from ..context import context
|
||||
|
||||
|
||||
class Buffer(Exception):
|
||||
"""
|
||||
List of strings with some helper routines.
|
||||
@@ -28,10 +31,10 @@ class Buffer(Exception):
|
||||
The ``0th`` item in the buffer is the oldest item, and
|
||||
will be received first.
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, buffer_fill_size = None):
|
||||
self.data = [] # Buffer
|
||||
self.size = 0 # Length
|
||||
|
||||
self.buffer_fill_size = buffer_fill_size
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
@@ -169,3 +172,19 @@ class Buffer(Exception):
|
||||
self.size -= len(data)
|
||||
|
||||
return data
|
||||
|
||||
def get_fill_size(self, size=None):
|
||||
"""
|
||||
Retrieves the default fill size for this buffer class.
|
||||
|
||||
Arguments:
|
||||
size (int): (Optional) If set and not None, returns the size variable back.
|
||||
|
||||
Returns:
|
||||
Fill size as integer if size == None, else size.
|
||||
"""
|
||||
if size is None:
|
||||
size = self.buffer_fill_size
|
||||
|
||||
with context.local(buffer_size=size):
|
||||
return context.buffer_size
|
||||
@@ -20,13 +20,11 @@ class listen(sock):
|
||||
bindaddr(str): The address to bind to.
|
||||
fam: The string "any", "ipv4" or "ipv6" or an integer to pass to :func:`socket.getaddrinfo`.
|
||||
typ: The string "tcp" or "udp" or an integer to pass to :func:`socket.getaddrinfo`.
|
||||
timeout: A positive number, None
|
||||
"""
|
||||
|
||||
def __init__(self, port=0, bindaddr = "0.0.0.0",
|
||||
fam = "any", typ = "tcp",
|
||||
timeout = Timeout.default, level = None):
|
||||
super(listen, self).__init__(timeout, level = level)
|
||||
fam = "any", typ = "tcp", *args, **kwargs):
|
||||
super(listen, self).__init__(*args, **kwargs)
|
||||
|
||||
port = int(port)
|
||||
fam = {socket.AF_INET: 'ipv4',
|
||||
|
||||
@@ -44,8 +44,6 @@ class process(tube):
|
||||
Working directory. Uses the current working directory by default.
|
||||
env(dict):
|
||||
Environment variables. By default, inherits from Python's environment.
|
||||
timeout(int):
|
||||
Timeout to use on ``tube`` ``recv`` operations.
|
||||
stdin(int):
|
||||
File object or file descriptor number to use for ``stdin``.
|
||||
By default, a pipe is used. A pty can be used instead by setting
|
||||
@@ -206,11 +204,9 @@ class process(tube):
|
||||
executable = None,
|
||||
cwd = None,
|
||||
env = None,
|
||||
timeout = Timeout.default,
|
||||
stdin = PIPE,
|
||||
stdout = PTY,
|
||||
stderr = STDOUT,
|
||||
level = None,
|
||||
close_fds = True,
|
||||
preexec_fn = lambda: None,
|
||||
raw = True,
|
||||
@@ -218,8 +214,11 @@ class process(tube):
|
||||
setuid = None,
|
||||
where = 'local',
|
||||
display = None,
|
||||
alarm = None):
|
||||
super(process, self).__init__(timeout, level = level)
|
||||
alarm = None,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
super(process, self).__init__(*args,**kwargs)
|
||||
|
||||
# Permit using context.binary
|
||||
if argv is None:
|
||||
@@ -794,7 +793,7 @@ class process(tube):
|
||||
import pwnlib.elf.corefile
|
||||
return pwnlib.elf.corefile.Core(filename)
|
||||
|
||||
def leak(self, address, count=0):
|
||||
def leak(self, address, count=1):
|
||||
"""Leaks memory within the process at the specified address.
|
||||
|
||||
Arguments:
|
||||
|
||||
+6
-10
@@ -45,8 +45,8 @@ class remote(sock):
|
||||
|
||||
def __init__(self, host, port,
|
||||
fam = "any", typ = "tcp",
|
||||
timeout = Timeout.default, ssl=False, sock=None, level = None):
|
||||
super(remote, self).__init__(timeout, level = level)
|
||||
ssl=False, sock=None, *args, **kwargs):
|
||||
super(remote, self).__init__(*args, **kwargs)
|
||||
|
||||
self.rport = int(port)
|
||||
self.rhost = host
|
||||
@@ -150,17 +150,13 @@ class remote(sock):
|
||||
|
||||
class tcp(remote):
|
||||
__doc__ = remote.__doc__
|
||||
def __init__(self, host, port,
|
||||
fam = "any", typ = "tcp",
|
||||
timeout = Timeout.default, ssl=False, sock=None, level = None):
|
||||
return super(tcp, self).__init__(host, port, fam, typ, timeout, ssl, sock, level)
|
||||
def __init__(self, host, port, *a, **kw):
|
||||
return super(tcp, self).__init__(host, port, typ="tcp", *a, **kw)
|
||||
|
||||
class udp(remote):
|
||||
__doc__ = remote.__doc__
|
||||
def __init__(self, host, port,
|
||||
fam = "any", typ = "udp",
|
||||
timeout = Timeout.default, ssl=False, sock=None, level = None):
|
||||
return super(udp, self).__init__(host, port, fam, typ, timeout, ssl, sock, level)
|
||||
def __init__(self, host, port, *a, **kw):
|
||||
return super(udp, self).__init__(host, port, typ="udp", *a, **kw)
|
||||
|
||||
class connect(remote):
|
||||
__doc__ = remote.__doc__
|
||||
+14
-23
@@ -9,7 +9,6 @@ from . import tube
|
||||
from .. import context
|
||||
from .. import term
|
||||
from ..log import getLogger
|
||||
from ..timeout import Timeout
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
@@ -18,10 +17,8 @@ class serialtube(tube.tube):
|
||||
self, port = None, baudrate = 115200,
|
||||
convert_newlines = True,
|
||||
bytesize = 8, parity='N', stopbits=1, xonxoff = False,
|
||||
rtscts = False, dsrdtr = False,
|
||||
timeout = Timeout.default,
|
||||
level = None):
|
||||
super(serialtube, self).__init__(timeout, level = level)
|
||||
rtscts = False, dsrdtr = False, *a, **kw):
|
||||
super(serialtube, self).__init__(*a, **kw)
|
||||
|
||||
if port is None:
|
||||
if platform.system() == 'Darwin':
|
||||
@@ -49,21 +46,14 @@ class serialtube(tube.tube):
|
||||
if not self.conn:
|
||||
raise EOFError
|
||||
|
||||
if self.timeout == None:
|
||||
end = float('inf')
|
||||
else:
|
||||
end = time.time() + self.timeout
|
||||
with self.countdown():
|
||||
while self.conn and self.countdown_active():
|
||||
data = self.conn.read(numb)
|
||||
|
||||
while self.conn:
|
||||
data = self.conn.read(numb)
|
||||
if data:
|
||||
return data
|
||||
if data:
|
||||
return data
|
||||
|
||||
delta = end - time.time()
|
||||
if delta <= 0:
|
||||
break
|
||||
else:
|
||||
time.sleep(min(delta, 0.1))
|
||||
time.sleep(min(self.timeout, 0.1))
|
||||
|
||||
return None
|
||||
|
||||
@@ -83,10 +73,11 @@ class serialtube(tube.tube):
|
||||
pass
|
||||
|
||||
def can_recv_raw(self, timeout):
|
||||
end = time.time()
|
||||
while time.time() < end:
|
||||
if self.conn.inWaiting():
|
||||
return True
|
||||
with self.countdown(timeout):
|
||||
while self.conn and self.countdown_active():
|
||||
if self.conn.inWaiting():
|
||||
return True
|
||||
time.sleep(min(self.timeout, 0.1))
|
||||
return False
|
||||
|
||||
def connected_raw(self, direction):
|
||||
@@ -99,7 +90,7 @@ class serialtube(tube.tube):
|
||||
|
||||
def fileno(self):
|
||||
if not self.connected():
|
||||
self.error("A stopped program does not have a file number")
|
||||
self.error("A closed serialtube does not have a file number")
|
||||
|
||||
return self.conn.fileno()
|
||||
|
||||
|
||||
+79
-11
@@ -10,8 +10,8 @@ log = getLogger(__name__)
|
||||
class sock(tube):
|
||||
"""Methods available exclusively to sockets."""
|
||||
|
||||
def __init__(self, timeout, level = None):
|
||||
super(sock, self).__init__(timeout, level = level)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(sock, self).__init__(*args, **kwargs)
|
||||
self.closed = {"recv": False, "send": False}
|
||||
|
||||
# Overwritten for better usability
|
||||
@@ -26,13 +26,13 @@ class sock(tube):
|
||||
else:
|
||||
return super(sock, self).recvall(timeout)
|
||||
|
||||
def recv_raw(self, numb):
|
||||
def recv_raw(self, numb, *a):
|
||||
if self.closed["recv"]:
|
||||
raise EOFError
|
||||
|
||||
while True:
|
||||
try:
|
||||
data = self.sock.recv(numb)
|
||||
data = self.sock.recv(numb, *a)
|
||||
break
|
||||
except socket.timeout:
|
||||
return None
|
||||
@@ -72,21 +72,89 @@ class sock(tube):
|
||||
self.sock.settimeout(timeout)
|
||||
|
||||
def can_recv_raw(self, timeout):
|
||||
"""
|
||||
Tests:
|
||||
|
||||
>>> l = listen()
|
||||
>>> r = remote('localhost', l.lport)
|
||||
>>> r.can_recv_raw(timeout=0)
|
||||
False
|
||||
>>> l.send('a')
|
||||
>>> r.can_recv_raw(timeout=1)
|
||||
True
|
||||
>>> r.recv()
|
||||
'a'
|
||||
>>> r.can_recv_raw(timeout=0)
|
||||
False
|
||||
>>> l.close()
|
||||
>>> r.can_recv_raw(timeout=1)
|
||||
False
|
||||
>>> r.closed['recv']
|
||||
True
|
||||
"""
|
||||
if not self.sock or self.closed["recv"]:
|
||||
return False
|
||||
|
||||
return select.select([self.sock], [], [], timeout) == ([self.sock], [], [])
|
||||
# select() will tell us data is available at EOF
|
||||
can_recv = select.select([self.sock], [], [], timeout) == ([self.sock], [], [])
|
||||
|
||||
if not can_recv:
|
||||
return False
|
||||
|
||||
# Ensure there's actually data, not just EOF
|
||||
try:
|
||||
self.recv_raw(1, socket.MSG_PEEK)
|
||||
except EOFError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def connected_raw(self, direction):
|
||||
"""
|
||||
Tests:
|
||||
|
||||
>>> l = listen()
|
||||
>>> r = remote('localhost', l.lport)
|
||||
>>> r.connected()
|
||||
True
|
||||
>>> l.close()
|
||||
>>> time.sleep(1) # Avoid race condition
|
||||
>>> r.connected()
|
||||
False
|
||||
"""
|
||||
# If there's no socket, it's definitely closed
|
||||
if not self.sock:
|
||||
return False
|
||||
|
||||
if direction == 'any':
|
||||
return True
|
||||
elif direction == 'recv':
|
||||
return not self.closed['recv']
|
||||
elif direction == 'send':
|
||||
return not self.closed['send']
|
||||
# If we have noticed a connection close in a given direction before,
|
||||
# return fast.
|
||||
if self.closed.get(direction, False):
|
||||
return False
|
||||
|
||||
# If a connection is closed in all manners, return fast
|
||||
if all(self.closed.values()):
|
||||
return False
|
||||
|
||||
# Use poll() to determine the connection state
|
||||
want = {
|
||||
'recv': select.POLLIN,
|
||||
'send': select.POLLOUT,
|
||||
'any': select.POLLIN | select.POLLOUT,
|
||||
}[direction]
|
||||
|
||||
poll = select.poll()
|
||||
poll.register(self, want | select.POLLHUP | select.POLLERR)
|
||||
|
||||
for fd, event in poll.poll(0):
|
||||
if event & select.POLLHUP:
|
||||
self.close()
|
||||
return False
|
||||
if event & select.POLLIN:
|
||||
return True
|
||||
if event & select.POLLOUT:
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def close(self):
|
||||
if not getattr(self, 'sock', None):
|
||||
|
||||
+38
-18
@@ -59,7 +59,7 @@ class ssh_channel(sock):
|
||||
#: Only valid when instantiated through :meth:`ssh.process`
|
||||
pid = None
|
||||
|
||||
#: Executable of the process
|
||||
#: Executable of the procesks
|
||||
#: Only valid when instantiated through :meth:`ssh.process`
|
||||
executable = None
|
||||
|
||||
@@ -67,8 +67,8 @@ class ssh_channel(sock):
|
||||
#: Only valid when instantiated through :meth:`ssh.process`
|
||||
argv = None
|
||||
|
||||
def __init__(self, parent, process = None, tty = False, wd = None, env = None, timeout = Timeout.default, level = 0, raw = True):
|
||||
super(ssh_channel, self).__init__(timeout, level=level)
|
||||
def __init__(self, parent, process = None, tty = False, wd = None, env = None, raw = True, *args, **kwargs):
|
||||
super(ssh_channel, self).__init__(*args, **kwargs)
|
||||
|
||||
# keep the parent from being garbage collected in some cases
|
||||
self.parent = parent
|
||||
@@ -191,11 +191,11 @@ class ssh_channel(sock):
|
||||
return self.returncode
|
||||
|
||||
def can_recv_raw(self, timeout):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
if self.sock.recv_ready():
|
||||
return True
|
||||
time.sleep(0.05)
|
||||
with self.countdown(timeout):
|
||||
while self.countdown_active():
|
||||
if self.sock.recv_ready():
|
||||
return True
|
||||
time.sleep(min(self.timeout, 0.05))
|
||||
return False
|
||||
|
||||
def interactive(self, prompt = term.text.bold_red('$') + ' '):
|
||||
@@ -366,8 +366,8 @@ class ssh_channel(sock):
|
||||
return e
|
||||
|
||||
class ssh_connecter(sock):
|
||||
def __init__(self, parent, host, port, timeout = Timeout.default, level = None):
|
||||
super(ssh_connecter, self).__init__(timeout, level = level)
|
||||
def __init__(self, parent, host, port, *a, **kw):
|
||||
super(ssh_connecter, self).__init__(*a, **kw)
|
||||
|
||||
# keep the parent from being garbage collected in some cases
|
||||
self.parent = parent
|
||||
@@ -398,8 +398,8 @@ class ssh_connecter(sock):
|
||||
|
||||
|
||||
class ssh_listener(sock):
|
||||
def __init__(self, parent, bind_address, port, timeout = Timeout.default, level = None):
|
||||
super(ssh_listener, self).__init__(timeout, level = level)
|
||||
def __init__(self, parent, bind_address, port, *a, **kw):
|
||||
super(ssh_listener, self).__init__(*a, **kw)
|
||||
|
||||
# keep the parent from being garbage collected in some cases
|
||||
self.parent = parent
|
||||
@@ -478,8 +478,7 @@ class ssh(Timeout, Logger):
|
||||
|
||||
def __init__(self, user, host, port = 22, password = None, key = None,
|
||||
keyfile = None, proxy_command = None, proxy_sock = None,
|
||||
timeout = Timeout.default, level = None, cache = True,
|
||||
ssh_agent = False):
|
||||
level = None, cache = True, ssh_agent = False, *a, **kw):
|
||||
"""Creates a new ssh connection.
|
||||
|
||||
Arguments:
|
||||
@@ -498,7 +497,7 @@ class ssh(Timeout, Logger):
|
||||
|
||||
NOTE: The proxy_command and proxy_sock arguments is only available if a
|
||||
fairly new version of paramiko is used."""
|
||||
super(ssh, self).__init__(timeout)
|
||||
super(ssh, self).__init__(*a, **kw)
|
||||
|
||||
Logger.__init__(self)
|
||||
if level is not None:
|
||||
@@ -623,7 +622,8 @@ class ssh(Timeout, Logger):
|
||||
return self.run(shell, tty, timeout = timeout)
|
||||
|
||||
def process(self, argv=None, executable=None, tty=True, cwd=None, env=None, timeout=Timeout.default, run=True,
|
||||
stdin=0, stdout=1, stderr=2, preexec_fn=None, preexec_args=[], raw=True, aslr=None, setuid=None):
|
||||
stdin=0, stdout=1, stderr=2, preexec_fn=None, preexec_args=[], raw=True, aslr=None, setuid=None,
|
||||
shell=False):
|
||||
r"""
|
||||
Executes a process on the remote server, in the same fashion
|
||||
as pwnlib.tubes.process.process.
|
||||
@@ -680,6 +680,8 @@ class ssh(Timeout, Logger):
|
||||
See ``pwnlib.tubes.process.process`` for more information.
|
||||
setuid(bool):
|
||||
See ``pwnlib.tubes.process.process`` for more information.
|
||||
shell(bool):
|
||||
Pass the command-line arguments to the shell.
|
||||
|
||||
Returns:
|
||||
A new SSH channel, or a path to a script if ``run=False``.
|
||||
@@ -737,6 +739,9 @@ class ssh(Timeout, Logger):
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NameError: global name 'bar' is not defined
|
||||
|
||||
>>> s.process('echo hello', shell=True).recvall()
|
||||
'hello\n'
|
||||
"""
|
||||
if not argv and not executable:
|
||||
self.error("Must specify argv or executable")
|
||||
@@ -750,6 +755,11 @@ class ssh(Timeout, Logger):
|
||||
if not isinstance(argv, (list, tuple)):
|
||||
self.error('argv must be a list or tuple')
|
||||
|
||||
if shell:
|
||||
if len(argv) != 1:
|
||||
self.error('Cannot provide more than 1 argument if shell=True')
|
||||
argv = ['/bin/sh', '-c'] + argv
|
||||
|
||||
# Python doesn't like when an arg in argv contains '\x00'
|
||||
# -> execve() arg 2 must contain only strings
|
||||
for i, arg in enumerate(argv):
|
||||
@@ -862,6 +872,13 @@ if not %(aslr)r:
|
||||
|
||||
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
|
||||
|
||||
# Attempt to dump ALL core file regions
|
||||
try:
|
||||
with open('/proc/self/coredump_filter', 'w') as core_filter:
|
||||
core_filter.write('0x3f\n')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Assume that the user would prefer to have core dumps.
|
||||
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
|
||||
|
||||
@@ -941,7 +958,7 @@ os.execve(exe, argv, os.environ)
|
||||
|
||||
return result
|
||||
|
||||
def system(self, process, tty = True, wd = None, env = None, timeout = Timeout.default, raw = True):
|
||||
def system(self, process, tty = True, wd = None, env = None, timeout = None, raw = True):
|
||||
r"""system(process, tty = True, wd = None, env = None, timeout = Timeout.default, raw = True) -> ssh_channel
|
||||
|
||||
Open a new channel with a specific process inside. If `tty` is True,
|
||||
@@ -967,7 +984,10 @@ os.execve(exe, argv, os.environ)
|
||||
if wd is None:
|
||||
wd = self.cwd
|
||||
|
||||
return ssh_channel(self, process, tty, wd, env, timeout, level = self.level, raw = raw)
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
|
||||
return ssh_channel(self, process, tty, wd, env, timeout = timeout, level = self.level, raw = raw)
|
||||
|
||||
#: Backward compatibility. Use :meth:`system`
|
||||
run = system
|
||||
|
||||
@@ -30,18 +30,18 @@ class tube(Timeout, Logger):
|
||||
#: and related functions.
|
||||
newline = '\n'
|
||||
|
||||
def __init__(self, timeout = default, level = None):
|
||||
def __init__(self, timeout = default, level = None, *a, **kw):
|
||||
super(tube, self).__init__(timeout)
|
||||
|
||||
Logger.__init__(self, None)
|
||||
if level is not None:
|
||||
self.setLevel(level)
|
||||
|
||||
self.buffer = Buffer()
|
||||
self.buffer = Buffer(*a, **kw)
|
||||
atexit.register(self.close)
|
||||
|
||||
# Functions based on functions from subclasses
|
||||
def recv(self, numb = 4096, timeout = default):
|
||||
def recv(self, numb = None, timeout = default):
|
||||
r"""recv(numb = 4096, timeout = default) -> str
|
||||
|
||||
Receives up to `numb` bytes of data from the tube, and returns
|
||||
@@ -72,6 +72,7 @@ class tube(Timeout, Logger):
|
||||
[...] Received 0xc bytes:
|
||||
'Hello, world'
|
||||
"""
|
||||
numb = self.buffer.get_fill_size(numb)
|
||||
return self._recv(numb, timeout) or ''
|
||||
|
||||
def unrecv(self, data):
|
||||
@@ -122,7 +123,7 @@ class tube(Timeout, Logger):
|
||||
data = ''
|
||||
|
||||
with self.local(timeout):
|
||||
data = self.recv_raw(4096)
|
||||
data = self.recv_raw(self.buffer.get_fill_size())
|
||||
|
||||
if data and self.isEnabledFor(logging.DEBUG):
|
||||
self.debug('Received %#x bytes:' % len(data))
|
||||
@@ -141,12 +142,13 @@ class tube(Timeout, Logger):
|
||||
return data
|
||||
|
||||
|
||||
def _recv(self, numb = 4096, timeout = default):
|
||||
def _recv(self, numb = None, timeout = default):
|
||||
"""_recv(numb = 4096, timeout = default) -> str
|
||||
|
||||
Receives one chunk of from the internal buffer or from the OS if the
|
||||
buffer is empty.
|
||||
"""
|
||||
numb = self.buffer.get_fill_size(numb)
|
||||
data = ''
|
||||
|
||||
# No buffered data, could not put anything in the buffer
|
||||
|
||||
+21
-22
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import random
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import StringIO
|
||||
@@ -10,7 +11,7 @@ from . import packing
|
||||
from ..context import context
|
||||
from ..log import getLogger
|
||||
from ..term import text
|
||||
from .cyclic import cyclic
|
||||
from .cyclic import de_bruijn
|
||||
from .cyclic import cyclic_find
|
||||
|
||||
log = getLogger(__name__)
|
||||
@@ -559,13 +560,15 @@ default_style = {
|
||||
}
|
||||
|
||||
cyclic_pregen = ''
|
||||
de_bruijn_gen = de_bruijn()
|
||||
|
||||
def sequential_lines(a,b):
|
||||
return (a+b) in cyclic_pregen
|
||||
|
||||
def update_cyclic_pregenerated(size):
|
||||
global cyclic_pregen
|
||||
cyclic_pregen = cyclic(size)
|
||||
while size > len(cyclic_pregen):
|
||||
cyclic_pregen += de_bruijn_gen.next()
|
||||
|
||||
def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
highlight=None, cyclic=False):
|
||||
@@ -608,22 +611,6 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
spacer = ' '
|
||||
marker = (style.get('marker') or (lambda s:s))('│')
|
||||
|
||||
# Total length of the input stream
|
||||
total = 0
|
||||
|
||||
if hasattr(fd, 'len'):
|
||||
total = fd.len
|
||||
else:
|
||||
# Save the current file offset
|
||||
cur = fd.seek(0, os.SEEK_CUR)
|
||||
|
||||
# Determine the total size of the file
|
||||
fd.seek(0, os.SEEK_END)
|
||||
total = fd.tell()
|
||||
|
||||
# Restore the file offset
|
||||
fd.seek(cur, os.SEEK_SET)
|
||||
|
||||
if hexii:
|
||||
column_sep = ''
|
||||
line_fmt = '%%(offset)08x %%(hexbytes)-%is│' % (len(column_sep)+(width*byte_width))
|
||||
@@ -643,17 +630,29 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
|
||||
return hbyte, abyte
|
||||
cache = [style_byte(chr(b)) for b in range(256)]
|
||||
|
||||
if cyclic:
|
||||
update_cyclic_pregenerated(total)
|
||||
|
||||
numb = 0
|
||||
while True:
|
||||
offset = begin + numb
|
||||
chunk = fd.read(width)
|
||||
|
||||
# If a tube is passed in as fd, it will raise EOFError when it runs
|
||||
# out of data, unlike a file or StringIO object, which return an empty
|
||||
# string.
|
||||
try:
|
||||
chunk = fd.read(width)
|
||||
except EOFError:
|
||||
chunk = ''
|
||||
|
||||
# We have run out of data, exit the loop
|
||||
if chunk == '':
|
||||
break
|
||||
|
||||
# Advance the cursor by the number of bytes we actually read
|
||||
numb += len(chunk)
|
||||
|
||||
# Update the cyclic pattern in case
|
||||
if cyclic:
|
||||
update_cyclic_pregenerated(numb)
|
||||
|
||||
# If this chunk is the same as the last unique chunk,
|
||||
# use a '*' instead.
|
||||
if skip and last_unique:
|
||||
|
||||
+3
-61
@@ -2,19 +2,14 @@ import errno
|
||||
import socket
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
from .. import tubes
|
||||
from ..log import getLogger
|
||||
|
||||
try:
|
||||
import psutil
|
||||
_ok_import = True
|
||||
except ImportError:
|
||||
_ok_import = False
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
if _ok_import:
|
||||
all_pids = psutil.pids
|
||||
all_pids = psutil.pids
|
||||
|
||||
def pidof(target):
|
||||
"""pidof(target) -> int list
|
||||
@@ -305,56 +300,3 @@ def wait_for_debugger(pid):
|
||||
while tracer(pid) is None:
|
||||
time.sleep(0.01)
|
||||
l.success()
|
||||
|
||||
if not _ok_import:
|
||||
def _make_stub(func):
|
||||
func.__doc__ = 'Stubbed out function, because psutil is not available.'
|
||||
return func
|
||||
|
||||
@_make_stub
|
||||
def all_pids():
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def pidof(target):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def pid_by_name(name):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def name(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def parent(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def children(ppid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def ancestors(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def descendants(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def exe(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def cwd(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def cmdline(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
|
||||
@_make_stub
|
||||
def starttime(pid):
|
||||
log.error("Called stubbed-out function. Get psutil to work on your platform, then come back.")
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = '3.3.2'
|
||||
__version__ = '3.4.0beta4'
|
||||
@@ -54,11 +54,8 @@ install_requires = ['paramiko>=1.15.2',
|
||||
'pysocks',
|
||||
'python-dateutil',
|
||||
'pypandoc',
|
||||
'packaging']
|
||||
|
||||
# This is a hack until somebody ports psutil to OpenBSD
|
||||
if platform.system() != 'OpenBSD':
|
||||
install_requires.append('psutil>=2.1.3')
|
||||
'packaging',
|
||||
'psutil>=3.3.0']
|
||||
|
||||
# Check that the user has installed the Python development headers
|
||||
PythonH = os.path.join(get_python_inc(), 'Python.h')
|
||||
@@ -83,7 +80,7 @@ except ImportError:
|
||||
setup(
|
||||
name = 'pwntools',
|
||||
packages = find_packages(),
|
||||
version = '3.3.2',
|
||||
version = '3.4.0beta4',
|
||||
data_files = [('',
|
||||
glob.glob('*.md') + glob.glob('*.txt')),
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user