def _resolve(self, x): if x is None or pwn.isint(x): return x for y in [self.symbols, self.plt, self.sections]: if x in y: return y[x] return False
def __coerce__ (self, other): if pwn.isint(other) and self._load_addr: return (self._load_addr, other) elif isinstance(other, str): return (self.flush(), other) else: pwn.die('Could not coerce ROP. Other value was: %r' % other)
def __coerce__(self, other): if pwn.isint(other) and self._load_addr: return (self._load_addr, other) elif isinstance(other, str): return (self.flush(), other) else: pwn.die('Could not coerce ROP. Other value was: %r' % other)
def flat(*args, **kwargs): """Flattens the arguments into a string. Takes a single named argument 'func', which defaults to "p32" if no context is set and to "p" otherwise. - Strings are returned - Integers are converted using the 'func' argument. - Shellcode is assembled - Enumerables (such as lists) traversed recursivly and the concatenated. Example: - flat(5, "hello", [[6, "bar"], "baz"]) == '\\x05\\x00\\x00\\x00hello\\x06\\x00\\x00\\x00barbaz' """ global _AssemblerBlock if _AssemblerBlock == None: from pwn.internal.shellcode_helper import AssemblerBlock as _AssemblerBlock if 'arch' in kwargs and kwargs['arch'] != None: default_func = p else: default_func = p32 func = kwargs.get('func', default_func) obj = args[0] if len(args) == 1 else args if isinstance(obj, str): return obj elif pwn.isint(obj): return func(obj) elif hasattr(obj, '__flat__'): return obj.__flat__() else: return "".join(flat(o, func=func) for o in obj)
def _resolve(self, x): if x is None or pwn.isint(x): return x for y in [self.symbols, self.plt, self.sections]: if x in y: return y[x] return self.sections.get('.' + x, False)
def _mov_thumb(dst, src): if not pwn.isint(src): return "mov %s, %s" % (dst, src) srcu = src & 0xffffffff srcs = srcu - 2 * (srcu & 0x80000000) if srcu == 0: return 'eor %s, %s' % (dst, dst) if srcu < 256: return 'mov %s, #%d' % (dst, src) if -256 < srcs < 0: return 'eor %s, %s\nsub %s, #%d' % (dst, dst, dst, -srcs) shift1 = 0 while (1 << shift1) & src == 0: shift1 += 1 if (0xff << shift1) & src == src: if shift1 < 4: return 'mov %s, #%d\nlsl %s, #4\nlsr %s, #%d' % ( dst, src >> shift1, dst, dst, 4 - shift1) return 'mov %s, #%d\nlsl %s, #%d' % (dst, src >> shift1, dst, shift1) shift2 = 8 while (1 << shift2) & src == 0: shift2 += 1 if ((0xff << shift2) | 0xff) & src == src: return 'mov %s, #%d\nlsl %s, #%d\nadd %s, #%d' % ( dst, src >> shift2, dst, shift2, dst, src & 0xff) shift3 = shift1 + 8 while (1 << shift3) & src == 0: shift3 += 1 if ((0xff << shift1) | (0xff << shift3)) & src == src: return 'mov %s, #%d\nlsl %s, #%d\nadd %s, #%d\nlsl %s, #%d' % ( dst, src >> shift3, dst, shift3 - shift1, dst, (src >> shift1) & 0xff, dst, shift1) id = pwn.randoms(32, only=string.ascii_lowercase) if (src & 0xFF000000 == 0x0): src = src | 0xFF000000 extra = ''.join([ "lsl %s, #8" % dst, "lsr %s, #8" % dst, ]) return '\n'.join([ "ldr %s, %s" % (dst, id), "b %s_after" % id, "%s: .word %d" % (id, src), "%s_after:" % id, extra ])
def arg_fixup(s): if not isinstance(s, str): return s try: import ast s2 = ast.literal_eval(s) if pwn.isint(s2): return s2 except: pass try: s2 = pwn.clookup(s, eval=True) if isinstance(s2, list) and len(s2) == 1 and pwn.isint(s2[0]): return s2[0] except: pass return s
def arg_fixup(s): if not isinstance(s, str): return s try: import ast s2 = ast.literal_eval(s) if pwn.isint(s2): return s2 except: pass try: s2 = pwn.clookup(s, eval = True) if isinstance(s2, list) and len(s2) == 1 and pwn.isint(s2[0]): return s2[0] except: pass return s
def _mov_i386(dest, src, stack_allowed): regs = [ ['eax', 'ax', 'al', 'ah'], ['ebx', 'bx', 'bl', 'bh'], ['ecx', 'cx', 'cl', 'ch'], ['edx', 'dx', 'dl', 'dh'], ['edi', 'di'], ['esi', 'si'], ['ebp', 'bp'], ['esp', 'sp'], ] all_regs, sizes, bigger, smaller = _fix_regs(regs, [32, 16, 8, 8]) if dest not in all_regs: bug('%s is not a register' % str(dest)) if pwn.isint(src): if src >= 2**sizes[dest] or src < -(2**(sizes[dest] - 1)): pwn.log.warning('Number 0x%x does not fit into %s' % (src, dest)) srcp = packs_little_endian[sizes[dest]](src) if src == 0: return 'xor %s, %s' % (dest, dest) if '\x00' not in srcp and '\n' not in srcp: return 'mov %s, 0x%x' % (dest, src) if stack_allowed and sizes[ dest] == 32 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s' % (src, dest) if stack_allowed and sizes[ dest] == 16 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s\ninc esp\ninc esp' % (src, dest) a, b = pwn.xor_pair(srcp, avoid='\x00\n') u = unpacks_little_endian[sizes[dest]] a = u(a) b = u(b) return 'mov %s, 0x%x\nxor %s, 0x%x' % (dest, a, dest, b) elif src in all_regs: if src == dest or src in bigger[dest] or src in smaller[dest]: return '' elif sizes[dest] == sizes[src]: return 'mov %s, %s' % (dest, src) elif sizes[dest] > sizes[src]: return 'movzx %s, %s' % (dest, src) else: for r in bigger[dest]: if sizes[r] == sizes[src]: return 'mov %s, %s' % (r, src) bug('Register %s could not be moved into %s' % (src, dest)) bug('%s is neither a register nor an immediate' % src)
def output(xs): if doflat: return ''.join(chr(x) for x in xs) for con in list, tuple: if isinstance(args[0], con): if all(pwn.isint(x) for x in args[0]): return con(xs) else: return con(chr(x) for x in xs) return ''.join(chr(x) for x in xs)
def _mov_thumb(dst, src): if not pwn.isint(src): return "mov %s, %s" % (dst, src) srcu = src & 0xffffffff srcs = srcu - 2 * (srcu & 0x80000000) if srcu == 0: return 'eor %s, %s' % (dst, dst) if srcu < 256: return 'mov %s, #%d' % (dst, src) if -256 < srcs < 0: return 'eor %s, %s\nsub %s, #%d' % (dst, dst, dst, -srcs) shift1 = 0 while (1 << shift1) & src == 0: shift1 += 1 if (0xff << shift1) & src == src: if shift1 < 4: return 'mov %s, #%d\nlsl %s, #4\nlsr %s, #%d' % (dst, src >> shift1, dst, dst, 4-shift1) return 'mov %s, #%d\nlsl %s, #%d' % (dst, src >> shift1, dst, shift1) shift2 = 8 while (1 << shift2) & src == 0: shift2 += 1 if ((0xff << shift2) | 0xff) & src == src: return 'mov %s, #%d\nlsl %s, #%d\nadd %s, #%d' % (dst, src >> shift2, dst, shift2, dst, src & 0xff) shift3 = shift1 + 8 while (1 << shift3) & src == 0: shift3 += 1 if ((0xff << shift1) | (0xff << shift3)) & src == src: return 'mov %s, #%d\nlsl %s, #%d\nadd %s, #%d\nlsl %s, #%d' % (dst, src >> shift3, dst, shift3 - shift1, dst, (src >> shift1) & 0xff, dst, shift1) id = pwn.randoms(32, only = string.ascii_lowercase) if (src & 0xFF000000 == 0x0): src = src | 0xFF000000 extra = ''.join([ "lsl %s, #8" % dst, "lsr %s, #8" % dst, ]) return '\n'.join([ "ldr %s, %s" % (dst, id), "b %s_after" % id, "%s: .word %d" % (id, src), "%s_after:" % id, extra])
def _mov_i386(dest, src, stack_allowed): regs = [['eax', 'ax', 'al', 'ah'], ['ebx', 'bx', 'bl', 'bh'], ['ecx', 'cx', 'cl', 'ch'], ['edx', 'dx', 'dl', 'dh'], ['edi', 'di'], ['esi', 'si'], ['ebp', 'bp'], ['esp', 'sp'], ] all_regs, sizes, bigger, smaller = _fix_regs(regs, [32, 16, 8, 8]) if dest not in all_regs: bug('%s is not a register' % str(dest)) if pwn.isint(src): if src >= 2**sizes[dest] or src < -(2**(sizes[dest]-1)): pwn.log.warning('Number 0x%x does not fit into %s' % (src, dest)) srcp = packs_little_endian[sizes[dest]](src) if src == 0: return 'xor %s, %s' % (dest, dest) if '\x00' not in srcp and '\n' not in srcp: return 'mov %s, 0x%x' % (dest, src) if stack_allowed and sizes[dest] == 32 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s' % (src, dest) if stack_allowed and sizes[dest] == 16 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s\ninc esp\ninc esp' % (src, dest) a,b = pwn.xor_pair(srcp, avoid = '\x00\n') u = unpacks_little_endian[sizes[dest]] a = u(a) b = u(b) return 'mov %s, 0x%x\nxor %s, 0x%x' % (dest, a, dest, b) elif src in all_regs: if src == dest or src in bigger[dest] or src in smaller[dest]: return '' elif sizes[dest] == sizes[src]: return 'mov %s, %s' % (dest, src) elif sizes[dest] > sizes[src]: return 'movzx %s, %s' % (dest, src) else: for r in bigger[dest]: if sizes[r] == sizes[src]: return 'mov %s, %s' % (r, src) bug('Register %s could not be moved into %s' % (src, dest)) bug('%s is neither a register nor an immediate' % src)
def de_bruijn_find(subseq, alphabet = string.ascii_lowercase, n = None): """Returns the index for the subsequence of a De Bruijn Sequence for the given alphabet and subsequences of length n. If not specified, n will default to len(subseq). There exists better algorithms for this, but they depend on generating the De Bruijn sequence in another fashion. Somebody should look at it: http://www.sciencedirect.com/science/article/pii/S0012365X00001175 """ if pwn.isint(subseq): subseq = pwn.pint(subseq) if n == None: n = len(subseq) return gen_find(subseq, de_bruijn_generator(alphabet, n))
def xor(*args, **kwargs): """Flattens its arguments and then xors them together. If the end of a string is reached, it wraps around in the string. Converts the output to a string or a list or tuple of ints or chrs depending on the first input. Arguments: - func: The function to use with flat. Defaults to p8. - cut: How long a string should be returned. Can be either 'min'/'max'/'left'/'right' or a number. - flat: Ignore type of first argument and flatten output in all cases. Defaults to False.""" if len(args) == 0: return [] cut = kwargs.get('cut', 'max') func = kwargs.get('func', p8) doflat = kwargs.get('flat', False) def output(xs): if doflat: return ''.join(chr(x) for x in xs) for con in list, tuple: if isinstance(args[0], con): if all(pwn.isint(x) for x in args[0]): return con(xs) else: return con(chr(x) for x in xs) return ''.join(chr(x) for x in xs) strs = filter(len, [map(ord, flat(s, func=func)) for s in args]) if strs == []: return output([]) if pwn.isint(cut): l = cut elif cut == 'left': l = len(strs[0]) elif cut == 'right': l = len(strs[-1]) elif cut == 'min': l = min(map(len, strs)) elif cut == 'max': l = max(map(len, strs)) else: raise Exception("Not a valid cut argument") def get(n): return reduce(lambda x, y: x ^ y, [s[n % len(s)] for s in strs]) return output(get(n) for n in range(l))
def __len__(self): res = 0 for o in self._content: if pwn.isint(o) or _is_sympy(o): res += self.wordsize elif hasattr(o, '__len__'): res += len(o) else: res += len(pwn.flat(o)) return res
def pargs(args): out = [] for a in args: if a is None: out.append(garbage()) elif pwn.isint(a): out.append(p(a)) elif hasattr(a, '__iter__'): packed = pargs(a) payload.extend(packed) out.append(offset[0]) for a in packed: if pwn.isint(a): offset[0] += 4 else: offset[0] += len(a) else: if isinstance(a, str): a += '\x00' a = pwn.flat(a) payload.append(a) out.append(offset[0]) offset[0] += len(a) return out
def __setitem__ (self, addr, val): import pwn if pwn.isint(val): if val == 0: self.cache[addr] = 0 else: n = 0 while val: self.cache[addr + n] = val & 0xff val >>= 8 n += 1 elif isinstance(val, str): for n, c in enumerate(val): self.cache[addr + n] = ord(c) else: raise TypeError
def update_symbols(self, offset = 0, base = None): Block.symbols[self.name + '_offset_start'] = offset if base: Block.symbols[self.name + '_addr_start'] = base + offset for o in self._content: if isinstance(o, Block): offset = o.update_symbols(offset, base) elif pwn.isint(o) or _is_sympy(o): offset += self.wordsize elif hasattr(o, '__len__'): offset += len(o) else: offset += len(pwn.flat(o)) if base: Block.symbols[self.name + '_addr_end'] = base + offset Block.symbols[self.name + '_offset_end'] = offset Block.symbols[self.name + '_size'] = Block.symbols[self.name + '_offset_end'] - Block.symbols[self.name + '_offset_start'] return offset
def update_symbols(self, offset=0, base=None): Block.symbols[self.name + '_offset_start'] = offset if base: Block.symbols[self.name + '_addr_start'] = base + offset for o in self._content: if isinstance(o, Block): offset = o.update_symbols(offset, base) elif pwn.isint(o) or _is_sympy(o): offset += self.wordsize elif hasattr(o, '__len__'): offset += len(o) else: offset += len(pwn.flat(o)) if base: Block.symbols[self.name + '_addr_end'] = base + offset Block.symbols[self.name + '_offset_end'] = offset Block.symbols[self.name + '_size'] = Block.symbols[ self.name + '_offset_end'] - Block.symbols[self.name + '_offset_start'] return offset
def _mov_arm(dst, src): import string if not pwn.isint(src): return "mov %s, %s" % (dst, src) if len(asm("ldr %s, =%d" % (dst, src))) == 4: return "ldr %s, =%d" % (dst, src) srcu = src & 0xffffffff srcn = ~src & 0xffffffff for n, op in zip([srcu, srcn], ['mov', 'mvn']): shift1 = 0 while (0x03 << shift1) & n == 0: shift1 += 2 shift2 = shift1 + 8 while (0x03 << shift2) & n == 0: shift2 += 2 if n == (n & (0xff << shift1)) + (n & (0xff << shift2)): return '\n'.join([ "// mov %s, #%d" % (dst, src), "%s %s, #%d" % (op, dst, (n & (0xff << shift1))), "%s %s, #%d" % ("eor", dst, (n & (0xff << shift2))) ]) id = pwn.randoms(32, only=string.ascii_lowercase) return '\n'.join([ "ldr %s, %s" % (dst, id), "b %s_after" % id, "%s: .word %d" % (id, src), "%s_after:" % id ])
def _mov_arm(dst, src): import string if not pwn.isint(src): return "mov %s, %s" % (dst, src) if len(asm("ldr %s, =%d" % (dst, src))) == 4: return "ldr %s, =%d" % (dst, src) srcu = src & 0xffffffff srcn = ~src & 0xffffffff for n, op in zip([srcu, srcn], ['mov', 'mvn']): shift1 = 0 while (0x03 << shift1) & n == 0: shift1 += 2 shift2 = shift1 + 8 while (0x03 << shift2) & n == 0: shift2 += 2 if n == (n & (0xff << shift1)) + (n & (0xff << shift2)): return '\n'.join([ "// mov %s, #%d" % (dst, src), "%s %s, #%d" % (op, dst, (n & (0xff << shift1))), "%s %s, #%d" % ("eor", dst, (n & (0xff << shift2))) ]) id = pwn.randoms(32, only = string.ascii_lowercase) return '\n'.join([ "ldr %s, %s" % (dst, id), "b %s_after" % id, "%s: .word %d" % (id, src), "%s_after:" % id])
def _generate32(self): out = [] chain = self._chain self._chain = [] p = pwn.p32 def garbage(): return self._garbage(4) payload = [] offset = [0] def pargs(args): out = [] for a in args: if a is None: out.append(garbage()) elif pwn.isint(a): out.append(p(a)) elif hasattr(a, '__iter__'): packed = pargs(a) payload.extend(packed) out.append(offset[0]) for a in packed: if pwn.isint(a): offset[0] += 4 else: offset[0] += len(a) else: if isinstance(a, str): a += '\x00' a = pwn.flat(a) payload.append(a) out.append(offset[0]) offset[0] += len(a) return out for i in range(len(chain)): type, link = chain[i] islast = i == len(chain) - 1 issndlast = i == len(chain) - 2 if type == 'raw': out += pargs(link) elif type == 'call': target, pivot, args = link out.append(p(target)) if len(args) > 0: if islast: out.append(garbage()) out += pargs(args) elif issndlast and chain[i + 1][0] == 'call' and \ len(chain[i + 1][1][2]) == 0: # the last target has no arguments, so go straight to it out.append(p(chain[i + 1][1][0])) out += pargs(args) break else: if pivot is None: # find suitable popret res = self._pivot(args) if res is None: pwn.die( 'Could not find gadget for pivoting %d arguments' % len(args)) pivot, size = res args = pargs(args) for _ in range(size - len(args)): args.append(garbage()) out.append(p(pivot)) out += args elif type == 'migrate': if not islast: pwn.die('Migrate must be last link in chain') esp, ebp = link gp = self.gadget('popebp') gl = self.gadget('leave') if not gp or not gl: pwn.die( 'Could not find set-EBP and leave gadgets needed to migrate' ) if ebp is None: out += [p(gp), p(esp - 4), p(gl)] else: out += [p(gp), p(esp), p(gl)] self.raw(ebp) else: pwn.die('Unknown ROP-link type') offset = len(out) * 4 out_ = out + payload out = [] for o in out_: if pwn.isint(o): if self._load_addr is None: pwn.die( 'Load address of ROP chain not known; can\'t use structures' ) out.append(p(offset + o + self._load_addr)) else: out.append(o) self._load_addr = self._next_load_addr self._next_load_addr = None return ''.join(out)
def _generate32(self): out = [] chain = self._chain self._chain = [] p = pwn.p32 def garbage(): return self._garbage(4) payload = [] offset = [0] def pargs(args): out = [] for a in args: if a is None: out.append(garbage()) elif pwn.isint(a): out.append(p(a)) elif hasattr(a, '__iter__'): packed = pargs(a) payload.extend(packed) out.append(offset[0]) for a in packed: if pwn.isint(a): offset[0] += 4 else: offset[0] += len(a) else: if isinstance(a, str): a += '\x00' a = pwn.flat(a) payload.append(a) out.append(offset[0]) offset[0] += len(a) return out for i in range(len(chain)): type, link = chain[i] islast = i == len(chain) - 1 issndlast = i == len(chain) - 2 if type == 'raw': out += pargs(link) elif type == 'call': target, pivot, args = link out.append(p(target)) if len(args) > 0: if islast: out.append(garbage()) out += pargs(args) elif issndlast and chain[i + 1][0] == 'call' and \ len(chain[i + 1][1][2]) == 0: # the last target has no arguments, so go straight to it out.append(p(chain[i + 1][1][0])) out += pargs(args) break else: if pivot is None: # find suitable popret res = self._pivot(args) if res is None: pwn.die('Could not find gadget for pivoting %d arguments' % len(args)) pivot, size = res args = pargs(args) for _ in range(size - len(args)): args.append(garbage()) out.append(p(pivot)) out += args elif type == 'migrate': if not islast: pwn.die('Migrate must be last link in chain') esp, ebp = link gp = self._gadgets['popebp'] gl = self._gadgets['leave'] if len(gp) == 0 and len(gl) == 0: pwn.die('Could not find set-EBP and leave gadgets needed to migrate') gp = gp[0] gl = gl[0] if ebp is None: out += [p(gp), p(esp-4), p(gl)] else: out += [p(gp), p(esp), p(gl)] self.raw(ebp) else: pwn.die('Unknown ROP-link type') offset = len(out) * 4 out_ = out + payload out = [] for o in out_: if pwn.isint(o): if self._load_addr is None: pwn.die('Load address of ROP chain not known; can\'t use structures') out.append(p(offset + o + self._load_addr)) else: out.append(o) self._load_addr = self._next_load_addr self._next_load_addr = None return ''.join(out)
def _mov_amd64(dest, src, stack_allowed): regs = [['rax', 'eax', 'ax', 'al'], ['rbx', 'ebx', 'bx', 'bl'], ['rcx', 'ecx', 'cx', 'cl'], ['rdx', 'edx', 'dx', 'dl'], ['rdi', 'edi', 'di', 'dil'], ['rsi', 'esi', 'si', 'sil'], ['rbp', 'ebp', 'bp', 'bpl'], ['rsp', 'esp', 'sp', 'spl'], ['r8', 'r8d', 'r8w', 'r8b'], ['r9', 'r9d', 'r9w', 'r9b'], ['r10', 'r10d', 'r10w', 'r10b'], ['r11', 'r11d', 'r11w', 'r11b'], ['r12', 'r12d', 'r12w', 'r12b'], ['r13', 'r13d', 'r13w', 'r13b'], ['r14', 'r14d', 'r14w', 'r14b'], ['r15', 'r15d', 'r15w', 'r15b'] ] all_regs, sizes, bigger, smaller = _fix_regs(regs, [64, 32, 16, 8, 8]) if dest not in all_regs: bug('%s is not a register' % str(dest)) if pwn.isint(src): if src >= 2**sizes[dest] or src < -(2**(sizes[dest]-1)): pwn.log.warning('Number 0x%x does not fit into %s' % (src, dest)) srcp = packs_little_endian[sizes[dest]](src) if src == 0: if sizes[dest] == 64: return 'xor %s, %s' % (smaller[dest][0], smaller[dest][0]) else: return 'xor %s, %s' % (dest, dest) if '\x00' not in srcp and '\n' not in srcp: return 'mov %s, 0x%x' % (dest, src) if stack_allowed and sizes[dest] == 64 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s' % (src, dest) # TODO: is it a good idea to transform mov('eax', 17) to mov('rax', 17) # automatically? if stack_allowed and sizes[dest] == 32 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s' % (src, bigger[dest][0]) a,b = pwn.xor_pair(srcp, avoid = '\x00\n') u = unpacks_little_endian[sizes[dest]] a = u(a) b = u(b) return 'mov %s, 0x%x\nxor %s, 0x%x' % (dest, a, dest, b) elif src in all_regs: if src == dest or src in bigger[dest] or src in smaller[dest]: return '' elif sizes[dest] == sizes[src]: return 'mov %s, %s' % (dest, src) elif sizes[dest] == 64 and sizes[src] == 32: return 'mov %s, %s' % (smaller[dest][0], src) elif sizes[dest] > sizes[src]: return 'movzx %s, %s' % (dest, src) else: for r in bigger[dest]: if sizes[r] == sizes[src]: return 'mov %s, %s' % (r, src) bug('Register %s could not be moved into %s' % (src, dest)) bug('%s is neither a register nor an immediate' % src)
def bits(s, endian = 'big', zero = None, one = None, type = None, size = None): '''Converts the argument into a string of binary sequence or a binary integer list Arguments: - s: The sequence which should be parsed. - endian(optional): The binary endian, default 'big'. - zero(optional): The byte representing a 0bit, required if one is defined. - one(optional): The byte representing a 1bit, required if zero is defined. - type(optional): A string representing the input type, can be 'bool' or 'str', defaults to integer if not defined. - size: Number of bits to output, None for minimum number of bits. Returns a string of 1s and 0s if type = 'str', else a list of bits. ''' types = {bool: 'bool', 'bool': 'bool', str: 'str', 'str': 'str', 'string': 'str', int: 'int', 'int': 'int', None: None} try: type = types[type] except: pwn.die("Wat. Unknown type %s" % str(type)) if zero != None or one != None: if zero == None or one == None: pwn.die("Wat. You cannot specify just a zero or a one in bits") if type != None: pwn.die("You cannot specify both a type and (zero, one)") else: if type == 'bool': zero = False one = True elif type == 'str': zero = "0" one = "1" else: zero = 0 one = 1 out = [] if isinstance(s, str): for c in s: b = ord(c) byte = [] for _ in range(8): byte.append(one if b & 1 else zero) b >>= 1 if endian == 'little': out += byte elif endian == 'big': out += byte[::-1] else: pwn.die('Wat (endian style)') elif pwn.isint(s): while s: bit, s = one if s & 1 else zero, s >> 1 if endian == 'little': out.append(bit) else: out.insert(0, bit) else: print `s` pwn.die("Wat (bits does not support this type)") if size is not None: if len(out) < size: tail = [zero] * (size - len(out)) if endian == 'little': out += tail else: out = tail + out else: if endian == 'little': out = out[:size] else: out = out[-size:] if type == 'str': return ''.join(out) else: return out
def enhex(x): """Hex-encodes a string or integer""" if pwn.isint(x): x = pint(x) return x.encode('hex')
def bits(s, endian='big', zero=None, one=None, type=None, size=None): '''Converts the argument into a string of binary sequence or a binary integer list Arguments: - s: The sequence which should be parsed. - endian(optional): The binary endian, default 'big'. - zero(optional): The byte representing a 0bit, required if one is defined. - one(optional): The byte representing a 1bit, required if zero is defined. - type(optional): A string representing the input type, can be 'bool' or 'str', defaults to integer if not defined. - size: Number of bits to output, None for minimum number of bits. Returns a string of 1s and 0s if type = 'str', else a list of bits. ''' types = { bool: 'bool', 'bool': 'bool', str: 'str', 'str': 'str', 'string': 'str', int: 'int', 'int': 'int', None: None } try: type = types[type] except: pwn.die("Wat. Unknown type %s" % str(type)) if zero != None or one != None: if zero == None or one == None: pwn.die("Wat. You cannot specify just a zero or a one in bits") if type != None: pwn.die("You cannot specify both a type and (zero, one)") else: if type == 'bool': zero = False one = True elif type == 'str': zero = "0" one = "1" else: zero = 0 one = 1 out = [] if isinstance(s, str): for c in s: b = ord(c) byte = [] for _ in range(8): byte.append(one if b & 1 else zero) b >>= 1 if endian == 'little': out += byte elif endian == 'big': out += byte[::-1] else: pwn.die('Wat (endian style)') elif pwn.isint(s): while s: bit, s = one if s & 1 else zero, s >> 1 if endian == 'little': out.append(bit) else: out.insert(0, bit) else: print ` s ` pwn.die("Wat (bits does not support this type)") if size is not None: if len(out) < size: tail = [zero] * (size - len(out)) if endian == 'little': out += tail else: out = tail + out else: if endian == 'little': out = out[:size] else: out = out[-size:] if type == 'str': return ''.join(out) else: return out
def _mov_amd64(dest, src, stack_allowed): regs = [['rax', 'eax', 'ax', 'al'], ['rbx', 'ebx', 'bx', 'bl'], ['rcx', 'ecx', 'cx', 'cl'], ['rdx', 'edx', 'dx', 'dl'], ['rdi', 'edi', 'di', 'dil'], ['rsi', 'esi', 'si', 'sil'], ['rbp', 'ebp', 'bp', 'bpl'], ['rsp', 'esp', 'sp', 'spl'], ['r8', 'r8d', 'r8w', 'r8b'], ['r9', 'r9d', 'r9w', 'r9b'], ['r10', 'r10d', 'r10w', 'r10b'], ['r11', 'r11d', 'r11w', 'r11b'], ['r12', 'r12d', 'r12w', 'r12b'], ['r13', 'r13d', 'r13w', 'r13b'], ['r14', 'r14d', 'r14w', 'r14b'], ['r15', 'r15d', 'r15w', 'r15b']] all_regs, sizes, bigger, smaller = _fix_regs(regs, [64, 32, 16, 8, 8]) if dest not in all_regs: bug('%s is not a register' % str(dest)) if pwn.isint(src): if src >= 2**sizes[dest] or src < -(2**(sizes[dest] - 1)): pwn.log.warning('Number 0x%x does not fit into %s' % (src, dest)) srcp = packs_little_endian[sizes[dest]](src) if src == 0: if sizes[dest] == 64: return 'xor %s, %s' % (smaller[dest][0], smaller[dest][0]) else: return 'xor %s, %s' % (dest, dest) if '\x00' not in srcp and '\n' not in srcp: return 'mov %s, 0x%x' % (dest, src) if stack_allowed and sizes[ dest] == 64 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s' % (src, dest) # TODO: is it a good idea to transform mov('eax', 17) to mov('rax', 17) # automatically? if stack_allowed and sizes[ dest] == 32 and -128 <= src <= 127 and src != 0xa: return 'push 0x%x\npop %s' % (src, bigger[dest][0]) a, b = pwn.xor_pair(srcp, avoid='\x00\n') u = unpacks_little_endian[sizes[dest]] a = u(a) b = u(b) return 'mov %s, 0x%x\nxor %s, 0x%x' % (dest, a, dest, b) elif src in all_regs: if src == dest or src in bigger[dest] or src in smaller[dest]: return '' elif sizes[dest] == sizes[src]: return 'mov %s, %s' % (dest, src) elif sizes[dest] == 64 and sizes[src] == 32: return 'mov %s, %s' % (smaller[dest][0], src) elif sizes[dest] > sizes[src]: return 'movzx %s, %s' % (dest, src) else: for r in bigger[dest]: if sizes[r] == sizes[src]: return 'mov %s, %s' % (r, src) bug('Register %s could not be moved into %s' % (src, dest)) bug('%s is neither a register nor an immediate' % src)