# `pwnlib.util.fiddling` — Utilities bit fiddling

pwnlib.util.fiddling.b64d(s) → str

  Base64 decodes a string

  Example

      >>> b64d('dGVzdA==')
      b'test'

pwnlib.util.fiddling.b64e(s) → str

  Base64 encodes a string

  Example

      >>> b64e(b"test")
      'dGVzdA=='

pwnlib.util.fiddling.bits(s, endian='big', zero=0, one=1) → list

  Converts the argument into a list of bits.

  Parameters:

    - s – A string or number to be converted into bits.

    - endian (str) – The binary endian, default ‘big’.

    - zero – The representing a 0-bit.

    - one – The representing a 1-bit.

  Returns:

    A list consisting of the values specified in zero and one.

  Examples

      >>> bits(511, zero = "+", one = "-")
      ['+', '+', '+', '+', '+', '+', '+', '-', '-', '-', '-', '-', '-', '-', '-', '-']
      >>> sum(bits(b"test"))
      17
      >>> bits(0)
      [0, 0, 0, 0, 0, 0, 0, 0]

pwnlib.util.fiddling.bits_str(s, endian='big', zero='0', one='1') → str

  A wrapper around `bits()`, which converts the output into a string.

  Examples

      >>> bits_str(511)
      '0000000111111111'
      >>> bits_str(b"bits_str", endian = "little")
      '0100011010010110001011101100111011111010110011100010111001001110'

pwnlib.util.fiddling.bitswap(s) → str

  Reverses the bits in every byte of a given string.

  Example

      >>> bitswap(b"1234")
      b'\x8cL\xcc,'

pwnlib.util.fiddling.bitswap_int(n) → int

  Reverses the bits of a numbers and returns the result as a new number.

  Parameters:

    - n (int) – The number to swap.

    - width (int) – The width of the integer

  Examples

      >>> hex(bitswap_int(0x1234, 8))
      '0x2c'
      >>> hex(bitswap_int(0x1234, 16))
      '0x2c48'
      >>> hex(bitswap_int(0x1234, 24))
      '0x2c4800'
      >>> hex(bitswap_int(0x1234, 25))
      '0x589000'

pwnlib.util.fiddling.bnot(value, width=None)

  Returns the binary inverse of ‘value’.

pwnlib.util.fiddling.enhex(x) → str

  Hex-encodes a string.

  Example

      >>> enhex(b"test")
      '74657374'

pwnlib.util.fiddling.hexdump(s, width=16, skip=True, hexii=False, begin=0, style=None, highlight=None, cyclic=False, groupsize=4, total=True)
  hexdump(s, width = 16, skip = True, hexii = False, begin = 0, style = None,

    highlight = None, cyclic = False, groupsize=4, total = True) -> str

  Return a hexdump-dump of a string.

  Parameters:

    - s (bytes) – The data to hexdump.

    - width (int) – The number of characters per line

    - groupsize (int) – The number of characters per group

    - skip (bool) – Set to True, if repeated lines should be replaced by a “*”

    - hexii (bool) – Set to True, if a hexii-dump should be returned instead of a hexdump.

    - begin (int) – Offset of the first byte to print in the left column

    - style (dict) – Color scheme to use.

    - highlight (iterable) – Byte values to highlight.

    - cyclic (bool) – Attempt to skip consecutive, unmodified cyclic lines

    - total (bool) – Set to True, if total bytes should be printed

  Returns:

    A hexdump-dump in the form of a string.

  Examples

      >>> print(hexdump(b"abc"))
      00000000  61 62 63                                            │abc│
      00000003

      >>> print(hexdump(b'A'*32))
      00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
      *
      00000020

      >>> print(hexdump(b'A'*32, width=8))
      00000000  41 41 41 41  41 41 41 41  │AAAA│AAAA│
      *
      00000020

      >>> print(hexdump(cyclic(32), width=8, begin=0xdead0000, hexii=True))
      dead0000  .a  .a  .a  .a   .b  .a  .a  .a  │
      dead0008  .c  .a  .a  .a   .d  .a  .a  .a  │
      dead0010  .e  .a  .a  .a   .f  .a  .a  .a  │
      dead0018  .g  .a  .a  .a   .h  .a  .a  .a  │
      dead0020

      >>> print(hexdump(bytearray(range(256))))
      00000000  00 01 02 03  04 05 06 07  08 09 0a 0b  0c 0d 0e 0f  │····│····│····│····│
      00000010  10 11 12 13  14 15 16 17  18 19 1a 1b  1c 1d 1e 1f  │····│····│····│····│
      00000020  20 21 22 23  24 25 26 27  28 29 2a 2b  2c 2d 2e 2f  │ !"#│$%&'│()*+│,-./│
      00000030  30 31 32 33  34 35 36 37  38 39 3a 3b  3c 3d 3e 3f  │0123│4567│89:;│<=>?│
      00000040  40 41 42 43  44 45 46 47  48 49 4a 4b  4c 4d 4e 4f  │@ABC│DEFG│HIJK│LMNO│
      00000050  50 51 52 53  54 55 56 57  58 59 5a 5b  5c 5d 5e 5f  │PQRS│TUVW│XYZ[│\]^_│
      00000060  60 61 62 63  64 65 66 67  68 69 6a 6b  6c 6d 6e 6f  │`abc│defg│hijk│lmno│
      00000070  70 71 72 73  74 75 76 77  78 79 7a 7b  7c 7d 7e 7f  │pqrs│tuvw│xyz{│|}~·│
      00000080  80 81 82 83  84 85 86 87  88 89 8a 8b  8c 8d 8e 8f  │····│····│····│····│
      00000090  90 91 92 93  94 95 96 97  98 99 9a 9b  9c 9d 9e 9f  │····│····│····│····│
      000000a0  a0 a1 a2 a3  a4 a5 a6 a7  a8 a9 aa ab  ac ad ae af  │····│····│····│····│
      000000b0  b0 b1 b2 b3  b4 b5 b6 b7  b8 b9 ba bb  bc bd be bf  │····│····│····│····│
      000000c0  c0 c1 c2 c3  c4 c5 c6 c7  c8 c9 ca cb  cc cd ce cf  │····│····│····│····│
      000000d0  d0 d1 d2 d3  d4 d5 d6 d7  d8 d9 da db  dc dd de df  │····│····│····│····│
      000000e0  e0 e1 e2 e3  e4 e5 e6 e7  e8 e9 ea eb  ec ed ee ef  │····│····│····│····│
      000000f0  f0 f1 f2 f3  f4 f5 f6 f7  f8 f9 fa fb  fc fd fe ff  │····│····│····│····│
      00000100

      >>> print(hexdump(bytearray(range(256)), hexii=True))
      00000000      01  02  03   04  05  06  07   08  09  0a  0b   0c  0d  0e  0f  │
      00000010  10  11  12  13   14  15  16  17   18  19  1a  1b   1c  1d  1e  1f  │
      00000020  20  .!  ."  .#   .$  .%  .&  .'   .(  .)  .*  .+   .,  .-  ..  ./  │
      00000030  .0  .1  .2  .3   .4  .5  .6  .7   .8  .9  .:  .;   .<  .=  .>  .?  │
      00000040  .@  .A  .B  .C   .D  .E  .F  .G   .H  .I  .J  .K   .L  .M  .N  .O  │
      00000050  .P  .Q  .R  .S   .T  .U  .V  .W   .X  .Y  .Z  .[   .\  .]  .^  ._  │
      00000060  .`  .a  .b  .c   .d  .e  .f  .g   .h  .i  .j  .k   .l  .m  .n  .o  │
      00000070  .p  .q  .r  .s   .t  .u  .v  .w   .x  .y  .z  .{   .|  .}  .~  7f  │
      00000080  80  81  82  83   84  85  86  87   88  89  8a  8b   8c  8d  8e  8f  │
      00000090  90  91  92  93   94  95  96  97   98  99  9a  9b   9c  9d  9e  9f  │
      000000a0  a0  a1  a2  a3   a4  a5  a6  a7   a8  a9  aa  ab   ac  ad  ae  af  │
      000000b0  b0  b1  b2  b3   b4  b5  b6  b7   b8  b9  ba  bb   bc  bd  be  bf  │
      000000c0  c0  c1  c2  c3   c4  c5  c6  c7   c8  c9  ca  cb   cc  cd  ce  cf  │
      000000d0  d0  d1  d2  d3   d4  d5  d6  d7   d8  d9  da  db   dc  dd  de  df  │
      000000e0  e0  e1  e2  e3   e4  e5  e6  e7   e8  e9  ea  eb   ec  ed  ee  ef  │
      000000f0  f0  f1  f2  f3   f4  f5  f6  f7   f8  f9  fa  fb   fc  fd  fe  ##  │
      00000100

      >>> print(hexdump(b'X' * 64))
      00000000  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      *
      00000040

      >>> print(hexdump(b'X' * 64, skip=False))
      00000000  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      00000010  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      00000020  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      00000030  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      00000040

      >>> print(hexdump(fit({0x10: b'X'*0x20, 0x50-1: b'\xff'*20}, length=0xc0) + b'\x00'*32))
      00000000  61 61 61 61  62 61 61 61  63 61 61 61  64 61 61 61  │aaaa│baaa│caaa│daaa│
      00000010  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      *
      00000030  6d 61 61 61  6e 61 61 61  6f 61 61 61  70 61 61 61  │maaa│naaa│oaaa│paaa│
      00000040  71 61 61 61  72 61 61 61  73 61 61 61  74 61 61 ff  │qaaa│raaa│saaa│taa·│
      00000050  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  │····│····│····│····│
      00000060  ff ff ff 61  7a 61 61 62  62 61 61 62  63 61 61 62  │···a│zaab│baab│caab│
      00000070  64 61 61 62  65 61 61 62  66 61 61 62  67 61 61 62  │daab│eaab│faab│gaab│
      00000080  68 61 61 62  69 61 61 62  6a 61 61 62  6b 61 61 62  │haab│iaab│jaab│kaab│
      00000090  6c 61 61 62  6d 61 61 62  6e 61 61 62  6f 61 61 62  │laab│maab│naab│oaab│
      000000a0  70 61 61 62  71 61 61 62  72 61 61 62  73 61 61 62  │paab│qaab│raab│saab│
      000000b0  74 61 61 62  75 61 61 62  76 61 61 62  77 61 61 62  │taab│uaab│vaab│waab│
      000000c0  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
      *
      000000e0

      >>> print(hexdump(fit({0x10: b'X'*0x20, 0x50-1: b'\xff'*20}, length=0xc0) + b'\x00'*32, cyclic=1))
      00000000  61 61 61 61  62 61 61 61  63 61 61 61  64 61 61 61  │aaaa│baaa│caaa│daaa│
      00000010  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  │XXXX│XXXX│XXXX│XXXX│
      *
      00000030  6d 61 61 61  6e 61 61 61  6f 61 61 61  70 61 61 61  │maaa│naaa│oaaa│paaa│
      00000040  71 61 61 61  72 61 61 61  73 61 61 61  74 61 61 ff  │qaaa│raaa│saaa│taa·│
      00000050  ff ff ff ff  ff ff ff ff  ff ff ff ff  ff ff ff ff  │····│····│····│····│
      00000060  ff ff ff 61  7a 61 61 62  62 61 61 62  63 61 61 62  │···a│zaab│baab│caab│
      00000070  64 61 61 62  65 61 61 62  66 61 61 62  67 61 61 62  │daab│eaab│faab│gaab│
      *
      000000c0  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
      *
      000000e0

      >>> print(hexdump(fit({0x10: b'X'*0x20, 0x50-1: b'\xff'*20}, length=0xc0) + b'\x00'*32, cyclic=1, hexii=1))
      00000000  .a  .a  .a  .a   .b  .a  .a  .a   .c  .a  .a  .a   .d  .a  .a  .a  │
      00000010  .X  .X  .X  .X   .X  .X  .X  .X   .X  .X  .X  .X   .X  .X  .X  .X  │
      *
      00000030  .m  .a  .a  .a   .n  .a  .a  .a   .o  .a  .a  .a   .p  .a  .a  .a  │
      00000040  .q  .a  .a  .a   .r  .a  .a  .a   .s  .a  .a  .a   .t  .a  .a  ##  │
      00000050  ##  ##  ##  ##   ##  ##  ##  ##   ##  ##  ##  ##   ##  ##  ##  ##  │
      00000060  ##  ##  ##  .a   .z  .a  .a  .b   .b  .a  .a  .b   .c  .a  .a  .b  │
      00000070  .d  .a  .a  .b   .e  .a  .a  .b   .f  .a  .a  .b   .g  .a  .a  .b  │
      *
      000000c0                                                                     │
      *
      000000e0

      >>> print(hexdump(b'A'*16, width=9))
      00000000  41 41 41 41  41 41 41 41  41  │AAAA│AAAA│A│
      00000009  41 41 41 41  41 41 41         │AAAA│AAA│
      00000010
      >>> print(hexdump(b'A'*16, width=10))
      00000000  41 41 41 41  41 41 41 41  41 41  │AAAA│AAAA│AA│
      0000000a  41 41 41 41  41 41               │AAAA│AA│
      00000010
      >>> print(hexdump(b'A'*16, width=11))
      00000000  41 41 41 41  41 41 41 41  41 41 41  │AAAA│AAAA│AAA│
      0000000b  41 41 41 41  41                     │AAAA│A│
      00000010
      >>> print(hexdump(b'A'*16, width=12))
      00000000  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│
      0000000c  41 41 41 41                            │AAAA│
      00000010
      >>> print(hexdump(b'A'*16, width=13))
      00000000  41 41 41 41  41 41 41 41  41 41 41 41  41  │AAAA│AAAA│AAAA│A│
      0000000d  41 41 41                                   │AAA│
      00000010
      >>> print(hexdump(b'A'*16, width=14))
      00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41  │AAAA│AAAA│AAAA│AA│
      0000000e  41 41                                         │AA│
      00000010
      >>> print(hexdump(b'A'*16, width=15))
      00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41  │AAAA│AAAA│AAAA│AAA│
      0000000f  41                                               │A│
      00000010

      >>> print(hexdump(b'A'*24, width=16, groupsize=8))
      00000000  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  │AAAAAAAA│AAAAAAAA│
      00000010  41 41 41 41 41 41 41 41                           │AAAAAAAA│
      00000018
      >>> print(hexdump(b'A'*24, width=16, groupsize=-1))
      00000000  41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41  │AAAAAAAAAAAAAAAA│
      00000010  41 41 41 41 41 41 41 41                          │AAAAAAAA│
      00000018

      >>> print(hexdump(b'A'*24, width=16, total=False))
      00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
      00000010  41 41 41 41  41 41 41 41                            │AAAA│AAAA│
      >>> print(hexdump(b'A'*24, width=16, groupsize=8, total=False))
      00000000  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  │AAAAAAAA│AAAAAAAA│
      00000010  41 41 41 41 41 41 41 41                           │AAAAAAAA│

pwnlib.util.fiddling.hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None, highlight=None, cyclic=False, groupsize=4, total=True)
  hexdump_iter(s, width = 16, skip = True, hexii = False, begin = 0, style = None,

    highlight = None, cyclic = False, groupsize=4, total = True) -> str generator

  Return a hexdump-dump of a string as a generator of lines. Unless you have massive amounts of data you probably want to use `hexdump()`.

  Parameters:

    - fd (file) – File object to dump. Use `StringIO.StringIO()` or `hexdump()` to dump a string.

    - width (int) – The number of characters per line

    - groupsize (int) – The number of characters per group

    - skip (bool) – Set to True, if repeated lines should be replaced by a “*”

    - hexii (bool) – Set to True, if a hexii-dump should be returned instead of a hexdump.

    - begin (int) – Offset of the first byte to print in the left column

    - style (dict) – Color scheme to use.

    - highlight (iterable) – Byte values to highlight.

    - cyclic (bool) – Attempt to skip consecutive, unmodified cyclic lines

    - total (bool) – Set to True, if total bytes should be printed

  Returns:

    A generator producing the hexdump-dump one line at a time.

  Example

      >>> tmp = tempfile.NamedTemporaryFile()
      >>> _ = tmp.write(b'XXXXHELLO, WORLD')
      >>> tmp.flush()
      >>> _ = tmp.seek(4)
      >>> print('\n'.join(hexdump_iter(tmp)))
      00000000  48 45 4c 4c  4f 2c 20 57  4f 52 4c 44               │HELL│O, W│ORLD│
      0000000c

      >>> t = tube()
      >>> t.unrecv(b'I know kung fu')
      >>> print('\n'.join(hexdump_iter(t)))
      00000000  49 20 6b 6e  6f 77 20 6b  75 6e 67 20  66 75        │I kn│ow k│ung │fu│
      0000000e

pwnlib.util.fiddling.hexii(s, width=16, skip=True) → str

  Return a HEXII-dump of a string.

  Parameters:

    - s (str) – The string to dump

    - width (int) – The number of characters per line

    - skip (bool) – Should repeated lines be replaced by a “*”

  Returns:

    A HEXII-dump in the form of a string.

pwnlib.util.fiddling.isprint(c) → bool

  Return True if a character is printable

pwnlib.util.fiddling.js_escape(data, padding=context.cyclic_alphabet[0:1], endian=None, **kwargs) → str

  Pack data as an escaped Unicode string for use in JavaScript’s unescape() function

  Parameters:

    - data (bytes) – Bytes to pack

    - padding (bytes) – A single byte to use as padding if data is of uneven length

    - endian (str) – Endianness with which to pack the string (“little”/”big”)

  Returns:

    A string representation of the packed data

      >>> js_escape(b'\xde\xad\xbe\xef')
      '%uadde%uefbe'

      >>> js_escape(b'\xde\xad\xbe\xef', endian='big')
      '%udead%ubeef'

      >>> js_escape(b'\xde\xad\xbe')
      '%uadde%u61be'

      >>> js_escape(b'aaaa')
      '%u6161%u6161'

pwnlib.util.fiddling.js_unescape(s, endian=None, **kwargs) → bytes

  Unpack an escaped Unicode string from JavaScript’s escape() function

  Parameters:

    - s (str) – Escaped string to unpack

    - endian (str) – Endianness with which to unpack the string (“little”/”big”)

  Returns:

    A bytes representation of the unpacked data

      >>> js_unescape('%uadde%uefbe')
      b'\xde\xad\xbe\xef'

      >>> js_unescape('%udead%ubeef', endian='big')
      b'\xde\xad\xbe\xef'

      >>> js_unescape('abc%u4141123')
      b'a\x00b\x00c\x00AA1\x002\x003\x00'

      >>> data = b'abcdABCD1234!@#$\x00\x01\x02\x03\x80\x81\x82\x83'
      >>> js_unescape(js_escape(data)) == data
      True

      >>> js_unescape('%u4141%u42')
      Traceback (most recent call last):
      ValueError: Incomplete Unicode token: %u42

      >>> js_unescape('%u4141%uwoot%4141')
      Traceback (most recent call last):
      ValueError: Failed to decode token: %uwoot

      >>> js_unescape('%u4141%E4%F6%FC%u4141')
      Traceback (most recent call last):
      NotImplementedError: Non-Unicode % tokens are not supported: %E4

      >>> js_unescape('%u4141%zz%u4141')
      Traceback (most recent call last):
      ValueError: Bad % token: %zz

pwnlib.util.fiddling.naf(int) → int generator

  Returns a generator for the non-adjacent form (NAF[1]) of a number, n. If naf(n) generates z_0, z_1, …, then n == z_0 + z_1 * 2 + z_2 * 2**2, ….

  [1] https://en.wikipedia.org/wiki/Non-adjacent_form

  Example

      >>> n = 45
      >>> m = 0
      >>> x = 1
      >>> for z in naf(n):
      ...     m += x * z
      ...     x *= 2
      >>> n == m
      True

pwnlib.util.fiddling.negate(value, width=None)

  Returns the two’s complement of ‘value’.

pwnlib.util.fiddling.randoms(count, alphabet=string.ascii_lowercase) → str

  Returns a random string of a given length using only the specified alphabet.

  Parameters:

    - count (int) – The length of the desired string.

    - alphabet – The alphabet of allowed characters. Defaults to all lowercase characters.

  Returns:

    A random string.

  Example

      >>> randoms(10)
      'evafjilupm'

pwnlib.util.fiddling.rol(n, k, word_size=None)

  Returns a rotation by k of n.

  When n is a number, then means `((n << k) | (n >> (word_size - k)))` truncated to word_size bits.

  When n is a list, tuple or string, this is `n[k % len(n):] + n[:k % len(n)]`.

  Parameters:

    - n – The value to rotate.

    - k (int) – The rotation amount. Can be a positive or negative number.

    - word_size (int) – If n is a number, then this is the assumed bitsize of n. Defaults to `pwnlib.context.word_size` if None .

  Example

      >>> rol('abcdefg', 2)
      'cdefgab'
      >>> rol('abcdefg', -2)
      'fgabcde'
      >>> hex(rol(0x86, 3, 8))
      '0x34'
      >>> hex(rol(0x86, -3, 8))
      '0xd0'

pwnlib.util.fiddling.ror(n, k, word_size=None)

  A simple wrapper around `rol()`, which negates the values of k.

pwnlib.util.fiddling.tty_escape(s, lnext=b'\x16', dangerous=bytes(bytearray(range(0x20)))) → bytes

  Escape data for terminal output. This is useful when sending data to a terminal that may interpret certain bytes as control characters.

  Check `stty --all` for the current settings on your terminal.

  Parameters:

    - s (bytes) – The data to escape

    - lnext (bytes) – The byte to prepend to escape the next character. Defaults to ^V.

    - dangerous (bytes) – The bytes to escape

  Returns:

    The escaped data.

      >>> tty_escape(b'abc\x04d\x18e\x16f')
      b'abc\x16\x04d\x16\x18e\x16\x16f'

pwnlib.util.fiddling.unbits(s, endian='big') → str

  Converts an iterable of bits into a string.

  Parameters:

    - s – Iterable of bits

    - endian (str) – The string “little” or “big”, which specifies the bits endianness.

  Returns:

    A string of the decoded bits.

  Example

      >>> unbits([1])
      b'\x80'
      >>> unbits([1], endian = 'little')
      b'\x01'
      >>> unbits(bits(b'hello'), endian = 'little')
      b'\x16\xa666\xf6'

pwnlib.util.fiddling.unhex(s) → str

  Hex-decodes a string.

  Example

      >>> unhex("74657374")
      b'test'
      >>> unhex("F\n")
      b'\x0f'
      >>> unhex(bytearray(b" F "))
      b'\x0f'

pwnlib.util.fiddling.urldecode(s, ignore_invalid=False) → str

  URL-decodes a string.

  Example

      >>> urldecode("test%20%41")
      'test A'
      >>> urldecode("%qq")
      Traceback (most recent call last):
      ...
      ValueError: Invalid input to urldecode
      >>> urldecode("%qq", ignore_invalid = True)
      '%qq'

pwnlib.util.fiddling.urlencode(s) → str

  URL-encodes a string.

  Example

      >>> urlencode("test")
      '%74%65%73%74'

pwnlib.util.fiddling.xor(*args, cut='max') → str

  Flattens its arguments using `pwnlib.util.packing.flat()` and then xors them together. If the end of a string is reached, it wraps around in the string.

  Parameters:

    - args – The arguments to be xor’ed together.

    - cut – How long a string should be returned. Can be either ‘min’/’max’/’left’/’right’ or a number.

  Returns:

    The string of the arguments xor’ed together.

  Example

      >>> xor(b'lol', b'hello', 42)
      b'. ***'
      >>> xor(cut = 'min', other = '')
      Traceback (most recent call last):
        ...
      TypeError: xor() got an unexpected keyword argument 'other'

pwnlib.util.fiddling.xor_key(data, size=None, avoid='\x00\n')

  Finds a `size`-width value that can be XORed with a string to produce `data`, while neither the XOR value or XOR string contain any bytes in `avoid`.

  Parameters:

    - data (str) – The desired string.

    - avoid – The list of disallowed characters. Defaults to nulls and newlines.

    - size (int) – Size of the desired output value, default is word size.

  Returns:

    A tuple containing two strings; the XOR key and the XOR string. If no such pair exists, None is returned.

  Example

      >>> xor_key(b"Hello, world")
      (b'\x01\x01\x01\x01', b'Idmmn-!vnsme')

pwnlib.util.fiddling.xor_pair(data, avoid='\x00\n')

  Finds two strings that will xor into a given string, while only using a given alphabet.

  Parameters:

    - data (str) – The desired string.

    - avoid – The list of disallowed characters. Defaults to nulls and newlines.

  Returns:

    Two strings which will xor to the given string. If no such two strings exist, then None is returned.

  Example

      >>> xor_pair(b"test")
      (b'\x01\x01\x01\x01', b'udru')