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


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


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