diff --git a/lib/rex/poly/block.rb b/lib/rex/poly/block.rb index b9abcf15c5..e3592fe0f4 100644 --- a/lib/rex/poly/block.rb +++ b/lib/rex/poly/block.rb @@ -82,12 +82,16 @@ class LogicalBlock # Resets the block back to its starting point. # def reset - @perms = [] - @depends = [] - @next_blocks = [] - @clobbers = [] - @offset = nil - @state = nil + @perms = [] + @depends = [] + @next_blocks = [] + @clobbers = [] + @offset = nil + @state = nil + @once = false + @references = 0 + @used_references = 0 + @generated = false end # @@ -97,6 +101,46 @@ class LogicalBlock @name end + # + # 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. + # + def once=(tf) + @once = tf + end + + # + # 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. + # + def once + @once + end + + # + # Increments the number of blocks that depend on this block. + # + def ref + @references += 1 + end + + # + # Increments the number of blocks that have completed their dependency + # pass on this block. This number should never become higher than the + # @references attribute. + # + def deref + @used_references += 1 + end + + # + # Returns true if there is only one block reference remaining. + # + def last_reference? + (@references - @used_references <= 0) + end + # # Adds zero or more specific permutations that may be represented either as # strings or as Proc's to be called at evaluation time. @@ -118,6 +162,9 @@ class LogicalBlock # def depends_on(*depends) @depends = depends.dup + + # Increment dependent references + @depends.each { |b| b.ref } end # @@ -244,6 +291,12 @@ class LogicalBlock # attr_accessor :offset + # + # Whether or not this block has currently been generated for a given + # iteration. + # + attr_accessor :generated + protected # @@ -256,9 +309,27 @@ protected depend_idx = rand(@depends.length) @depends.length.times { |x| + cidx = (depend_idx + x) % @depends.length + + # Decrement the used reference count + @depends[cidx].deref + + # 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. + if ((@depends[cidx].once) and + (rand(2).to_i == 0) and + (@depends[cidx].last_reference? == false)) + next + # Otherwise, if this is a once block that has already been generated, + # skip it. + elsif ((@depends[cidx].once) and + (@depends[cidx].generated)) + next + end # Generate this block - @depends[(depend_idx + x) % @depends.length].generate_block_list(state) + @depends[cidx].generate_block_list(state) } # Assign the instance local state for the duration of this generation @@ -270,6 +341,9 @@ protected # 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 diff --git a/modules/encoders/x86/jmp_call_additive.rb b/modules/encoders/x86/jmp_call_additive.rb index 9d534cba81..3885081084 100644 --- a/modules/encoders/x86/jmp_call_additive.rb +++ b/modules/encoders/x86/jmp_call_additive.rb @@ -84,7 +84,12 @@ protected call = Rex::Poly::LogicalBlock.new('call', Proc.new { |b| "\xe8" + [ (-(b.offset_of(endb) - (b.offset_of(jmp) + 2))) ].pack('V') }) jmp.add_perm( - Proc.new { |b| "\xeb" + [ (b.offset_of(call) - (b.offset_of(b) + 2)) ].pack('C') }) + Proc.new { |b| "\xeb" + [ (b.offset_of(fin) + 1 - (b.offset_of(b) + 2)) ].pack('C') }) + + # These blocks can be in lots of different places, but should only be + # used once. + cld.once = true + init_key.once = true # This can be improved by making it so init_key and cld can occur # anywhere prior to pusheip. @@ -95,8 +100,9 @@ protected lodsd.depends_on(xor) xor.depends_on(pusheip) pusheip.depends_on(popeip, init_key, cld) - call.depends_on(fin) + call.depends_on(fin, init_key, cld) jmp.next_blocks(call) + jmp.depends_on(init_key, cld) jmp.generate([ Rex::Arch::X86::ESP,