Module: Pwnlib::Shellcraft::Generators::X86::Common

Extended by:
Helper
Defined in:
lib/pwnlib/shellcraft/generators/x86/common/common.rb,
lib/pwnlib/shellcraft/generators/x86/common/mov.rb,
lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb,
lib/pwnlib/shellcraft/generators/x86/common/infloop.rb,
lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb,
lib/pwnlib/shellcraft/generators/x86/common/setregs.rb,
lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb

Overview

For non os-related methods.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helper

extended

Class Method Details

.define_arch_dependent_method(method) ⇒ Object



12
13
14
15
16
17
18
19
20
21
# File 'lib/pwnlib/shellcraft/generators/x86/common/common.rb', line 12

def define_arch_dependent_method(method)
  define_method(method) do |*args, **kwargs|
    case context.arch
    when 'amd64'
      cat Amd64::Common.public_send(method, *args, **kwargs)
    when 'i386'
      cat I386::Common.public_send(method, *args, **kwargs)
    end
  end
end

Instance Method Details

#infloopObject

Infinite loop.

Examples:

shellcraft.infloop
#=> "infloop_1:\n  jmp infloop_1"


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

def infloop
  label = get_label('infloop')
  cat "#{label}:"
  cat "jmp #{label}"
end

#pushstr_array(reg, array) ⇒ Object

Push an array of pointers onto the stack.

Examples:

context.arch = 'i386'
puts shellcraft.pushstr_array('eax', ['push', 'een'])
# /* push argument array ["push\x00", "een\x00"] */
# /* push "push\x00een\x00" */
# push 1
# dec byte ptr [esp]
# push 0x1010101
# xor dword ptr [esp], 0x1010101 ^ 0x6e656500
# push 0x68737570
# xor eax, eax /* 0 */
# push eax /* null terminate */
# push 9
# pop eax
# add eax, esp
# push eax /* "een\x00" */
# push 8
# pop eax
# add eax, esp
# push eax /* "push\x00" */
# mov eax, esp
#=> nil
context.arch = 'amd64'
puts shellcraft.pushstr_array('rax', ['meow', 'oh'])
#   /* push argument array ["meow\x00", "oh\x00"] */
#   /* push "meow\x00oh\x00" */
#   mov rax, 0x101010101010101
#   push rax
#   mov rax, 0x101010101010101 ^ 0x686f00776f656d
#   xor [rsp], rax
#   xor eax, eax /* 0 */
#   push rax /* null terminate */
#   push 0xd
#   pop rax
#   add rax, rsp
#   push rax /* "oh\x00" */
#   push 0x10
#   pop rax
#   add rax, rsp
#   push rax /* "meow\x00" */
#   mov rax, rsp
#=> nil

Parameters:

  • reg (String)

    Destination register to hold the result pointer.

  • array (Array<String>)

    List of arguments to push. NULL termination is normalized so that each argument ends with exactly one NULL byte.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb', line 64

def pushstr_array(reg, array)
  abi = ::Pwnlib::ABI::ABI.default
  array = array.map { |a| "#{a.gsub(/\x00+\Z/, '')}\x00" }
  array_str = array.join
  word_size = abi.arg_alignment
  offset = array_str.size + word_size
  cat "/* push argument array #{array.inspect} */"
  cat Common.pushstr(array_str)
  cat Common.mov(reg, 0)
  cat "push #{reg} /* null terminate */"
  array.reverse.each_with_index do |arg, i|
    cat Common.mov(reg, offset + word_size * i - arg.size)
    cat "add #{reg}, #{abi.stack_pointer}"
    cat "push #{reg} /* #{arg.inspect} */"
    offset -= arg.size
  end
  cat Common.mov(reg, abi.stack_pointer)
end

#setregs(reg_context, stack_allowed: true) ⇒ Object

Set registers to given values. See example for clearly usage.

Examples:

context.arch = 'i386'
puts shellcraft.setregs({ eax: 'ebx', ebx: 'ecx', ecx: 0x123 })
#  mov eax, ebx
#  mov ebx, ecx
#  xor ecx, ecx
#  mov cx, 0x123
context.arch = 'amd64'
puts shellcraft.setregs({ rdi: 'rsi', rsi: 'rdi' })
#  xchg rdi, rsi

puts shellcraft.setregs({ rax: -1 })
#  push -1
#  pop rax

puts shellcraft.setregs({ rax: -1 }, stack_allowed: false)
#  mov rax, -1

Parameters:

  • reg_context (Hash{Symbol => String, Symbol, Numeric})

    The values of each registers to be set, see examples.

  • stack_allowed (Boolean) (defaults to: true)

    If we can use stack for setting values. With stack_allowed equals true, shellcode would be shorter.



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
# File 'lib/pwnlib/shellcraft/generators/x86/common/setregs.rb', line 37

def setregs(reg_context, stack_allowed: true)
  abi = ::Pwnlib::ABI::ABI.default
  reg_context = reg_context.reject { |_, v| v.nil? }
  # convert all registers to string
  reg_context = reg_context.map do |k, v|
    v = register?(v) ? v.to_s : v
    [k.to_s, v]
  end
  reg_context = reg_context.to_h
  ax_str, dx_str = abi.cdq_pair
  eax = reg_context[ax_str]
  edx = reg_context[dx_str]
  cdq = false
  ev = lambda do |reg|
    return reg unless reg.is_a?(String)

    evaluate(reg)
  end
  eax = ev[eax]
  edx = ev[edx]

  if eax.is_a?(Numeric) && edx.is_a?(Numeric) && edx.zero? && (eax & (1 << 31)).zero?
    # @diff
    #   The condition is wrong in python-pwntools, and here we don't care the case of edx==0xffffffff.
    cdq = true
    reg_context.delete(dx_str)
  end
  sorted_regs = regsort(reg_context, registers)
  if sorted_regs.empty?
    cat '/* setregs noop */'
  else
    sorted_regs.each do |how, src, dst|
      if how == 'xchg'
        cat "xchg #{src}, #{dst}"
      else
        # Bug in python-pwntools, which is missing `stack_allowed`.
        # Proof of bug: pwnlib.shellcraft.setregs({'rax': 1}, stack_allowed=False)
        cat Common.mov(src, dst, stack_allowed: stack_allowed)
      end
    end
  end
  cat "cdq /* #{dx_str}=0 */" if cdq
end