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:
parent
4b777686d8
commit
d2670d52ec
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue