def gnu_hash(s): """gnu_hash(str) -> int Function used to generated GNU-style hashes for strings. """ s = bytearray(_encode(s)) h = 5381 for c in s: h = h * 33 + c return h & 0xffffffff
def write_text(self, data): r"""Write text to the file at this path >>> f = SSHPath('somefile', ssh=ssh_conn) >>> f.write_text("HELLO 😭") >>> f.read_bytes() b'HELLO \xf0\x9f\x98\xad' >>> f.read_text() 'HELLO 😭' """ data = _encode(data) self.write_bytes(data)
def sysv_hash(symbol): """sysv_hash(str) -> int Function used to generate SYSV-style hashes for strings. """ h = 0 g = 0 for c in bytearray(_encode(symbol)): h = (h << 4) + c g = h & 0xf0000000 h ^= (g >> 24) h &= ~g return h & 0xffffffff
def _dynamic_load_dynelf(self, libname): """_dynamic_load_dynelf(libname) -> DynELF Looks up information about a loaded library via the link map. Arguments: libname(str): Name of the library to resolve, or a substring (e.g. 'libc.so') Returns: A DynELF instance for the loaded library, or None. """ cur = self.link_map leak = self.leak LinkMap = { 32: elf.Elf32_Link_Map, 64: elf.Elf64_Link_Map }[self.elfclass] # make sure we rewind to the beginning! while leak.field(cur, LinkMap.l_prev): cur = leak.field(cur, LinkMap.l_prev) libname = _encode(libname) while cur: self.status("link_map entry %#x" % cur) p_name = leak.field(cur, LinkMap.l_name) name = leak.s(p_name) if libname in name: break if name: self.status('Skipping %s' % name) cur = leak.field(cur, LinkMap.l_next) else: self.failure("Could not find library with name containing %r" % libname) return None libbase = leak.field(cur, LinkMap.l_addr) self.status("Resolved library %r at %#x" % (libname, libbase)) lib = DynELF(leak, libbase) lib._dynamic = leak.field(cur, LinkMap.l_ld) lib._waitfor = self._waitfor return lib
def __init__(self, elf, symbol, args, data_addr=None): self.elf = elf self.elf_load_address_fixup = self.elf.address - self.elf.load_addr self.strtab = elf.dynamic_value_by_tag("DT_STRTAB") + self.elf_load_address_fixup self.symtab = elf.dynamic_value_by_tag("DT_SYMTAB") + self.elf_load_address_fixup self.jmprel = elf.dynamic_value_by_tag("DT_JMPREL") + self.elf_load_address_fixup self.versym = elf.dynamic_value_by_tag("DT_VERSYM") + self.elf_load_address_fixup self.symbol = _encode(symbol) self.args = args self.real_args = self._format_args() self.unreliable = False self.data_addr = data_addr if data_addr is not None else self._get_recommended_address() # Will be set when built self.reloc_index = -1 self.payload = b"" # PIE is untested, gcc forces FULL-RELRO when PIE is set if self.elf.pie and self.elf_load_address_fixup == 0: log.warning("WARNING: ELF is PIE but has no base address set") self._build()
def aux(args): for i, arg in enumerate(args): if isinstance(arg, (str,bytes)): args[i] = _encode(args[i]) + b"\x00" elif isinstance(arg, (list, tuple)): aux(arg)
def cyclic_find(subseq, alphabet = None, n = None): """cyclic_find(subseq, alphabet = None, n = None) -> int Calculates the position of a substring into a De Bruijn sequence. .. todo: "Calculates" is an overstatement. It simply traverses the list. There exists better algorithms for this, but they depend on generating the De Bruijn sequence in another fashion. Somebody should look at it: https://www.sciencedirect.com/science/article/pii/S0012365X00001175 Arguments: subseq: The subsequence to look for. This can be a string, a list or an integer. If an integer is provided it will be packed as a little endian integer. alphabet: List or string to generate the sequence over. By default, uses :obj:`.context.cyclic_alphabet`. n(int): The length of subsequences that should be unique. By default, uses :obj:`.context.cyclic_size`. Examples: Let's generate an example cyclic pattern. >>> cyclic(16) b'aaaabaaacaaadaaa' Note that 'baaa' starts at offset 4. The `cyclic_find` routine shows us this: >>> cyclic_find(b'baaa') 4 The *default* length of a subsequence generated by `cyclic` is `4`. If a longer value is submitted, it is automatically truncated to four bytes. >>> cyclic_find(b'baaacaaa') 4 If you provided e.g. `n=8` to `cyclic` to generate larger subsequences, you must explicitly provide that argument. >>> cyclic_find(b'baaacaaa', n=8) 3515208 We can generate a large cyclic pattern, and grab a subset of it to check a deeper offset. >>> cyclic_find(cyclic(1000)[514:518]) 514 Instead of passing in the byte representation of the pattern, you can also pass in the integer value. Note that this is sensitive to the selected endianness via `context.endian`. >>> cyclic_find(0x61616162) 4 >>> cyclic_find(0x61616162, endian='big') 1 You can use anything for the cyclic pattern, including non-printable characters. >>> cyclic_find(0x00000000, alphabet=unhex('DEADBEEF00')) 621 """ if n is None: n = context.cyclic_size if isinstance(subseq, six.integer_types): subseq = packing.pack(subseq, bytes=n) subseq = packing._encode(subseq) if len(subseq) != n: log.warn_once("cyclic_find() expects %i-byte subsequences by default, you gave %r\n" "Unless you specified cyclic(..., n=%i), you probably just want the first 4 bytes.\n" "Truncating the data at 4 bytes. Specify cyclic_find(..., n=%i) to override this.", n, subseq, len(subseq), len(subseq)) subseq = subseq[:n] if alphabet is None: alphabet = context.cyclic_alphabet alphabet = packing._encode(alphabet) if any(c not in alphabet for c in subseq): return -1 n = n or len(subseq) return _gen_find(subseq, de_bruijn(alphabet, n))
def lookup(self, symb=None, lib=None): """lookup(symb = None, lib = None) -> int Find the address of ``symbol``, which is found in ``lib``. Arguments: symb(str): Named routine to look up If omitted, the base address of the library will be returned. lib(str): Substring to match for the library name. If omitted, the current library is searched. If set to ``'libc'``, ``'libc.so'`` is assumed. Returns: Address of the named symbol, or :const:`None`. """ result = None if lib == 'libc': lib = 'libc.so' if symb: symb = _encode(symb) # # Get a pretty name for the symbol to show the user # if symb and lib: pretty = '%r in %r' % (symb, lib) else: pretty = repr(symb or lib) if not pretty: self.failure("Must specify a library or symbol") self.waitfor('Resolving %s' % pretty) # # If we are loading from a different library, create # a DynELF instance for it. # if lib is not None: dynlib = self._dynamic_load_dynelf(lib) else: dynlib = self if dynlib is None: log.failure("Could not find %r" % lib) return None # # If we are resolving a symbol in the library, find it. # if symb and self.libcdb: # Try a quick lookup by build ID self.status("Trying lookup based on Build ID") build_id = dynlib._lookup_build_id(lib=lib) if build_id: log.info("Trying lookup based on Build ID: %s" % build_id) path = libcdb.search_by_build_id(build_id) if path: with context.local(log_level='error'): e = ELF(path) e.address = dynlib.libbase result = e.symbols[symb] if symb and not result: self.status("Trying remote lookup") result = dynlib._lookup(symb) if not symb: result = dynlib.libbase # # Did we win? # if result: self.success("%#x" % result) else: self.failure("Could not find %s" % pretty) return result