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

Methods included from Helper

extended

Instance Method Details

#infloopObject



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.

Parameters:

  • dst (String, Symbol, Integer)

    Destination.

  • src (String, Symbol, Integer)

    Source to be copied.

  • n (Integer)

    The number of bytes to be copied.

See Also:



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.

Raises:

  • (ArgumentError)


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

#nopObject

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

#setregs(reg_context, stack_allowed: true) ⇒ Object



15
16
17
18
19
# File 'lib/pwnlib/shellcraft/generators/i386/common/setregs.rb', line 15

def setregs(*args, **kwargs)
  context.local(arch: :i386) do
    cat X86::Common.setregs(*args, **kwargs)
  end
end