Path: blob/master/modules/encoders/x86/shikata_ga_nai.rb
19852 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'rex/poly'67class MetasploitModule < Msf::Encoder::XorAdditiveFeedback89# The shikata encoder has an excellent ranking because it is polymorphic.10# Party time, excellent!11Rank = ExcellentRanking1213def initialize14super(15'Name' => 'Polymorphic XOR Additive Feedback Encoder',16'Description' => %q{17This encoder implements a polymorphic XOR additive feedback encoder.18The decoder stub is generated based on dynamic instruction19substitution and dynamic block ordering. Registers are also20selected dynamically.21},22'Author' => 'spoonm',23'Arch' => ARCH_X86,24'License' => MSF_LICENSE,25'Decoder' => {26'KeySize' => 4,27'BlockSize' => 428})29end3031#32# Generates the shikata decoder stub.33#34def decoder_stub(state)35# If the decoder stub has not already been generated for this state, do36# it now. The decoder stub method may be called more than once.37if state.decoder_stub.nil?3839# Sanity check that saved_registers doesn't overlap with modified_registers40if !(modified_registers & saved_registers).empty?41raise BadGenerateError42end4344# Shikata will only cut off the last 1-4 bytes of it's own end45# depending on the alignment of the original buffer46cutoff = 4 - (state.buf.length & 3)47block = generate_shikata_block(state, state.buf.length + cutoff, cutoff) || (raise BadGenerateError)4849# Set the state specific key offset to wherever the XORK ended up.50state.decoder_key_offset = block.index('XORK')5152# Take the last 1-4 bytes of shikata and prepend them to the buffer53# that is going to be encoded to make it align on a 4-byte boundary.54state.buf = block.slice!(block.length - cutoff, cutoff) + state.buf5556# Cache this decoder stub. The reason we cache the decoder stub is57# because we need to ensure that the same stub is returned every time58# for a given encoder state.59state.decoder_stub = block60end6162state.decoder_stub63end6465# Indicate that this module can preserve some registers66def can_preserve_registers?67true68end6970# A list of registers always touched by this encoder71def modified_registers72# ESP is assumed and is handled through preserves_stack?73[74# The counter register is hardcoded75Rex::Arch::X86::ECX,76# These are modified by div and mul operations77Rex::Arch::X86::EAX, Rex::Arch::X86::EDX78]79end8081# Always blacklist these registers in our block generation82def block_generator_register_blacklist83[Rex::Arch::X86::ESP, Rex::Arch::X86::ECX] | saved_registers84end8586protected8788#89# Returns the set of FPU instructions that can be used for the FPU block of90# the decoder stub.91#92def fpu_instructions93fpus = []94950xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }960xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }970xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }980xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }990xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }100101fpus << "\xd9\xd0"102fpus << "\xd9\xe1"103fpus << "\xd9\xf6"104fpus << "\xd9\xf7"105fpus << "\xd9\xe5"106107# This FPU instruction seems to fail consistently on Linux108# fpus << "\xdb\xe1"109110fpus111end112113#114# Returns a polymorphic decoder stub that is capable of decoding a buffer115# of the supplied length and encodes the last cutoff bytes of itself.116#117def generate_shikata_block(state, length, cutoff)118# Declare logical registers119Rex::Poly::LogicalRegister::X86.new('count', 'ecx')120addr_reg = Rex::Poly::LogicalRegister::X86.new('addr')121key_reg = nil122123if state.context_encoding124key_reg = Rex::Poly::LogicalRegister::X86.new('key', 'eax')125else126key_reg = Rex::Poly::LogicalRegister::X86.new('key')127end128129# Declare individual blocks130endb = Rex::Poly::SymbolicBlock::End.new131132# Clear the counter register133clear_register = Rex::Poly::LogicalBlock.new(134'clear_register',135"\x31\xc9", # xor ecx,ecx136"\x29\xc9", # sub ecx,ecx137"\x33\xc9", # xor ecx,ecx138"\x2b\xc9" # sub ecx,ecx139)140141# Initialize the counter after zeroing it142init_counter = Rex::Poly::LogicalBlock.new('init_counter')143144# Divide the length by four but ensure that it aligns on a block size145# boundary (4 byte).146length += 4 + (4 - (length & 3)) & 3147length /= 4148149if (length <= 255)150init_counter.add_perm("\xb1" + [ length ].pack('C'))151elsif (length <= 65536)152init_counter.add_perm("\x66\xb9" + [ length ].pack('v'))153else154init_counter.add_perm("\xb9" + [ length ].pack('V'))155end156157# Key initialization block158init_key = nil159160# If using context encoding, we use a mov reg, [addr]161if state.context_encoding162init_key = Rex::Poly::LogicalBlock.new(163'init_key',164proc { |b| (0xa1 + b.regnum_of(key_reg)).chr + 'XORK' }165)166# Otherwise, we do a direct mov reg, val167else168init_key = Rex::Poly::LogicalBlock.new('init_key',169proc { |b| (0xb8 + b.regnum_of(key_reg)).chr + 'XORK' })170end171172xor = proc { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }173add = proc { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }174175sub4 = proc { |b| sub_immediate(b.regnum_of(addr_reg), -4) }176add4 = proc { |b| add_immediate(b.regnum_of(addr_reg), 4) }177178if datastore['BufferRegister']179180buff_reg = Rex::Poly::LogicalRegister::X86.new('buff', datastore['BufferRegister'])181offset = (datastore['BufferOffset'] ? datastore['BufferOffset'].to_i : 0)182if ((offset < -255) || (offset > 255)) && state.badchars.include?("\x00")183raise EncodingError, "Can't generate NULL-free decoder with a BufferOffset bigger than one byte"184end185186mov = proc do |b|187# mov <buff_reg>, <addr_reg>188"\x89" + (0xc0 + b.regnum_of(addr_reg) + (8 * b.regnum_of(buff_reg))).chr189end190add_offset = proc { |b| add_immediate(b.regnum_of(addr_reg), offset) }191sub_offset = proc { |b| sub_immediate(b.regnum_of(addr_reg), -offset) }192193getpc = Rex::Poly::LogicalBlock.new('getpc')194getpc.add_perm(proc { |b| mov.call(b) + add_offset.call(b) })195getpc.add_perm(proc { |b| mov.call(b) + sub_offset.call(b) })196197# With an offset of less than four, inc is smaller than or the same size as add198if (offset > 0) && (offset < 4)199getpc.add_perm(proc { |b| mov.call(b) + inc(b.regnum_of(addr_reg)) * offset })200elsif (offset < 0) && (offset > -4)201getpc.add_perm(proc { |b| mov.call(b) + dec(b.regnum_of(addr_reg)) * -offset })202end203204# NOTE: Adding a perm with possibly different sizes is normally205# wrong since it will change the SymbolicBlock::End offset during206# various stages of generation. In this case, though, offset is207# constant throughout the whole process, so it isn't a problem.208getpc.add_perm(proc do |b|209if (offset < -255) || (offset > 255)210# lea addr_reg, [buff_reg + DWORD offset]211# NOTE: This will generate NULL bytes!212"\x8d" + (0x80 + b.regnum_of(buff_reg) + (8 * b.regnum_of(addr_reg))).chr + [offset].pack('V')213elsif (offset > -255) && (offset != 0) && (offset < 255)214# lea addr_reg, [buff_reg + byte offset]215"\x8d" + (0x40 + b.regnum_of(buff_reg) + (8 * b.regnum_of(addr_reg))).chr + [offset].pack('c')216else217# lea addr_reg, [buff_reg]218"\x8d" + (b.regnum_of(buff_reg) + (8 * b.regnum_of(addr_reg))).chr219end220end)221222# BufferReg+BufferOffset points right at the beginning of our223# buffer, so in contrast to the fnstenv technique, we don't have to224# sub off any other offsets.225xor1 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - cutoff) ].pack('c') }226xor2 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - 4 - cutoff) ].pack('c') }227add1 = proc { |b| add.call(b) + [ (b.offset_of(endb) - cutoff) ].pack('c') }228add2 = proc { |b| add.call(b) + [ (b.offset_of(endb) - 4 - cutoff) ].pack('c') }229230else231# FPU blocks232fpu = Rex::Poly::LogicalBlock.new('fpu',233*fpu_instructions)234235fnstenv = Rex::Poly::LogicalBlock.new('fnstenv',236"\xd9\x74\x24\xf4")237fnstenv.depends_on(fpu)238239# Get EIP off the stack240getpc = Rex::Poly::LogicalBlock.new('getpc',241proc { |b| (0x58 + b.regnum_of(addr_reg)).chr })242getpc.depends_on(fnstenv)243244# Subtract the offset of the fpu instruction since that's where eip points after fnstenv245xor1 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }246xor2 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }247add1 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }248add2 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }249end250251# Decoder loop block252loop_block = Rex::Poly::LogicalBlock.new('loop_block')253254loop_block.add_perm(255proc { |b| xor1.call(b) + add1.call(b) + sub4.call(b) },256proc { |b| xor1.call(b) + sub4.call(b) + add2.call(b) },257proc { |b| sub4.call(b) + xor2.call(b) + add2.call(b) },258proc { |b| xor1.call(b) + add1.call(b) + add4.call(b) },259proc { |b| xor1.call(b) + add4.call(b) + add2.call(b) },260proc { |b| add4.call(b) + xor2.call(b) + add2.call(b) }261)262263# Loop instruction block264loop_inst = Rex::Poly::LogicalBlock.new('loop_inst',265"\xe2\xf5")266# In the current implementation the loop block is a constant size,267# so really no need for a fancy calculation. Nevertheless, here's268# one way to do it:269# Proc.new { |b|270# # loop <loop_block label>271# # -2 to account for the size of this instruction272# "\xe2" + [ -2 - b.size_of(loop_block) ].pack('c')273# })274275# Define block dependencies276clear_register.depends_on(getpc)277init_counter.depends_on(clear_register)278loop_block.depends_on(init_counter, init_key)279loop_inst.depends_on(loop_block)280281begin282# Generate a permutation saving the ECX, ESP, and user defined registers283loop_inst.generate(block_generator_register_blacklist, nil, state.badchars)284rescue RuntimeError, EncodingError => e285# The Rex::Poly block generator can raise RuntimeError variants286raise EncodingError, e.to_s287end288end289290# Convert the SaveRegisters to an array of x86 register constants291def saved_registers292Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])293end294295def sub_immediate(regnum, imm)296return '' if imm.nil? || (imm == 0)297298if (imm > 255) || (imm < -255)299"\x81" + (0xe8 + regnum).chr + [imm].pack('V')300else301"\x83" + (0xe8 + regnum).chr + [imm].pack('c')302end303end304305def add_immediate(regnum, imm)306return '' if imm.nil? || (imm == 0)307308if (imm > 255) || (imm < -255)309"\x81" + (0xc0 + regnum).chr + [imm].pack('V')310else311"\x83" + (0xc0 + regnum).chr + [imm].pack('c')312end313end314315def inc(regnum)316[0x40 + regnum].pack('C')317end318319def dec(regnum)320[0x48 + regnum].pack('C')321end322end323324325