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
This commit is contained in:
James Lee 2011-01-26 04:24:41 +00:00
parent 4b777686d8
commit d2670d52ec
2 changed files with 120 additions and 22 deletions

View File

@ -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

View File

@ -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 <buff_reg>, <addr_reg>
"\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 <loop_block label>
# # -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