class OneGadget::Emulators::X86
Super class for amd64 and i386 processor.
Public Class Methods
new(registers, sp, pc)
click to toggle source
Constructor for a x86 processor.
Calls superclass method
OneGadget::Emulators::Processor::new
# File lib/one_gadget/emulators/x86.rb, line 13 def initialize(registers, sp, pc) super(registers, sp) @pc = pc end
Public Instance Methods
instructions()
click to toggle source
Supported instruction set. @return [Array<Instruction>] The supported instructions.
# File lib/one_gadget/emulators/x86.rb, line 35 def instructions [ Instruction.new('add', 2), Instruction.new('call', 1), Instruction.new('jmp', 1), Instruction.new('lea', 2), Instruction.new('mov', 2), Instruction.new('nop', -1), Instruction.new('push', 1), Instruction.new('sub', 2), Instruction.new('xor', 2), Instruction.new('movq', 2), Instruction.new('movaps', 2), Instruction.new('movhps', 2), Instruction.new('punpcklqdq', 2) ] end
process!(cmd)
click to toggle source
Process one command. Will raise exceptions when encounter unhandled instruction. @param [String] cmd
One line from result of objdump.
@return [Boolean]
If successfully processed.
# File lib/one_gadget/emulators/x86.rb, line 24 def process!(cmd) inst, args = parse(cmd) # return registers[pc] = args[0] if inst.inst == 'call' return true if inst.inst == 'jmp' # believe the fetcher has handled jmp. sym = "inst_#{inst.inst}".to_sym __send__(sym, *args) != :fail end
Private Instance Methods
add_writable(dst)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 201 def add_writable(dst) lmda = arg_to_lambda(dst).ref! # pc-relative addresses should be writable return if lmda.obj == pc @constraints << [:writable, lmda] end
check_xmm_sp(dst, src) { || ... }
click to toggle source
check whether (dst, src) is in form (xmm*, [sp+*])
# File lib/one_gadget/emulators/x86.rb, line 112 def check_xmm_sp(dst, src) return yield unless xmm_reg?(dst) && src.include?(sp) dst_lm = arg_to_lambda(dst) src_lm = arg_to_lambda(src) return yield if src_lm.deref_count != 1 src_lm.ref! [dst_lm, src_lm] end
inst_add(dst, src)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 163 def inst_add(dst, src) check_register!(dst) src = arg_to_lambda(src) registers[dst] += src end
inst_call(addr)
click to toggle source
Handle some valid calls. For example, sigprocmask
will always be a valid call because it just invokes syscall.
# File lib/one_gadget/emulators/x86.rb, line 183 def inst_call(addr) # This is the last call return registers[pc] = addr if %w[execve execl posix_spawn].any? { |n| addr.include?(n) } # TODO: handle some registers would be fucked after call checker = { 'sigprocmask' => {}, '__close' => {}, 'unsetenv' => { 0 => :global_var? }, '__sigaction' => { 1 => :global_var?, 2 => :zero? } } func = checker.keys.find { |n| addr.include?(n) } return if func && checker[func].all? { |idx, sym| check_argument(idx, sym) } # unhandled case or checker's condition fails :fail end
inst_lea(dst, src)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 138 def inst_lea(dst, src) check_register!(dst) registers[dst] = arg_to_lambda(src).ref! end
inst_mov(dst, src)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 55 def inst_mov(dst, src) src = arg_to_lambda(src) if register?(dst) registers[dst] = src else # Just ignore strange case... # TODO(david942j): #120 return add_writable(dst) unless dst.include?(sp) dst = arg_to_lambda(dst) return if dst.deref_count != 1 # should not happen dst.ref! stack[dst.evaluate(eval_dict)] = src end end
inst_movaps(dst, src)
click to toggle source
This instruction moves 128bits.
# File lib/one_gadget/emulators/x86.rb, line 73 def inst_movaps(dst, src) # XXX: here we only support `movaps [sp+*], xmm*` src, dst = check_xmm_sp(src, dst) { raise_unsupported('movaps', dst, src) } off = dst.evaluate(eval_dict) @constraints << [:raw, "#{sp} & 0xf == #{0x10 - off & 0xf}"] (128 / self.class.bits).times do |i| stack[off + i * size_t] = src[i] end end
inst_movhps(dst, src)
click to toggle source
Move src to dst
# File lib/one_gadget/emulators/x86.rb, line 102 def inst_movhps(dst, src) # XXX: here we only support `movhps xmm*, [sp+*]` dst, src = check_xmm_sp(dst, src) { raise_unsupported('movhps', dst, src) } off = src.evaluate(eval_dict) (64 / self.class.bits).times do |i| dst[i + 64 / self.class.bits] = stack[off + i * size_t] end end
inst_movq(dst, src)
click to toggle source
Move src to dst Supported forms:
movq xmm*, [sp+*] movq xmm*, reg64
# File lib/one_gadget/emulators/x86.rb, line 87 def inst_movq(dst, src) if self.class.bits == 64 && xmm_reg?(dst) && src.start_with?('r') && register?(src) dst = arg_to_lambda(dst) src = arg_to_lambda(src) dst[0] = src return end dst, src = check_xmm_sp(dst, src) { raise_unsupported('movq', dst, src) } off = src.evaluate(eval_dict) (64 / self.class.bits).times do |i| dst[i] = stack[off + i * size_t] end end
inst_nop(*)
click to toggle source
yap, nop
# File lib/one_gadget/emulators/x86.rb, line 178 def inst_nop(*); end
inst_punpcklqdq(dst, src)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 128 def inst_punpcklqdq(dst, src) raise_unsupported('punpcklqdq', dst, src) unless xmm_reg?(dst) && xmm_reg?(src) dst = arg_to_lambda(dst) src = arg_to_lambda(src) (64 / self.class.bits).times do |i| dst[i + 64 / self.class.bits] = src[i] end end
inst_push(val)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 144 def inst_push(val) val = arg_to_lambda(val) registers[sp] -= size_t cur_top = registers[sp].evaluate(eval_dict) raise Error::InstructionArgumentError, "Corrupted stack pointer: #{cur_top}" unless cur_top.is_a?(Integer) stack[cur_top] = val end
inst_sub(dst, src)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 170 def inst_sub(dst, src) src = arg_to_lambda(src) raise Error::UnsupportedInstructionArgumentError, "Unhandled -= of type #{src.class}" unless src.is_a?(Integer) registers[dst] -= src end
inst_xor(dst, src)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 153 def inst_xor(dst, src) check_register!(dst) # only supports dst == src raise Error::UnsupportedInstructionArgumentError, 'xor operator only supports dst = src' unless dst == src dst[0] = 'r' if self.class.bits == 64 && dst.start_with?('e') registers[dst] = 0 end
to_lambda(reg)
click to toggle source
Calls superclass method
OneGadget::Emulators::Processor#to_lambda
# File lib/one_gadget/emulators/x86.rb, line 209 def to_lambda(reg) return super unless reg =~ /^xmm\d+$/ Array.new(128 / self.class.bits) do |i| cast = "(u#{self.class.bits})" OneGadget::Emulators::Lambda.new(i.zero? ? "#{cast}#{reg}" : "#{cast}(#{reg} >> #{self.class.bits * i})") end end
xmm_reg?(reg)
click to toggle source
# File lib/one_gadget/emulators/x86.rb, line 123 def xmm_reg?(reg) reg.start_with?('xmm') && register?(reg) end