Parent

Class/Module Index [+]

Quicksearch

Rex::Poly::LogicalBlock

This class represents a logical block which is defined as a concise portion of code that may have one or more functionally equivalent implementations. A logical block should serve a very specific purpose, and any permutations beyond the first should result in exactly the same functionality without any adverse side effects to other blocks.

Like blocks of code, LogicalBlock's can depend on one another in terms of ordering and precedence. By marking blocks as dependent on another, a hierarchy begins to form. This is a block dependency graph.

To add permutations to a LogicalBlock, they can either be passed in as a list of arguments to the constructor following the blocks name or can be added on the fly by calling the add_perm method. To get a random permutation, the rand_perm method can be called.

To mark one block as depending on another, the depends_on method can be called with zero or more LogicalBlock instances as parameters.

Attributes

generated[RW]

Whether or not this block has currently been generated for a given iteration.

offset[RW]

This attributes contains the currently assigned offset of the permutation associated with this block into the polymorphic buffer that is being generated.

Public Class Methods

new(name, *perms) click to toggle source

Initializes the logical block's name along with zero or more specific blocks.

# File lib/rex/poly/block.rb, line 75
def initialize(name, *perms)
        @name  = name

        reset

        add_perm(*perms)
end

Public Instance Methods

add_perm(*perms) click to toggle source

Adds zero or more specific permutations that may be represented either as strings or as Proc's to be called at evaluation time.

# File lib/rex/poly/block.rb, line 150
def add_perm(*perms)
        @perms.concat(perms)
end
clobbers(*registers) click to toggle source

Defines the list of zero or more LogicalRegister's that this block clobbers.

# File lib/rex/poly/block.rb, line 217
def clobbers(*registers)
        @clobbers = registers
end
depends_on(*depends) click to toggle source

Sets the blocks that this block instance depends on.

# File lib/rex/poly/block.rb, line 198
def depends_on(*depends)
        @depends = depends.dup

        # Increment dependent references
        @depends.each { |b| b.ref }
end
deref() click to toggle source

Increments the number of blocks that have completed their dependency pass on this block. This number should never become higher than the @references attribute.

# File lib/rex/poly/block.rb, line 135
def deref
        @used_references += 1
end
each_clobbers(&block) click to toggle source

Enumerates each register instance that is clobbered by this block.

# File lib/rex/poly/block.rb, line 224
def each_clobbers(&block)
        @clobbers.each(&block)
end
generate(save_registers = nil, state = nil, badchars = nil) click to toggle source

Generates the polymorphic buffer that results from this block and any of the blocks that it either directly or indirectly depends on. A list of register numbers to be saved can be passed in as an argument.

This method is not thread safe. To call this method on a single block instance from within multiple threads, be sure to encapsulate the calls inside a locked context.

# File lib/rex/poly/block.rb, line 237
def generate(save_registers = nil, state = nil, badchars = nil)
        # Create a localized state instance if one was not supplied.
        state = Rex::Poly::State.new if (state == nil)
        buf   = nil
        cnt   = 0

        # This is a lame way of doing this.  We just try to generate at most 128
        # times until we don't have badchars.  The reason we have to do it this
        # way is because of the fact that badchars can be introduced through
        # block offsetting and register number selection which can't be readily
        # predicted or detected during the generation phase.  In the future we
        # can make this better, but for now this will have to do.
        begin
                buf = do_generate(save_registers, state, badchars)

                if (buf and
                    (badchars.nil? or Rex::Text.badchar_index(buf, badchars).nil?))
                        break
                end
        end while ((cnt += 1) < 128)

        # If we passed 128 tries, then we can't succeed.
        buf = nil if (cnt >= 128)

        buf
end
last_reference?() click to toggle source

Returns true if there is only one block reference remaining.

# File lib/rex/poly/block.rb, line 142
def last_reference?
        (@references - @used_references <= 0)
end
name() click to toggle source

Returns the block's name.

# File lib/rex/poly/block.rb, line 102
def name
        @name
end
next_blocks(*blocks) click to toggle source

Defines the next blocks, but not in a dependency fashion but rather in a linking of separate block contexts.

# File lib/rex/poly/block.rb, line 209
def next_blocks(*blocks)
        @next_blocks = blocks.dup
end
offset_of(lblock) click to toggle source

Returns the offset of a block. If the active state for this instance is operating in the first phase, then zero is always returned. Otherwise, the correct offset for the supplied block is returned.

# File lib/rex/poly/block.rb, line 269
def offset_of(lblock)
        if (@state.first_phase)
                0
        else
                if (lblock.kind_of?(SymbolicBlock::End))
                        @state.curr_offset
                else
                        lblock.offset
                end
        end
end
once() click to toggle source

Returns true if this block is a 'once' block. That is, this block is dependend upon by multiple blocks but should only be generated once.

# File lib/rex/poly/block.rb, line 119
def once
        @once
end
once=(tf) click to toggle source

Flags whether or not the block should only be generated once. This can be used to mark a blog as being depended upon by multiple blocks, but making it such that it is only generated once.

# File lib/rex/poly/block.rb, line 111
def once=(tf)
        @once = tf
end
rand_perm() click to toggle source

Returns a random permutation that is encapsulated in a Permutation class instance.

# File lib/rex/poly/block.rb, line 158
def rand_perm
        perm = nil

        if (@state.badchars)
                perm = rand_perm_badchars
        else
                perm = Permutation.new(@perms[rand(@perms.length)], self)
        end

        if (perm.nil?)
                raise RuntimeError, "Failed to locate a valid permutation."
        end

        perm
end
rand_perm_badchars() click to toggle source

Returns a random permutation that passes any necessary bad character checks.

# File lib/rex/poly/block.rb, line 178
def rand_perm_badchars
        idx = rand(@perms.length)
        off = 0

        while (off < @perms.length)
                p = @perms[(idx + off) % @perms.length]

                if (p.kind_of?(Proc) or
                    @state.badchars.nil? or
                    Rex::Text.badchar_index(p, @state.badchars).nil?)
                        return Permutation.new(p, self)
                end

                off += 1
        end
end
ref() click to toggle source

Increments the number of blocks that depend on this block.

# File lib/rex/poly/block.rb, line 126
def ref
        @references += 1
end
regnum_of(reg) click to toggle source

Returns the register number associated with the supplied LogicalRegister instance. If the active state for this instance is operating in the first phase, then zero is always returned. Otherwise, the correct register number is returned based on what is currently assigned to the supplied LogicalRegister instance, if anything.

# File lib/rex/poly/block.rb, line 288
def regnum_of(reg)
        (@state.first_phase) ? 0 : reg.regnum
end
reset() click to toggle source

Resets the block back to its starting point.

# File lib/rex/poly/block.rb, line 86
def reset
        @perms           = []
        @depends         = []
        @next_blocks     = []
        @clobbers        = []
        @offset          = nil
        @state           = nil
        @once            = false
        @references      = 0
        @used_references = 0
        @generated       = false
end
size_of(lblock) click to toggle source
# File lib/rex/poly/block.rb, line 292
def size_of(lblock)
        @state.block_list.map { |b, p|
                if b == lblock
                        return p.length
                end
        }
        0
end

Protected Instance Methods

do_generate(save_registers, state, badchars) click to toggle source

Performs the actual polymorphic buffer generation. Called from generate

# File lib/rex/poly/block.rb, line 319
def do_generate(save_registers, state, badchars)
        # Reset the state in case it was passed in.
        state.reset

        # Set the bad character list
        state.badchars = badchars if (badchars)

        # Consume any registers that should be saved.
        save_registers.each { |reg|
                state.consume_regnum(reg)
        } if (save_registers)

        # Build the linear list of blocks that will be processed.  This
        # list is built in a dynamic fashion based on block dependencies.
        # The list that is returned is an Array of which each element is a two
        # member array, the first element being the LogicalBlock instance that
        # the permutation came from and the second being an instance of the
        # Permutation class associated with the selected permutation.
        block_list = generate_block_list(state)

        # Transition into the second phase which enables offset_of and regnum_of
        # calls to return real values.
        state.first_phase = false

        # Now that every block has been assigned an offset, generate the
        # buffer block by block, assigning registers as necessary.
        block_list.each { |b|

                # Generate the next permutation and append it to the buffer.
                begin
                        state.buffer += b[1].to_s
                # If an invalid register exception is raised, try to consume a random
                # register from the register's associated architecture register
                # number set.
                rescue InvalidRegisterError => e
                        e.reg.regnum = state.consume_regnum_from_set(e.reg.class.regnum_set)
                        retry
                end

                # Remove any of the registers that have been clobbered by this block
                # from the list of consumed register numbers so that they can be used
                # in the future.
                b[0].each_clobbers { |reg|
                        begin
                                state.defecate_regnum(reg.regnum)

                                reg.regnum = nil
                        rescue InvalidRegisterError
                        end
                }

        }

        # Finally, return the buffer that has been created.
        state.buffer
end
generate_block_list(state, level=0) click to toggle source

Generates the linear list of block permutations which is stored in the supplied state instance. This is done prior to assigning blocks offsets

# File lib/rex/poly/block.rb, line 380
def generate_block_list(state, level=0)
        if @depends.length > 1
                @depends.length.times {
                        f = rand(@depends.length)
                        @depends.push(@depends.delete_at(f))
                }
        end

        @depends.length.times { |cidx|

                pass = false

                while (not pass)

                        if (@depends[cidx].generated)
                                break

                        # If this dependent block is a once block and the magic 8 ball turns
                        # up zero, skip it and let a later block pick it up.  We only do this
                        # if we are not the last block to have a dependency on this block.
                        elsif ((@depends[cidx].once) and
                     (rand(2).to_i == 0) and
                     (@depends[cidx].last_reference? == false))
                                break
                        end

                        # Generate this block
                        @depends[cidx].generate_block_list(state, level+1)

                        if level != 0
                                return
                        else
                                @depends.length.times {
                                        f = rand(@depends.length)
                                        @depends.push(@depends.delete_at(f))
                                }

                                next
                        end
                end

                next
        }

        self.deref

        # Assign the instance local state for the duration of this generation
        @state = state

        # Select a random permutation
        perm = rand_perm

        # Set our block offset to the current state offset
        self.offset = state.curr_offset

        # Flag ourselves as having been generated for this iteration.
        self.generated = true

        # Adjust the current offset based on the permutations length
        state.curr_offset += perm.length

        # Add it to the linear list of blocks
        state.block_list << [ self, perm ]

        # Generate all the blocks that follow this one.
        @next_blocks.each { |b|
                b.generate_block_list(state)
        }

        # Return the state's block list
        state.block_list
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.