lib/pwnlib/shellcraft/generators/x86/common/setregs.rb
# encoding: ASCII-8BIT
# frozen_string_literal: true
require 'pwnlib/shellcraft/generators/x86/common/common'
module Pwnlib
module Shellcraft
module Generators
module X86
module Common
# Set registers to given values. See example for clearly usage.
#
# @param [Hash{Symbol => String, Symbol, Numeric}] reg_context
# The values of each registers to be set, see examples.
# @param [Boolean] stack_allowed
# If we can use stack for setting values.
# With +stack_allowed+ equals +true+, shellcode would be shorter.
#
# @example
# context.arch = 'i386'
# puts shellcraft.setregs({ eax: 'ebx', ebx: 'ecx', ecx: 0x123 })
# # mov eax, ebx
# # mov ebx, ecx
# # xor ecx, ecx
# # mov cx, 0x123
# @example
# 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
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
end
end
end
end
end