Module: Pwnlib::Shellcraft::Generators::I386::Common
- Extended by:
- Helper
- Defined in:
- lib/pwnlib/shellcraft/generators/i386/common/common.rb,
lib/pwnlib/shellcraft/generators/i386/common/mov.rb,
lib/pwnlib/shellcraft/generators/i386/common/nop.rb,
lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb,
lib/pwnlib/shellcraft/generators/i386/common/infloop.rb,
lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb,
lib/pwnlib/shellcraft/generators/i386/common/setregs.rb,
lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb
Overview
For non os-related methods.
Instance Method Summary collapse
- #infloop ⇒ Object
-
#memcpy(dst, src, n) ⇒ Object
Like
memcpy
in glibc. -
#mov(dst, src, stack_allowed: true) ⇒ Object
Move
src
intodst
without newlines and null bytes. -
#nop ⇒ Object
A no-op instruction.
-
#pushstr(str, append_null: true) ⇒ Object
Push a string to stack.
- #pushstr_array(reg, array) ⇒ Object
- #setregs(reg_context, stack_allowed: true) ⇒ Object
Methods included from Helper
Instance Method Details
#infloop ⇒ Object
15 16 17 18 19 |
# File 'lib/pwnlib/shellcraft/generators/i386/common/infloop.rb', line 15 def infloop(*args) context.local(arch: :i386) do cat X86::Common.infloop(*args) end end |
#memcpy(dst, src, n) ⇒ Object
Like memcpy
in glibc.
Copy n
bytes from src
to dst
.
24 25 26 27 28 29 |
# File 'lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb', line 24 def memcpy(dst, src, n) cat "/* memcpy(#{pretty(dst)}, #{pretty(src)}, #{pretty(n)}) */" cat 'cld' cat Common.setregs({ edi: dst, esi: src, ecx: n }) cat 'rep movsb' end |
#mov(dst, src, stack_allowed: true) ⇒ Object
Move src
into dst
without newlines and null bytes.
See Amd64::Common#mov for parameters’ details.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/pwnlib/shellcraft/generators/i386/common/mov.rb', line 14 def mov(dst, src, stack_allowed: true) raise ArgumentError, "#{dst} is not a register" unless register?(dst) dst = get_register(dst) raise ArgumentError, "cannot use #{dst} on i386" if dst.size > 32 || dst.is64bit if register?(src) src = get_register(src) raise ArgumentError, "cannot use #{src} on i386" if src.size > 32 || src.is64bit if dst.size < src.size && !dst.bigger.include?(src.name) raise ArgumentError, "cannot mov #{dst}, #{src}: dst is smaller than src" end else context.local(arch: 'i386') { src = evaluate(src) } raise ArgumentError, format('cannot mov %s, %d: dst is smaller than src', dst, src) unless dst.fits(src) # Calculate the packed version srcp = pack(src & ((1 << dst.size) - 1), bits: dst.size) # Calculate the unsigned and signed versions srcu = unpack(srcp, bits: dst.size, signed: false) srcs = unpack(srcp, bits: dst.size, signed: true) srcp_neg = p32(-src) srcp_not = p32(src ^ 0xffffffff) end if register?(src) if src == dst || dst.bigger.include?(src.name) cat "/* moving #{src} into #{dst}, but this is a no-op */" elsif dst.size > src.size cat "movzx #{dst}, #{src}" else cat "mov #{dst}, #{src}" end elsif src.is_a?(Numeric) # Constant or immi xor = ->(reg) { "xor #{reg.xor}, #{reg.xor}" } if src.zero? # special case for zeroes cat "xor #{dst}, #{dst} /* #{src} */" elsif stack_allowed && dst.size == 32 && src == 10 cat "push 9 /* mov #{dst}, '\\n' */" cat "pop #{dst}" cat "inc #{dst}" elsif stack_allowed && dst.size == 32 && (-2**7 <= srcs && srcs < 2**7) && okay(srcp[0]) cat "push #{pretty(src)}" cat "pop #{dst}" elsif okay(srcp) # Easy case. This implies that the register size and value are the same. cat "mov #{dst}, #{pretty(src)}" elsif srcu < 2**8 && okay(srcp[0]) && dst.sizes.include?(8) # Move 8-bit value into reg. cat xor[dst] cat "mov #{dst.sizes[8]}, #{pretty(src)}" elsif srcu == srcu & 0xff00 && okay(srcp[1]) && dst.ff00 # Target value is a 16-bit value with no data in the low 8 bits, we can use the 'AH' style register. cat xor[dst] cat "mov #{dst.ff00}, #{pretty(src)} >> 8" elsif srcu < 2**16 && okay(srcp[0, 2]) # Target value is a 16-bit value, use a 16-bit mov. cat xor[dst] cat "mov #{dst.sizes[16]}, #{pretty(src)}" elsif okay(srcp_neg) cat "mov #{dst}, -#{pretty(src)}" cat "neg #{dst}" elsif okay(srcp_not) cat "mov #{dst}, (-1) ^ #{pretty(src)}" cat "not #{dst}" else # All else has failed. Use some XOR magic to move things around. a, b = xor_pair(srcp, avoid: "\x00\n") a = hex(unpack(a, bits: dst.size)) b = hex(unpack(b, bits: dst.size)) cat "mov #{dst}, #{a}" cat "xor #{dst}, #{b} /* #{hex(src)} == #{a} ^ #{b} */" end end end |
#nop ⇒ Object
A no-op instruction.
11 12 13 |
# File 'lib/pwnlib/shellcraft/generators/i386/common/nop.rb', line 11 def nop cat 'nop' end |
#pushstr(str, append_null: true) ⇒ Object
Push a string to stack.
See Amd64::Common#pushstr for parameters’ details.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb', line 14 def pushstr(str, append_null: true) # This will not affect callee's +str+. str += "\x00" if append_null && !str.end_with?("\x00") return if str.empty? padding = str[-1].ord >= 128 ? "\xff" : "\x00" cat "/* push #{str.inspect} */" group(4, str, underfull_action: :fill, fill_value: padding).reverse_each do |word| sign = u32(word, endian: 'little', signed: true) if [0, 0xa].include?(sign) # simple forbidden byte case cat "push #{pretty(sign + 1)}" cat 'dec byte ptr [esp]' elsif sign >= -128 && sign <= 127 cat "push #{pretty(sign)}" elsif okay(word) cat "push #{pretty(sign)}" else a = u32(xor_pair(word).first, endian: 'little', signed: false) cat "push #{pretty(a)}" cat "xor dword ptr [esp], #{pretty(a ^ sign)} /* #{pretty(a)} ^ #{pretty(sign)} */" end end end |
#pushstr_array(reg, array) ⇒ Object
15 16 17 18 19 |
# File 'lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb', line 15 def pushstr_array(*args) context.local(arch: :i386) do cat X86::Common.pushstr_array(*args) end end |