Namespace

Class/Module Index [+]

Quicksearch

Rex::Arch::X86::UnitTest::Klass

everything here is mostly stole from vlad's perl x86 stuff

Constants

EAX

Register number constants

EBP
EBX
ECX
EDI
EDX
ESI
ESP

Public Class Methods

add(val, reg, badchars = '', adjust = false, bits = 0) click to toggle source

This method generates the opcodes equivalent to subtracting with a negative value from a given register.

# File lib/rex/arch/x86.rb, line 329
def self.add(val, reg, badchars = '', adjust = false, bits = 0)
        sub(val, reg, badchars, true, adjust, bits)
end
adjust_reg(reg, adjustment) click to toggle source

This method adjusts the value of the ESP register by a given amount.

# File lib/rex/arch/x86.rb, line 357
def self.adjust_reg(reg, adjustment)
        if (adjustment > 0)
                sub(adjustment, reg, '', false, false, 32)
        else
                add(adjustment, reg, '', true, 32)
        end
end
call(addr) click to toggle source

This method returns the opcodes that compose a relative call instruction to the address specified.

# File lib/rex/arch/x86.rb, line 96
def self.call(addr)
        "\xe8" + pack_dword(rel_number(addr, -5))
end
clear(reg, badchars = '') click to toggle source

This method generates an instruction that clears the supplied register in a manner that attempts to avoid bad characters, if supplied.

# File lib/rex/arch/x86.rb, line 189
def self.clear(reg, badchars = '')
        _check_reg(reg)
        return set(reg, 0, badchars)
end
copy_to_stack(len) click to toggle source

Generates a buffer that will copy memory immediately following the stub that is generated to be copied to the stack

# File lib/rex/arch/x86.rb, line 66
def self.copy_to_stack(len)
        # four byte align
        len = (len + 3) & ~0x3

        stub =
                "\xeb\x0f"+                # jmp _end
                push_dword(len)+           # push n
                "\x59"+                    # pop ecx
                "\x5e"+                    # pop esi
                "\x29\xcc"+                # sub esp, ecx
                "\x89\xe7"+                # mov edi, esp
                "\xf3\xa4"+                # rep movsb
                "\xff\xe4"+                # jmp esp
                "\xe8\xec\xff\xff\xff"     # call _start

        stub
end
dword_adjust(dword, amount=0) click to toggle source

This method adds/subs a packed long integer

# File lib/rex/arch/x86.rb, line 42
def self.dword_adjust(dword, amount=0)
        pack_dword(dword.unpack('V')[0] + amount)
end
encode_effective(shift, dst) click to toggle source

This method generates the encoded effective value for a register.

# File lib/rex/arch/x86.rb, line 139
def self.encode_effective(shift, dst)
        return (0xc0 | (shift << 3) | dst)
end
encode_modrm(dst, src) click to toggle source

This method generates the mod r/m character for a source and destination register.

# File lib/rex/arch/x86.rb, line 147
def self.encode_modrm(dst, src)
        _check_reg(dst, src)
        return (0xc0 | src | dst << 3).chr
end
fpu_instructions() click to toggle source

This method returns an array of 'safe' FPU instructions

# File lib/rex/arch/x86.rb, line 385
def self.fpu_instructions
        fpus = []

        0xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }
        0xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }
        0xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }
        0xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }
        0xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }

        fpus << "\xd9\xd0"
        fpus << "\xd9\xe1"
        fpus << "\xd9\xf6"
        fpus << "\xd9\xf7"
        fpus << "\xd9\xe5"

        # This FPU instruction seems to fail consistently on Linux
        #fpus << "\xdb\xe1"

        fpus
end
geteip_fpu(badchars) click to toggle source

This method returns an array containing a geteip stub, a register, and an offset This method will return nil if the getip generation fails

# File lib/rex/arch/x86.rb, line 410
def self.geteip_fpu(badchars)

        #
        # Default badchars to an empty string
        #
        badchars ||= ''

        #
        # Bail out early if D9 is restricted
        #
        return nil if badchars.index("\xd9")

        #
        # Create a list of FPU instructions
        #
        fpus = *self.fpu_instructions
        bads = []
        badchars.each_byte  do |c|
                fpus.each do |str|
                        bads << str if (str.index(c.chr))
                end
        end
        bads.each { |str| fpus.delete(str) }
        return nil if fpus.length == 0

        #
        # Create a list of registers to use for fnstenv
        #
        dsts = []
        0.upto(7) do |c|
                dsts << c if (not badchars.index( (0x70+c).chr ))
        end

        if (dsts.include?(ESP) and badchars.index("\x24"))
                dsts.delete(ESP)
        end

        return nil if dsts.length == 0

        #
        # Grab a random FPU instruction
        #
        fpu = fpus[ rand(fpus.length) ]

        #
        # Grab a random register from dst
        #
        while(dsts.length > 0)
                buf = ''
                dst = dsts[ rand(dsts.length) ]
                dsts.delete(dst)

                # If the register is not ESP, copy ESP
                if (dst != ESP)
                        next if badchars.index( (0x70 + dst).chr )

                        if !(badchars.index("\x89") or badchars.index( (0xE0+dst).chr ))
                                buf << "\x89" + (0xE0 + dst).chr
                        else
                                next if badchars.index("\x54")
                                next if badchars.index( (0x58+dst).chr )
                                buf << "\x54" + (0x58 + dst).chr
                        end
                end

                pad = 0
                while (pad < (128-12) and badchars.index( (256-12-pad).chr))
                        pad += 4
                end

                # Give up on finding a value to use here
                if (pad == (128-12))
                        return nil
                end

                out = buf + fpu + "\xd9" + (0x70 + dst).chr
                out << "\x24" if dst == ESP
                out << (256-12-pad).chr

                regs = [*(0..7)]
                while (regs.length > 0)
                        reg = regs[ rand(regs.length) ]
                        regs.delete(reg)
                        next if reg == ESP
                        next if badchars.index( (0x58 + reg).chr )

                        # Pop the value back out
                        0.upto(pad / 4) { |c| out << (0x58 + reg).chr }

                        # Fix the value to point to self
                        gap = out.length - buf.length

                        return [out, REG_NAMES32[reg].upcase, gap]
                end
        end

        return nil
end
jmp(addr) click to toggle source

This method returns the opcodes that compose a jump instruction to the supplied relative offset.

# File lib/rex/arch/x86.rb, line 35
def self.jmp(addr)
        "\xe9" + pack_dword(rel_number(addr))
end
jmp_reg(str) click to toggle source

Jump tp a specific register

# File lib/rex/arch/x86.rb, line 27
def self.jmp_reg(str)
        reg = reg_number(str)
        _check_reg(reg)
        "\xFF" + [224 + reg].pack('C')
end
jmp_short(addr) click to toggle source

This method returns the opcodes that compose a short jump instruction to the supplied relative offset.

# File lib/rex/arch/x86.rb, line 88
def self.jmp_short(addr)
        "\xeb" + pack_lsb(rel_number(addr, -2))
end
mov_byte(reg, val) click to toggle source

This method generates the opcodes that set the low byte of a given register to the supplied value.

# File lib/rex/arch/x86.rb, line 198
def self.mov_byte(reg, val)
        _check_reg(reg)
        # chr will raise RangeError if val not between 0 .. 255
        return (0xb0 | reg).chr + val.chr
end
mov_dword(reg, val) click to toggle source

This method generates the opcodes that set the a register to the supplied value.

# File lib/rex/arch/x86.rb, line 220
def self.mov_dword(reg, val)
        _check_reg(reg)
        return (0xb8 | reg).chr + pack_dword(val)
end
mov_word(reg, val) click to toggle source

This method generates the opcodes that set the low word of a given register to the supplied value.

# File lib/rex/arch/x86.rb, line 208
def self.mov_word(reg, val)
        _check_reg(reg)
        if val < 0 || val > 0xffff
                raise RangeError, "Can only take unsigned word values!", caller()
        end
        return "\x66" + (0xb8 | reg).chr + pack_word(val)
end
pack_dword(num) click to toggle source

This method wrappers packing an integer as a little-endian buffer.

# File lib/rex/arch/x86.rb, line 343
def self.pack_dword(num)
        [num].pack('V')
end
pack_lsb(num) click to toggle source

This method returns the least significant byte of a packed dword.

# File lib/rex/arch/x86.rb, line 350
def self.pack_lsb(num)
        pack_dword(num)[0,1]
end
pack_word(num) click to toggle source

This method wrappers packing a short integer as a little-endian buffer.

# File lib/rex/arch/x86.rb, line 336
def self.pack_word(num)
        [num].pack('v')
end
pop_dword(dst) click to toggle source

This method generates a pop dword instruction into a register.

# File lib/rex/arch/x86.rb, line 180
def self.pop_dword(dst)
        _check_reg(dst)
        return (0x58 | dst).chr
end
push_byte(byte) click to toggle source

This method generates a push byte instruction.

# File lib/rex/arch/x86.rb, line 155
def self.push_byte(byte)
        # push byte will sign extend...
        if byte < 128 && byte >= -128
                return "\x6a" + (byte & 0xff).chr
        end
        raise ::ArgumentError, "Can only take signed byte values!", caller()
end
push_dword(val) click to toggle source

This method generates a push dword instruction.

# File lib/rex/arch/x86.rb, line 173
def self.push_dword(val)
        return "\x68" + pack_dword(val)
end
push_word(val) click to toggle source

This method generates a push word instruction.

# File lib/rex/arch/x86.rb, line 166
def self.push_word(val)
        return "\x66\x68" + pack_word(val)
end
reg_name32(num) click to toggle source

This method returns the register named associated with a given register number.

# File lib/rex/arch/x86.rb, line 131
def self.reg_name32(num)
        _check_reg(num)
        return REG_NAMES32[num].dup
end
reg_number(str) click to toggle source

This method returns the number associated with a named register.

# File lib/rex/arch/x86.rb, line 123
def self.reg_number(str)
        return self.const_get(str.upcase)
end
rel_number(num, delta = 0) click to toggle source

This method returns a number offset to the supplied string.

# File lib/rex/arch/x86.rb, line 103
def self.rel_number(num, delta = 0)
        s = num.to_s

        case s[0, 2]
                when '$+'
                        num = s[2 .. -1].to_i
                when '$-'
                        num = -1 * s[2 .. -1].to_i
                when '0x'
                        num = s.hex
                else
                        delta = 0
        end

        return num + delta
end
searcher(tag) click to toggle source

This method returns the opcodes that compose a tag-based search routine

# File lib/rex/arch/x86.rb, line 49
def self.searcher(tag)
        "\xbe" + dword_adjust(tag,-1)+  # mov esi, Tag - 1
        "\x46" +                        # inc esi
        "\x47" +                        # inc edi (end_search:)
        "\x39\x37" +                    # cmp [edi],esi
        "\x75\xfb" +                    # jnz 0xa (end_search)
        "\x46" +                        # inc esi
        "\x4f" +                        # dec edi (start_search:)
        "\x39\x77\xfc" +                # cmp [edi-0x4],esi
        "\x75\xfa" +                    # jnz 0x10 (start_search)
        jmp_reg('edi')                  # jmp edi
end
set(dst, val, badchars = '') click to toggle source

This method is a general way of setting a register to a value. Depending on the value supplied, different sets of instructions may be used.

TODO: Make this moderatly intelligent so it chain instructions by itself

(ie. xor eax, eax + mov al, 4 + xchg ah, al)
# File lib/rex/arch/x86.rb, line 231
        def self.set(dst, val, badchars = '')
                _check_reg(dst)

                # If the value is 0 try xor/sub dst, dst (2 bytes)
                if(val == 0)
                        opcodes = Rex::Text.remove_badchars("\x29\x2b\x31\x33", badchars)
                        if !opcodes.empty?
                                return opcodes[rand(opcodes.length)].chr + encode_modrm(dst, dst)
                        end
# TODO: SHL/SHR
# TODO: AND
                end

                # try push BYTE val; pop dst (3 bytes)
                begin
                        return _check_badchars(push_byte(val) + pop_dword(dst), badchars)
                rescue ::ArgumentError, ::RuntimeError, ::RangeError
                end

                # try clear dst, mov BYTE dst (4 bytes)
                begin
                        # break if val == 0
                        return _check_badchars(clear(dst, badchars) + mov_byte(dst, val), badchars)
                rescue ::ArgumentError, ::RuntimeError, ::RangeError
                end

                # try mov DWORD dst (5 bytes)
                begin
                        return _check_badchars(mov_dword(dst, val), badchars)
                rescue ::ArgumentError, ::RuntimeError, ::RangeError
                end

                # try push DWORD, pop dst (6 bytes)
                begin
                        return _check_badchars(push_dword(val) + pop_dword(dst), badchars)
                rescue ::ArgumentError, ::RuntimeError, ::RangeError
                end

                # try clear dst, mov WORD dst (6 bytes)
                begin
                        # break if val == 0
                        return _check_badchars(clear(dst, badchars) + mov_word(dst, val), badchars)
                rescue ::ArgumentError, ::RuntimeError, ::RangeError
                end

                raise RuntimeError, "No valid set instruction could be created!", caller()
        end
sub(val, reg, badchars = '', add = false, adjust = false, bits = 0) click to toggle source

Builds a subtraction instruction using the supplied operand and register.

# File lib/rex/arch/x86.rb, line 283
def self.sub(val, reg, badchars = '', add = false, adjust = false, bits = 0)
        opcodes = []
        shift   = (add == true) ? 0 : 5

        if (bits <= 8 and val >= -0x7f and val <= 0x7f)
                opcodes <<
                        ((adjust) ? '' : clear(reg, badchars)) +
                        "\x83" +
                        [ encode_effective(shift, reg) ].pack('C') +
                        [ val.to_i ].pack('C')
        end

        if (bits <= 16 and val >= -0xffff and val <= 0)
                opcodes <<
                        ((adjust) ? '' : clear(reg, badchars)) +
                        "\x66\x81" +
                        [ encode_effective(shift, reg) ].pack('C') +
                        [ val.to_i ].pack('v')
        end

        opcodes <<
                ((adjust) ? '' : clear(reg, badchars)) +
                "\x81" +
                [ encode_effective(shift, reg) ].pack('C') +
                [ val.to_i ].pack('V')

        # Search for a compatible opcode
        opcodes.each { |op|
                begin
                        _check_badchars(op, badchars)
                rescue
                        next
                end

                return op
        }

        if opcodes.empty?
                raise RuntimeError, "Could not find a usable opcode", caller()
        end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.