117 lines
3.3 KiB
Ruby
117 lines
3.3 KiB
Ruby
require 'msf/core'
|
|
|
|
module Msf
|
|
module Encoders
|
|
module X86
|
|
|
|
###
|
|
#
|
|
# "\xfc" + # cld
|
|
# "\xbbXORK" + # mov ebx, key
|
|
# "\xeb\x0c" + # jmp short 0x14
|
|
# "\x5e" + # pop esi
|
|
# "\x56" + # push esi
|
|
# "\x31\x1e" + # xor [esi], ebx
|
|
# "\xad" + # lodsd
|
|
# "\x01\xc3" + # add ebx, eax
|
|
# "\x85\xc0" + # test eax, eax
|
|
# "\x75\xf7" + # jnz 0xa
|
|
# "\xc3" + # ret
|
|
# "\xe8\xef\xff\xff\xff", # call 0x8
|
|
#
|
|
###
|
|
class JmpCallAdditive < Msf::Encoder::XorAdditiveFeedback
|
|
|
|
Rank = GreatRanking
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'Polymorphic Jump/Call XOR Additive Feedback Encoder',
|
|
'Version' => '$Revision$',
|
|
'Description' => 'Polymorphic Jump/Call XOR Additive Feedback',
|
|
'Author' => 'skape',
|
|
'Arch' => ARCH_X86,
|
|
'License' => GPL_LICENSE,
|
|
'Decoder' =>
|
|
{
|
|
'KeySize' => 4,
|
|
'BlockSize' => 4,
|
|
})
|
|
end
|
|
|
|
#
|
|
# Generates a polymorphic version of the jmp/call/additive stub.
|
|
#
|
|
def decoder_stub(state)
|
|
if (state.decoder_stub == nil)
|
|
block = generate_decoder_stub
|
|
state.decoder_key_offset = block.index('XORK')
|
|
state.decoder_stub = block
|
|
end
|
|
|
|
state.decoder_stub
|
|
end
|
|
|
|
#
|
|
# Append the termination block.
|
|
#
|
|
def encode_end(state)
|
|
state.encoded += [ state.key ].pack(state.decoder_key_pack)
|
|
end
|
|
|
|
protected
|
|
|
|
#
|
|
# Does the actual stub generation.
|
|
#
|
|
def generate_decoder_stub
|
|
key_reg = Rex::Poly::LogicalRegister::X86.new('key')
|
|
endb = Rex::Poly::SymbolicBlock::End.new
|
|
cld = Rex::Poly::LogicalBlock.new('cld', "\xfc")
|
|
init_key = Rex::Poly::LogicalBlock.new('init_key',
|
|
Proc.new { |b| (0xb8 + b.regnum_of(key_reg)).chr + 'XORK' })
|
|
popeip = Rex::Poly::LogicalBlock.new('popeip', "\x5e")
|
|
pusheip = Rex::Poly::LogicalBlock.new('pusheip', "\x56")
|
|
xor = Rex::Poly::LogicalBlock.new('xor',
|
|
Proc.new { |b| "\x31" + (6 + (8 * b.regnum_of(key_reg))).chr })
|
|
lodsd = Rex::Poly::LogicalBlock.new('lodsd', "\xad")
|
|
add = Rex::Poly::LogicalBlock.new('add',
|
|
Proc.new { |b| "\x01" + (0xc0 + b.regnum_of(key_reg)).chr })
|
|
test = Rex::Poly::LogicalBlock.new('test', "\x85\xc0")
|
|
jnz = Rex::Poly::LogicalBlock.new('jnz',
|
|
Proc.new { |b| "\x75" + [ (0x100 - (b.offset_of(b) - b.offset_of(xor) + 2)) ].pack('C') })
|
|
fin = Rex::Poly::LogicalBlock.new('ret', "\xc3")
|
|
jmp = Rex::Poly::LogicalBlock.new('jmp')
|
|
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(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.
|
|
fin.depends_on(jnz)
|
|
jnz.depends_on(test)
|
|
test.depends_on(add)
|
|
add.depends_on(lodsd)
|
|
lodsd.depends_on(xor)
|
|
xor.depends_on(pusheip)
|
|
pusheip.depends_on(popeip, init_key, cld)
|
|
call.depends_on(fin, init_key, cld)
|
|
jmp.next_blocks(call)
|
|
jmp.depends_on(init_key, cld)
|
|
|
|
jmp.generate([
|
|
Rex::Arch::X86::ESP,
|
|
Rex::Arch::X86::EAX,
|
|
Rex::Arch::X86::ESI ])
|
|
end
|
|
|
|
end
|
|
|
|
end end end
|