class Rex::ElfScan::Scanner::JmpRegScanner

Public Instance Methods

_build_byte_list(base, regnums) click to toggle source

build a list for regex of the possible bytes, based on a base byte and a list of register numbers..

# File lib/rex/elfscan/scanner.rb, line 84
def _build_byte_list(base, regnums)
  regnums.collect { |regnum| Regexp.escape((base | regnum).chr) }.join('')
end
_parse_ret(data) click to toggle source
# File lib/rex/elfscan/scanner.rb, line 99
def _parse_ret(data)
  if data.length == 1
    return "ret"
  else
    return "retn 0x%04x" % data[1, 2].unpack('v')[0]
  end
end
_ret_size(offset) click to toggle source
# File lib/rex/elfscan/scanner.rb, line 88
def _ret_size(offset)
  case elf.read(offset, 1)
    when "\xc3"
      return 1
    when "\xc2"
      return 3
  end

  raise "Cannot read at offset: #{offset}"
end
config(param) click to toggle source
# File lib/rex/elfscan/scanner.rb, line 63
def config(param)
  regnums = param['args']

  # build a list of the call bytes
  calls  = _build_byte_list(0xd0, regnums - [4]) # note call esp's don't work..
  jmps   = _build_byte_list(0xe0, regnums)
  pushs1 = _build_byte_list(0x50, regnums)
  pushs2 = _build_byte_list(0xf0, regnums)

  regexstr = '('
  if !calls.empty?
    regexstr += "\xff[#{calls}]|"
  end

  regexstr += "\xff[#{jmps}]|([#{pushs1}]|\xff[#{pushs2}])(\xc3|\xc2..))"

  self.regex = Regexp.new(regexstr, nil, 'n')
end
scan_segment(program_header, param={}) click to toggle source
# File lib/rex/elfscan/scanner.rb, line 108
def scan_segment(program_header, param={})
  offset = program_header.p_offset

  hits = []

  while (offset = elf.index(regex, offset)) != nil

    rva     = elf.offset_to_rva(offset)
    message = ''

    parse_ret = false

    byte1 = elf.read(offset, 1).unpack('C')[0]

    if byte1 == 0xff
      byte2   = elf.read(offset+1, 1).unpack('C')[0]
      regname = Rex::Arch::X86.reg_name32(byte2 & 0x7)

      case byte2 & 0xf8
      when 0xd0
        message = "call #{regname}"
        offset += 2
      when 0xe0
        message = "jmp #{regname}"
        offset += 2
      when 0xf0
        retsize = _ret_size(offset+2)
        message = "push #{regname}; " + _parse_ret(elf.read(offset+2, retsize))
        offset += 2 + retsize
      else
        raise "Unexpected value at #{offset}"
      end
    else
      regname = Rex::Arch::X86.reg_name32(byte1 & 0x7)
      retsize = _ret_size(offset+1)
      message = "push #{regname}; " + _parse_ret(elf.read(offset+1, retsize))
      offset += 1 + retsize
    end

    hits << [ rva, message ]
  end

  return hits
end