pwnlib.context
— Setting runtime variables¶
-
pwnlib.context.
context
= ContextType()[source]¶ Global
context
object, used to store commonly-used pwntools settings. In most cases, the context is used to infer default variables values. For example,pwnlib.asm.asm()
can take anos
parameter as a keyword argument. If it is not supplied, theos
specified bycontext
is used instead. Consider it a shorthand to passingos=
andarch=
to every single function call.
-
class
pwnlib.context.
ContextType
(**kwargs)[source]¶ Class for specifying information about the target machine. Intended for use as a pseudo-singleton through the global variable
pwnlib.context.context
, available viafrom pwn import *
ascontext
.The context is usually specified at the top of the Python file for clarity.
#!/usr/bin/env python3 context.update(arch='i386', os='linux')
Currently supported properties and their defaults are listed below. The defaults are inherited from
pwnlib.context.ContextType.defaults
.Additionally, the context is thread-aware when using
pwnlib.context.Thread
instead ofthreading.Thread
(all internalpwntools
threads use the former).The context is also scope-aware by using the
with
keyword.Examples
>>> context.clear() >>> context.update(os='linux') >>> context.os == 'linux' True >>> context.arch = 'arm' >>> vars(context) == {'arch': 'arm', 'bits': 32, 'endian': 'little', 'os': 'linux'} True >>> context.endian 'little' >>> context.bits 32 >>> def nop(): ... print(enhex(pwnlib.asm.asm('nop'))) >>> nop() 00f020e3 >>> with context.local(arch = 'i386'): ... nop() 90 >>> from pwnlib.context import Thread as PwnThread >>> from threading import Thread as NormalThread >>> with context.local(arch = 'mips'): ... pwnthread = PwnThread(target=nop) ... thread = NormalThread(target=nop) >>> # Normal thread uses the default value for arch, 'i386' >>> _ = (thread.start(), thread.join()) 90 >>> # Pwnthread uses the correct context from creation-time >>> _ = (pwnthread.start(), pwnthread.join()) 00000000 >>> nop() 00f020e3
-
class
Thread
(*args, **kwargs)[source]¶ Instantiates a context-aware thread, which inherit its context when it is instantiated. The class can be accessed both on the context module as pwnlib.context.Thread and on the context singleton object inside the context module as pwnlib.context.context.Thread.
Threads created by using the native :class`threading`.Thread` will have a clean (default) context.
Regardless of the mechanism used to create any thread, the context is de-coupled from the parent thread, so changes do not cascade to child or parent.
Saves a copy of the context when instantiated (at
__init__
) and updates the new thread’s context before passing control to the user code viarun
ortarget=
.Examples
>>> context.clear() >>> context.update(arch='arm') >>> def p(): ... print(context.arch) ... context.arch = 'mips' ... print(context.arch) >>> # Note that a normal Thread starts with a clean context >>> # (i386 is the default architecture) >>> t = threading.Thread(target=p) >>> _ = (t.start(), t.join()) i386 mips >>> # Note that the main Thread's context is unchanged >>> print(context.arch) arm >>> # Note that a context-aware Thread receives a copy of the context >>> t = pwnlib.context.Thread(target=p) >>> _ = (t.start(), t.join()) arm mips >>> # Again, the main thread is unchanged >>> print(context.arch) arm
Implementation Details:
This class implemented by hooking the private function
threading.Thread._Thread_bootstrap()
, which is called before passing control tothreading.Thread.run()
.This could be done by overriding
run
itself, but we would have to ensure that all uses of the class would only ever use the keywordtarget=
for__init__
, or that all subclasses invokesuper(Subclass.self).set_up_context()
or similar.
-
ContextType.
arch
[source]¶ Target binary architecture.
Allowed values are listed in
pwnlib.context.ContextType.architectures
.Side Effects:
If an architecture is specified which also implies additional attributes (e.g. ‘amd64’ implies 64-bit words, ‘powerpc’ implies big-endian), these attributes will be set on the context if a user has not already set a value.
The following properties may be modified.
bits
endian
Raises: AttributeError
– An invalid architecture was specifiedExamples
>>> context.clear() >>> context.arch == 'i386' # Default architecture True
>>> context.arch = 'mips' >>> context.arch == 'mips' True
>>> context.arch = 'doge' Traceback (most recent call last): ... AttributeError: arch must be one of ['aarch64', ..., 'thumb']
>>> context.arch = 'ppc' >>> context.arch == 'powerpc' # Aliased architecture True
>>> context.clear() >>> context.bits == 32 # Default value True >>> context.arch = 'amd64' >>> context.bits == 64 # New value True
Note that expressly setting
bits
means that we use that value instead of the default>>> context.clear() >>> context.bits = 32 >>> context.arch = 'amd64' >>> context.bits == 32 True
Setting the architecture can override the defaults for both
endian
andbits
>>> context.clear() >>> context.arch = 'powerpc64' >>> vars(context) == {'arch': 'powerpc64', 'bits': 64, 'endian': 'big'} True
-
ContextType.
architectures
= OrderedDict([('powerpc64', {'bits': 64, 'endian': 'big'}), ('aarch64', {'bits': 64, 'endian': 'little'}), ('powerpc', {'bits': 32, 'endian': 'big'}), ('sparc64', {'bits': 64, 'endian': 'big'}), ('mips64', {'bits': 64, 'endian': 'little'}), ('msp430', {'bits': 16, 'endian': 'little'}), ('alpha', {'bits': 64, 'endian': 'little'}), ('amd64', {'bits': 64, 'endian': 'little'}), ('thumb', {'bits': 32, 'endian': 'little'}), ('sparc', {'bits': 32, 'endian': 'big'}), ('s390', {'bits': 32, 'endian': 'big'}), ('cris', {'bits': 32, 'endian': 'little'}), ('i386', {'bits': 32, 'endian': 'little'}), ('ia64', {'bits': 64, 'endian': 'big'}), ('mips', {'bits': 32, 'endian': 'little'}), ('m68k', {'bits': 32, 'endian': 'big'}), ('arm', {'bits': 32, 'endian': 'little'}), ('vax', {'bits': 32, 'endian': 'little'}), ('avr', {'bits': 8, 'endian': 'little'})])[source]¶ Keys are valid values for
pwnlib.context.ContextType.arch()
. Values are defaults which are set whenpwnlib.context.ContextType.arch
is set
-
ContextType.
aslr
[source]¶ ASLR settings for new processes.
If
False
, attempt to disable ASLR in all processes which are created viapersonality
(setarch -R
) andsetrlimit
(ulimit -s unlimited
).The
setarch
changes are lost if asetuid
binary is executed.
-
ContextType.
binary
[source]¶ Infer target architecture, bit-with, and endianness from a binary file. Data type is a
pwnlib.elf.ELF
object.Examples
>>> context.clear() >>> context.arch, context.bits ('i386', 32) >>> context.binary = '/bin/bash' >>> context.binary ELF('/bin/bash') >>> (context.arch, context.bits) == (context.binary.arch, context.binary.bits) True
-
ContextType.
bits
[source]¶ Target machine word size, in bits (i.e. the size of general purpose registers).
The default value is
32
, but changes according toarch
.Examples
>>> context.clear() >>> context.bits == 32 True >>> context.bits = 64 >>> context.bits == 64 True >>> context.bits = -1 Traceback (most recent call last): ... AttributeError: bits must be > 0 (-1)
-
ContextType.
bytes
[source]¶ Target machine word size, in bytes (i.e. the size of general purpose registers).
This is a convenience wrapper around
bits / 8
.Examples
>>> context.bytes = 1 >>> context.bits == 8 True >>> context.bytes = 0 Traceback (most recent call last): ... AttributeError: bits must be > 0 (0)
-
ContextType.
clear
(*args, **kwargs)[source]¶ Clears the contents of the context. All values are set to their defaults.
Parameters: - a – Arguments passed to
update
- kw – Arguments passed to
update
Examples
>>> # Default value >>> context.arch == 'i386' True >>> context.arch = 'arm' >>> context.arch == 'i386' False >>> context.clear() >>> context.arch == 'i386' True
- a – Arguments passed to
-
ContextType.
copy
() → dict[source]¶ Returns a copy of the current context as a dictionary.
Examples
>>> context.clear() >>> context.os = 'linux' >>> vars(context) == {'os': 'linux'} True
-
ContextType.
defaults
= {'noptrace': False, 'aslr': True, 'proxy': None, 'binary': None, 'os': 'linux', 'randomize': False, 'bits': 32, 'log_level': 20, 'signed': False, 'arch': 'i386', 'kernel': None, 'endian': 'little', 'log_file': <pwnlib.context._devnull object>, 'timeout': 1048576.0, 'device': None, 'terminal': None, 'newline': '\n'}[source]¶ Default values for
pwnlib.context.ContextType
-
ContextType.
device
[source]¶ Sets a target device for local, attached-device debugging.
This is useful for local Android exploitation.
This option automatically inherits the ANDROID_SERIAL environment value.
-
ContextType.
endian
[source]¶ Endianness of the target machine.
The default value is
'little'
, but changes according toarch
.Raises: AttributeError
– An invalid endianness was providedExamples
>>> context.clear() >>> context.endian == 'little' True
>>> context.endian = 'big' >>> context.endian 'big'
>>> context.endian = 'be' >>> context.endian == 'big' True
>>> context.endian = 'foobar' Traceback (most recent call last): ... AttributeError: endian must be one of ['be', 'big', 'eb', 'el', 'le', 'little']
-
ContextType.
endianness
[source]¶ Legacy alias for
endian
.Examples
>>> context.endian == context.endianness True
-
ContextType.
endiannesses
= OrderedDict([('little', 'little'), ('big', 'big'), ('eb', 'big'), ('el', 'little'), ('be', 'big'), ('le', 'little')])[source]¶ Valid values for
endian
-
ContextType.
kernel
[source]¶ Target machine’s kernel architecture.
Usually, this is the same as
arch
, except when running a 32-bit binary on a 64-bit kernel (e.g. i386-on-amd64).Even then, this doesn’t matter much – only when the the segment registers need to be known
-
ContextType.
local
(**kwargs) → context manager[source]¶ Create a context manager for use with the
with
statement.For more information, see the example below or PEP 343.
Parameters: kwargs – Variables to be assigned in the new environment. Returns: ContextType manager for managing the old and new environment. Examples
>>> context.clear() >>> context.timeout = 1 >>> context.timeout == 1 True >>> print(context.timeout) 1.0 >>> with context.local(timeout=2): ... print(context.timeout) ... context.timeout = 3 ... print(context.timeout) 2.0 3.0 >>> print(context.timeout) 1.0
-
ContextType.
log_file
[source]¶ Sets the target file for all logging output.
Works in a similar fashion to
log_level
.Examples
>>> context.log_file = 'foo.txt' >>> log.debug('Hello!') >>> with context.local(log_level='ERROR'): ... log.info('Hello again!') >>> with context.local(log_file='bar.txt'): ... log.debug('Hello from bar!') >>> log.info('Hello from foo!') >>> open('foo.txt').readlines()[-3] '...:DEBUG:...:Hello!\n' >>> open('foo.txt').readlines()[-2] '...:INFO:...:Hello again!\n' >>> open('foo.txt').readlines()[-1] '...:INFO:...:Hello from foo!\n' >>> open('bar.txt').readlines()[-1] '...:DEBUG:...:Hello from bar!\n'
-
ContextType.
log_level
[source]¶ Sets the verbosity of
pwntools
logging mechanism.More specifically it controls the filtering of messages that happens inside the handler for logging to the screen. So if you want e.g. log all messages to a file, then this attribute makes no difference to you.
Valid values are specified by the standard Python
logging
module.Default value is set to
INFO
.Examples
>>> context.log_level = 'error' >>> context.log_level == logging.ERROR True >>> context.log_level = 10 >>> context.log_level = 'foobar' Traceback (most recent call last): ... AttributeError: log_level must be an integer or one of ['CRITICAL', 'DEBUG', 'ERROR', 'INFO', 'NOTSET', 'WARN', 'WARNING']
-
ContextType.
noptrace
[source]¶ Disable all actions which rely on ptrace.
This is useful for switching between local exploitation with a debugger, and remote exploitation (without a debugger).
This option can be set with the
NOPTRACE
command-line argument.
-
ContextType.
os
[source]¶ Operating system of the target machine.
The default value is
linux
.Allowed values are listed in
pwnlib.context.ContextType.oses
.Examples
>>> context.os = 'linux' >>> context.os = 'foobar' Traceback (most recent call last): ... AttributeError: os must be one of ['android', 'cgc', 'freebsd', 'linux', 'windows']
-
ContextType.
oses
= ['android', 'cgc', 'freebsd', 'linux', 'windows'][source]¶ Valid values for
pwnlib.context.ContextType.os()
-
ContextType.
proxy
[source]¶ Default proxy for all socket connections.
Examples
>>> context.proxy = 'localhost' >>> r = remote('google.com', 80) Traceback (most recent call last): ... pwnlib.exception.PwnlibException: Could not connect to google.com on port 80 >>> context.proxy = None >>> r = remote('google.com', 80, level='error')
-
ContextType.
signed
[source]¶ Signed-ness for packing operation when it’s not explicitly set.
Can be set to any non-string truthy value, or the specific string values
'signed'
or'unsigned'
which are converted intoTrue
andFalse
correspondingly.Examples
>>> context.signed False >>> context.signed = 1 >>> context.signed True >>> context.signed = 'signed' >>> context.signed True >>> context.signed = 'unsigned' >>> context.signed False >>> context.signed = 'foobar' Traceback (most recent call last): ... AttributeError: signed must be one of ['no', 'signed', 'unsigned', 'yes'] or a non-string truthy value
-
ContextType.
signednesses
= {'no': False, 'yes': True, 'signed': True, 'unsigned': False}[source]¶ Valid string values for
signed
-
ContextType.
terminal
[source]¶ Default terminal used by
pwnlib.util.misc.run_in_new_terminal()
. Can be a string or an iterable of strings. In the latter case the first entry is the terminal and the rest are default arguments.
-
ContextType.
timeout
[source]¶ Default amount of time to wait for a blocking operation before it times out, specified in seconds.
The default value is to have an infinite timeout.
See
pwnlib.timeout.Timeout
for additional information on valid values.
-
ContextType.
update
(*args, **kwargs)[source]¶ Convenience function, which is shorthand for setting multiple variables at once.
It is a simple shorthand such that:
context.update(os='linux', arch='arm', ...)
is equivalent to:
context.os = 'linux' context.arch = 'arm' ...
The following syntax is also valid:
context.update({'os': 'linux', 'arch': 'arm'})
Parameters: kwargs – Variables to be assigned in the environment. Examples
>>> context.clear() >>> context.update(arch='i386', os='linux') >>> context.arch, context.os ('i386', 'linux')
-
class
-
class
pwnlib.context.
Thread
(*args, **kwargs)[source]¶ Instantiates a context-aware thread, which inherit its context when it is instantiated. The class can be accessed both on the context module as pwnlib.context.Thread and on the context singleton object inside the context module as pwnlib.context.context.Thread.
Threads created by using the native :class`threading`.Thread` will have a clean (default) context.
Regardless of the mechanism used to create any thread, the context is de-coupled from the parent thread, so changes do not cascade to child or parent.
Saves a copy of the context when instantiated (at
__init__
) and updates the new thread’s context before passing control to the user code viarun
ortarget=
.Examples
>>> context.clear() >>> context.update(arch='arm') >>> def p(): ... print(context.arch) ... context.arch = 'mips' ... print(context.arch) >>> # Note that a normal Thread starts with a clean context >>> # (i386 is the default architecture) >>> t = threading.Thread(target=p) >>> _ = (t.start(), t.join()) i386 mips >>> # Note that the main Thread's context is unchanged >>> print(context.arch) arm >>> # Note that a context-aware Thread receives a copy of the context >>> t = pwnlib.context.Thread(target=p) >>> _ = (t.start(), t.join()) arm mips >>> # Again, the main thread is unchanged >>> print(context.arch) arm
Implementation Details:
This class implemented by hooking the private function
threading.Thread._Thread_bootstrap()
, which is called before passing control tothreading.Thread.run()
.This could be done by overriding
run
itself, but we would have to ensure that all uses of the class would only ever use the keywordtarget=
for__init__
, or that all subclasses invokesuper(Subclass.self).set_up_context()
or similar.