From d2670d52ecf384abbd6ffbe17e39e99b2f40f558 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 26 Jan 2011 04:24:41 +0000 Subject: [PATCH] add BufferRegister and BufferOffset support for shikata_ga_nai. see #3563. tested this pretty extensively. /me crosses fingers git-svn-id: file:///home/svn/framework3/trunk@11646 4d416f70-5f16-0410-b530-b9f4589650da --- lib/rex/poly/block.rb | 9 ++ modules/encoders/x86/shikata_ga_nai.rb | 133 +++++++++++++++++++++---- 2 files changed, 120 insertions(+), 22 deletions(-) diff --git a/lib/rex/poly/block.rb b/lib/rex/poly/block.rb index f6b8a61783..cb78d02d6a 100644 --- a/lib/rex/poly/block.rb +++ b/lib/rex/poly/block.rb @@ -289,6 +289,15 @@ class LogicalBlock (@state.first_phase) ? 0 : reg.regnum end + def size_of(lblock) + @state.block_list.map { |b, p| + if b == lblock + return p.length + end + } + 0 + end + # # This attributes contains the currently assigned offset of the permutation # associated with this block into the polymorphic buffer that is being diff --git a/modules/encoders/x86/shikata_ga_nai.rb b/modules/encoders/x86/shikata_ga_nai.rb index a6c2388bc5..4d2734c73a 100644 --- a/modules/encoders/x86/shikata_ga_nai.rb +++ b/modules/encoders/x86/shikata_ga_nai.rb @@ -114,16 +114,6 @@ protected # Declare individual blocks endb = Rex::Poly::SymbolicBlock::End.new - # FPU blocks - fpu = Rex::Poly::LogicalBlock.new('fpu', - *fpu_instructions) - fnstenv = Rex::Poly::LogicalBlock.new('fnstenv', - "\xd9\x74\x24\xf4") - - # Get EIP off the stack - popeip = Rex::Poly::LogicalBlock.new('popeip', - Proc.new { |b| (0x58 + b.regnum_of(addr_reg)).chr }) - # Clear the counter register clear_register = Rex::Poly::LogicalBlock.new('clear_register', "\x31\xc9", @@ -158,18 +148,87 @@ protected Proc.new { |b| (0xb8 + b.regnum_of(key_reg)).chr + 'XORK'}) end + xor = Proc.new { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr } + add = Proc.new { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr } + + sub4 = Proc.new { |b| sub_immediate(b.regnum_of(addr_reg), -4) } + add4 = Proc.new { |b| add_immediate(b.regnum_of(addr_reg), 4) } + + if (datastore["BufferRegister"]) + + buff_reg = Rex::Poly::LogicalRegister::X86.new('buff', datastore["BufferRegister"]) + offset = (datastore["BufferOffset"] ? datastore["BufferOffset"].to_i : 0) + if ((offset < -255 or offset > 255) and state.badchars.include? "\x00") + raise EncodingError.new("Can't generate NULL-free decoder with a BufferOffset bigger than one byte") + end + mov = Proc.new { |b| + # mov , + "\x89" + (0xc0 + b.regnum_of(addr_reg) + (8 * b.regnum_of(buff_reg))).chr + } + add_offset = Proc.new { |b| add_immediate(b.regnum_of(addr_reg), offset) } + sub_offset = Proc.new { |b| sub_immediate(b.regnum_of(addr_reg), -offset) } + + getpc = Rex::Poly::LogicalBlock.new('getpc') + getpc.add_perm(Proc.new{ |b| mov.call(b) + add_offset.call(b) }) + getpc.add_perm(Proc.new{ |b| mov.call(b) + sub_offset.call(b) }) + + # With an offset of less than four, inc is smaller than or the same size as add + if (offset > 0 and offset < 4) + getpc.add_perm(Proc.new{ |b| mov.call(b) + inc(b.regnum_of(addr_reg))*offset }) + elsif (offset < 0 and offset > -4) + getpc.add_perm(Proc.new{ |b| mov.call(b) + dec(b.regnum_of(addr_reg))*(-offset) }) + end + + # NOTE: Adding a perm with possibly different sizes is normally + # wrong since it will change the SymbolicBlock::End offset during + # various stages of generation. In this case, though, offset is + # constant throughout the whole process, so it isn't a problem. + getpc.add_perm(Proc.new{ |b| + if (offset < -255 or offset > 255) + # lea addr_reg, [buff_reg + DWORD offset] + # NOTE: This will generate NULL bytes! + "\x8d" + (0x80 + b.regnum_of(buff_reg) + (8 * b.regnum_of(addr_reg))).chr + [offset].pack('V') + elsif (offset > -255 and offset != 0 and offset < 255) + # lea addr_reg, [buff_reg + byte offset] + "\x8d" + (0x40 + b.regnum_of(buff_reg) + (8 * b.regnum_of(addr_reg))).chr + [offset].pack('c') + else + # lea addr_reg, [buff_reg] + "\x8d" + (b.regnum_of(buff_reg) + (8 * b.regnum_of(addr_reg))).chr + end + }) + + # BufferReg+BufferOffset points right at the beginning of our + # buffer, so in contrast to the fnstenv technique, we don't have to + # sub off any other offsets. + xor1 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - cutoff) ].pack('c') } + xor2 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - 4 - cutoff) ].pack('c') } + add1 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - cutoff) ].pack('c') } + add2 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - 4 - cutoff) ].pack('c') } + + else + # FPU blocks + fpu = Rex::Poly::LogicalBlock.new('fpu', + *fpu_instructions) + + fnstenv = Rex::Poly::LogicalBlock.new('fnstenv', + "\xd9\x74\x24\xf4") + fnstenv.depends_on(fpu) + + # Get EIP off the stack + getpc = Rex::Poly::LogicalBlock.new('getpc', + Proc.new { |b| (0x58 + b.regnum_of(addr_reg)).chr }) + getpc.depends_on(fnstenv) + + # Subtract the offset of the fpu instruction since that's where eip points after fnstenv + xor1 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') } + xor2 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') } + add1 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') } + add2 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') } + end + # Decoder loop block loop_block = Rex::Poly::LogicalBlock.new('loop_block') - xor = Proc.new { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr } - xor1 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') } - xor2 = Proc.new { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') } - add = Proc.new { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr } - add1 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') } - add2 = Proc.new { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') } - sub4 = Proc.new { |b| "\x83" + (0xe8 + b.regnum_of(addr_reg)).chr + "\xfc" } - add4 = Proc.new { |b| "\x83" + (0xc0 + b.regnum_of(addr_reg)).chr + "\x04" } - loop_block.add_perm( Proc.new { |b| xor1.call(b) + add1.call(b) + sub4.call(b) }, Proc.new { |b| xor1.call(b) + sub4.call(b) + add2.call(b) }, @@ -181,12 +240,19 @@ protected # Loop instruction block loop_inst = Rex::Poly::LogicalBlock.new('loop_inst', "\xe2\xf5") + # In the current implementation the loop block is a constant size, + # so really no need for a fancy calculation. Nevertheless, here's + # one way to do it: + #Proc.new { |b| + # # loop + # # -2 to account for the size of this instruction + # "\xe2" + [ -2 - b.size_of(loop_block) ].pack('c') + #}) # Define block dependencies - fnstenv.depends_on(fpu) - popeip.depends_on(fnstenv) + clear_register.depends_on(getpc) init_counter.depends_on(clear_register) - loop_block.depends_on(popeip, init_counter, init_key) + loop_block.depends_on(init_counter, init_key) loop_inst.depends_on(loop_block) # Generate a permutation saving the ECX and ESP registers @@ -195,4 +261,27 @@ protected Rex::Arch::X86::ECX ], nil, state.badchars) end + def sub_immediate(regnum, imm) + return "" if imm.nil? or imm == 0 + if imm > 255 or imm < -255 + "\x81" + (0xe8 + regnum).chr + [imm].pack('V') + else + "\x83" + (0xe8 + regnum).chr + [imm].pack('c') + end + end + def add_immediate(regnum, imm) + return "" if imm.nil? or imm == 0 + if imm > 255 or imm < -255 + "\x81" + (0xc0 + regnum).chr + [imm].pack('V') + else + "\x83" + (0xc0 + regnum).chr + [imm].pack('c') + end + end + def inc(regnum) + [0x40 + regnum].pack('C') + end + def dec(regnum) + [0x48 + regnum].pack('C') + end + end