# `pwnlib.memleak` — Helper class for leaking memory

class pwnlib.memleak.MemLeak(f, search_range=20, reraise=True, relative=False)

  MemLeak is a caching and heuristic tool for exploiting memory leaks.

  It can be used as a decorator, around functions of the form:

  > def some_leaker(addr):

  >   … return data_as_string_or_None

  It will cache leaked memory (which requires either non-randomized static data or a continouous session). If required, dynamic or known data can be set with the set-functions, but this is usually not required. If a byte cannot be recovered, it will try to leak nearby bytes in the hope that the byte is recovered as a side-effect.

  Parameters:

    - f (function) – The leaker function.

    - search_range (int) – How many bytes to search backwards in case an address does not work.

    - reraise (bool) – Whether to reraise call `pwnlib.log.warning()` in case the leaker function throws an exception.

  Example

      >>> import pwnlib
      >>> binsh = pwnlib.util.misc.read('/bin/sh')
      >>> @pwnlib.memleak.MemLeak
      ... def leaker(addr):
      ...     print("leaking 0x%x" % addr)
      ...     return binsh[addr:addr+4]
      >>> leaker.s(0)[:4]
      leaking 0x0
      leaking 0x4
      b'\x7fELF'
      >>> leaker[:4]
      b'\x7fELF'
      >>> hex(leaker.d(0))
      '0x464c457f'
      >>> hex(leaker.clearb(1))
      '0x45'
      >>> hex(leaker.d(0))
      leaking 0x1
      '0x464c457f'
      >>> @pwnlib.memleak.MemLeak
      ... def leaker_nonulls(addr):
      ...     print("leaking 0x%x" % addr)
      ...     if addr & 0xff == 0:
      ...         return None
      ...     return binsh[addr:addr+4]
      >>> leaker_nonulls.d(0) is None
      leaking 0x0
      True
      >>> leaker_nonulls[0x100:0x104] == binsh[0x100:0x104]
      leaking 0x100
      leaking 0xff
      leaking 0x103
      True

      >>> memory = {-4+i: c.encode() for i,c in enumerate('wxyzABCDE')}
      >>> def relative_leak(index):
      ...     return memory.get(index, None)
      >>> leak = pwnlib.memleak.MemLeak(relative_leak, relative = True)
      >>> leak[-1:2]
      b'zAB'

  static NoNewlines(function)

    Wrapper for leak functions such that addresses which contain newline bytes are not leaked.

    This is useful if the address which is used for the leak is provided by e.g. `fgets()`.

  static NoNulls(function)

    Wrapper for leak functions such that addresses which contain NULL bytes are not leaked.

    This is useful if the address which is used for the leak is read in via a string-reading function like `scanf("%s")` or smilar.

  static NoWhitespace(function)

    Wrapper for leak functions such that addresses which contain whitespace bytes are not leaked.

    This is useful if the address which is used for the leak is read in via e.g. `scanf()`.

  static String(function)

    Wrapper for leak functions which leak strings, such that a NULL terminator is automaticall added.

    This is useful if the data leaked is printed out as a NULL-terminated string, via e.g. `printf()`.

  __call__(*a, **kw)

    Call self as a function.

  __init__(f, search_range=20, reraise=True, relative=False)
  __repr__()

    Return repr(self).

  _leak(addr, n, recurse=True)

    _leak(addr, n) => str

    Leak `n` consecutive bytes starting at `addr`.

    Returns:

      A string of length `n`, or `None`.

  b(addr, ndx=0) → int

    Leak byte at `((uint8_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+2], reraise=False)
        >>> l.b(0) == ord('a')
        True
        >>> l.b(25) == ord('z')
        True
        >>> l.b(26) is None
        True

  clearb(addr, ndx=0) → int

    Clears byte at `((uint8_t*)addr)[ndx]` from the cache and returns the removed value or None if the address was not completely set.

    Examples

        >>> l = MemLeak(lambda a: None)
        >>> l.cache = {0:b'a'}
        >>> l.n(0,1) == b'a'
        True
        >>> l.clearb(0) == unpack(b'a', 8)
        True
        >>> l.cache
        {}
        >>> l.clearb(0) is None
        True

  cleard(addr, ndx=0) → int

    Clears dword at `((uint32_t*)addr)[ndx]` from the cache and returns the removed value or None if the address was not completely set.

    Examples

        >>> l = MemLeak(lambda a: None)
        >>> l.cache = {0: b'a', 1: b'b', 2: b'c', 3: b'd'}
        >>> l.n(0, 4) == b'abcd'
        True
        >>> l.cleard(0) == unpack(b'abcd', 32)
        True
        >>> l.cache
        {}

  clearq(addr, ndx=0) → int

    Clears qword at `((uint64_t*)addr)[ndx]` from the cache and returns the removed value or None if the address was not completely set.

    Examples

        >>> c = MemLeak(lambda addr: b'')
        >>> c.cache = {x:b'x' for x in range(0x100, 0x108)}
        >>> c.clearq(0x100) == unpack(b'xxxxxxxx', 64)
        True
        >>> c.cache == {}
        True

  clearw(addr, ndx=0) → int

    Clears word at `((uint16_t*)addr)[ndx]` from the cache and returns the removed value or None if the address was not completely set.

    Examples

        >>> l = MemLeak(lambda a: None)
        >>> l.cache = {0: b'a', 1: b'b'}
        >>> l.n(0, 2) == b'ab'
        True
        >>> l.clearw(0) == unpack(b'ab', 16)
        True
        >>> l.cache
        {}

  d(addr, ndx=0) → int

    Leak dword at `((uint32_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+8], reraise=False)
        >>> l.d(0) == unpack(b'abcd', 32)
        True
        >>> l.d(22) == unpack(b'wxyz', 32)
        True
        >>> l.d(23) is None
        True

  field(address, obj)

    field(address, field) => a structure field.

    Leak a field from a structure.

    Parameters:

      - address (int) – Base address to calculate offsets from

      - field (obj) – Instance of a ctypes field

    Return Value:

      The type of the return value will be dictated by the type of `field`.

  field_compare(address, obj, expected)

    field_compare(address, field, expected) ==> bool

    Leak a field from a structure, with an expected value. As soon as any mismatch is found, stop leaking the structure.

    Parameters:

      - address (int) – Base address to calculate offsets from

      - field (obj) – Instance of a ctypes field

      - expected (int,bytes) – Expected value

    Return Value:

      The type of the return value will be dictated by the type of `field`.

  n(addr, ndx=0) → str

    Leak numb bytes at addr.

    Returns:

      A string with the leaked bytes, will return None if any are missing

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+4], reraise=False)
        >>> l.n(0,1) == b'a'
        True
        >>> l.n(0,26) == data
        True
        >>> len(l.n(0,26)) == 26
        True
        >>> l.n(0,27) is None
        True

  p(addr, ndx=0) → int

    Leak a pointer-width value at `((void**) addr)[ndx]`

  p16(addr, val, ndx=0)

    Sets word at `((uint16_t*)addr)[ndx]` to val in the cache.

    Examples

        >>> l = MemLeak(lambda x: b'')
        >>> l.cache == {}
        True
        >>> l.setw(33, 0x41)
        >>> l.cache == {33: b'A', 34: b'\x00'}
        True

  p32(addr, val, ndx=0)

    Sets dword at `((uint32_t*)addr)[ndx]` to val in the cache.

    Examples

    See `setw()`.

  p64(addr, val, ndx=0)

    Sets qword at `((uint64_t*)addr)[ndx]` to val in the cache.

    Examples

    See `setw()`.

  p8(addr, val, ndx=0)

    Sets byte at `((uint8_t*)addr)[ndx]` to val in the cache.

    Examples

        >>> l = MemLeak(lambda x: b'')
        >>> l.cache == {}
        True
        >>> l.setb(33, 0x41)
        >>> l.cache == {33: b'A'}
        True

  q(addr, ndx=0) → int

    Leak qword at `((uint64_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+16], reraise=False)
        >>> l.q(0) == unpack(b'abcdefgh', 64)
        True
        >>> l.q(18) == unpack(b'stuvwxyz', 64)
        True
        >>> l.q(19) is None
        True

  raw(addr, numb) → list

    Leak numb bytes at addr

  s(addr) → str

    Leak bytes at addr until failure or a nullbyte is found

    Returns:

      A string, without a NULL terminator. The returned string will be empty if the first byte is a NULL terminator, or if the first byte could not be retrieved.

    Examples

        >>> data = b"Hello\x00World"
        >>> l = MemLeak(lambda a: data[a:a+4], reraise=False)
        >>> l.s(0) == b"Hello"
        True
        >>> l.s(5) == b""
        True
        >>> l.s(6) == b"World"
        True
        >>> l.s(999) == b""
        True

  setb(addr, val, ndx=0)

    Sets byte at `((uint8_t*)addr)[ndx]` to val in the cache.

    Examples

        >>> l = MemLeak(lambda x: b'')
        >>> l.cache == {}
        True
        >>> l.setb(33, 0x41)
        >>> l.cache == {33: b'A'}
        True

  setd(addr, val, ndx=0)

    Sets dword at `((uint32_t*)addr)[ndx]` to val in the cache.

    Examples

    See `setw()`.

  setq(addr, val, ndx=0)

    Sets qword at `((uint64_t*)addr)[ndx]` to val in the cache.

    Examples

    See `setw()`.

  sets(addr, val, null_terminate=True)

    Set known string at addr, which will be optionally be null-terminated

    Note that this method is a bit dumb about how it handles the data. It will null-terminate the data, but it will not stop at the first null.

    Examples

        >>> l = MemLeak(lambda x: b'')
        >>> l.cache == {}
        True
        >>> l.sets(0, b'H\x00ello')
        >>> l.cache == {0: b'H', 1: b'\x00', 2: b'e', 3: b'l', 4: b'l', 5: b'o', 6: b'\x00'}
        True

  setw(addr, val, ndx=0)

    Sets word at `((uint16_t*)addr)[ndx]` to val in the cache.

    Examples

        >>> l = MemLeak(lambda x: b'')
        >>> l.cache == {}
        True
        >>> l.setw(33, 0x41)
        >>> l.cache == {33: b'A', 34: b'\x00'}
        True

  struct(address, struct)

    struct(address, struct) => structure object Leak an entire structure. :param address: Addess of structure in memory :type address: int :param struct: A ctypes structure to be instantiated with leaked data :type struct: class

    Return Value:

      An instance of the provided struct class, with the leaked data decoded

    Examples

        >>> @pwnlib.memleak.MemLeak
        ... def leaker(addr):
        ...     return b"A"
        >>> e = leaker.struct(0, pwnlib.elf.Elf32_Phdr)
        >>> hex(e.p_paddr)
        '0x41414141'

  u16(addr, ndx=0)

    w(addr, ndx = 0) -> int

    Leak word at `((uint16_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+4], reraise=False)
        >>> l.w(0) == unpack(b'ab', 16)
        True
        >>> l.w(24) == unpack(b'yz', 16)
        True
        >>> l.w(25) is None
        True

  u32(addr, ndx=0)

    d(addr, ndx = 0) -> int

    Leak dword at `((uint32_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+8], reraise=False)
        >>> l.d(0) == unpack(b'abcd', 32)
        True
        >>> l.d(22) == unpack(b'wxyz', 32)
        True
        >>> l.d(23) is None
        True

  u64(addr, ndx=0)

    q(addr, ndx = 0) -> int

    Leak qword at `((uint64_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+16], reraise=False)
        >>> l.q(0) == unpack(b'abcdefgh', 64)
        True
        >>> l.q(18) == unpack(b'stuvwxyz', 64)
        True
        >>> l.q(19) is None
        True

  u8(addr, ndx=0)

    b(addr, ndx = 0) -> int

    Leak byte at `((uint8_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+2], reraise=False)
        >>> l.b(0) == ord('a')
        True
        >>> l.b(25) == ord('z')
        True
        >>> l.b(26) is None
        True

  w(addr, ndx=0) → int

    Leak word at `((uint16_t*) addr)[ndx]`

    Examples

        >>> import string
        >>> data = string.ascii_lowercase.encode()
        >>> l = MemLeak(lambda a: data[a:a+4], reraise=False)
        >>> l.w(0) == unpack(b'ab', 16)
        True
        >>> l.w(24) == unpack(b'yz', 16)
        True
        >>> l.w(25) is None
        True

  __weakref__

    list of weak references to the object

class pwnlib.memleak.RelativeMemLeak(*a, **kw)
  __init__(*a, **kw)