metasploit-framework/modules/encoders/x64/zutto_dekiru.rb

236 lines
6.2 KiB
Ruby
Raw Normal View History

require 'metasm'
require 'msf/core'
require 'rex/nop/opty2'
class MetasploitModule < Msf::Encoder::Xor
2016-07-12 19:45:14 +00:00
Rank = ManualRanking
def initialize
super(
'Name' => 'Zutto Dekiru',
'Version' => '$Revision: 14774 $',
'Description' => 'Inspired by shikata_ga_nai using fxsave64 to work under x86_64 systems.',
'Author' => 'agix',
'Arch' => ARCH_X86_64,
'License' => MSF_LICENSE,
'EncoderType' => Msf::Encoder::Type::Raw,
'Decoder' =>
{
'KeySize' => 8,
'KeyPack' => 'Q'
}
)
end
@@cpu64 = Metasm::X86_64.new
def assemble(src, cpu=@@cpu64)
Metasm::Shellcode.assemble(cpu, src).encode_string
end
def fxsave64(reg)
case reg
when "rax"
return "\x48\x0f\xae\x00"
when "rbx"
return "\x48\x0f\xae\x03"
when "rcx"
return "\x48\x0f\xae\x01"
when "rdx"
return "\x48\x0f\xae\x02"
when "rsi"
return "\x48\x0f\xae\x06"
when "rdi"
return "\x48\x0f\xae\x07"
when "rbp"
return "\x48\x0f\xae\x45\x00"
when "r8"
return "\x49\x0f\xae\x00"
when "r9"
return "\x49\x0f\xae\x01"
when "r10"
return "\x49\x0f\xae\x02"
when "r11"
return "\x49\x0f\xae\x03"
when "r12"
return "\x49\x0f\xae\x04\x24"
when "r13"
return "\x49\x0f\xae\x45\x00"
when "r14"
return "\x49\x0f\xae\x06"
when "r15"
return "\x49\x0f\xae\x07"
end
2016-07-12 19:45:14 +00:00
end
def nop(length,save_registers=[])
test = Rex::Nop::Opty2.new('',save_registers)
return test.generate_sled(length)
end
# Indicate that this module can preserve some registers
def can_preserve_registers?
true
end
#
# Returns the set of FPU instructions that can be used for the FPU block of
# the decoder stub.
#
def fpu_instructions
fpus = []
0xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }
0xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }
0xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }
0xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }
0xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }
fpus << "\xd9\xd0"
fpus << "\xd9\xe1"
fpus << "\xd9\xf6"
fpus << "\xd9\xf7"
fpus << "\xd9\xe5"
# This FPU instruction seems to fail consistently on Linux
#fpus << "\xdb\xe1"
fpus
end
def rand_string(length)
o = [('0'..'9'),('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten;
string = (0..(length-1)).map{ o[rand(o.length)] }.join;
return string
end
def xor_string(text,key)
text.length.times {|n| text[n] = (text[n].ord^key[n.modulo(key.length)].ord).chr }
return text
end
def ordered_random_merge(a,b)
a, b = a.dup, b.dup
a.map{rand(b.size+1)}.sort.reverse.each do |index|
b.insert(index, a.pop)
end
2016-07-12 19:45:14 +00:00
b
end
def encode_block(state, block)
2016-07-12 19:50:46 +00:00
allowed_reg = [
2016-07-12 19:45:14 +00:00
["rax", "eax", "ax", "al" ],
["rbx", "ebx", "bx", "bl" ],
["rcx", "ecx", "cx", "cl" ],
["rdx", "edx", "dx", "dl" ],
["rsi", "esi", "si", "sil" ],
["rdi", "edi", "di", "dil" ],
["rbp", "ebp", "bp", "bpl" ],
["r8", "r8d", "r8w", "r8b" ],
["r9", "r9d", "r9w", "r9b" ],
["r10", "r10d", "r10w", "r10b"],
["r11", "r11d", "r11w", "r11b"],
["r12", "r12d", "r12w", "r12b"],
["r13", "r13d", "r13w", "r13b"],
["r14", "r14d", "r14w", "r14b"],
["r15", "r15d", "r15w", "r15b"],
]
2016-07-12 19:50:46 +00:00
allowed_reg.delete_if { |reg| datastore['SaveRegisters'] && datastore['SaveRegisters'].include?(reg.first) }
allowed_reg.shuffle!
2016-07-12 19:45:14 +00:00
if block.length%8 != 0
block += nop(8-(block.length%8))
end
2016-07-12 19:45:14 +00:00
regType = 3
2016-07-12 19:45:14 +00:00
if (block.length/8) > 0xff
2016-07-12 19:50:46 +00:00
regType = 2
end
2016-07-12 19:45:14 +00:00
if (block.length/8) > 0xffff
2016-07-12 19:50:46 +00:00
regType = 1
end
2016-07-12 19:45:14 +00:00
if (block.length/8) > 0xffffffff
2016-07-12 19:50:46 +00:00
regType = 0
end
2016-07-12 19:50:46 +00:00
reg_key = allowed_reg[0][0]
reg_size = allowed_reg[3]
reg_rip = allowed_reg[1][0]
reg_env = allowed_reg[2]
2016-07-12 19:50:46 +00:00
flip_coin = rand(2)
2016-07-12 19:45:14 +00:00
fpuOpcode = Rex::Poly::LogicalBlock.new('fpu',
*fpu_instructions)
2016-07-12 19:45:14 +00:00
fpu = []
fpu << ["fpu",fpuOpcode.generate([], nil, state.badchars)]
2016-07-12 19:45:14 +00:00
sub = (rand(0xd00)&0xfff0)+0xf000
lea = []
2016-07-12 19:50:46 +00:00
if flip_coin==0
lea << ["lea", assemble("mov %s, rsp"%reg_env[0])]
lea << ["lea1", assemble("and "+reg_env[2]+", 0x%x"%sub)]
2016-07-12 19:45:14 +00:00
else
lea << ["lea", assemble("push rsp")]
2016-07-12 19:50:46 +00:00
lea << ["lea1", assemble("pop "+reg_env[0])]
lea << ["lea2", assemble("and "+reg_env[2]+", 0x%x"%sub)]
2016-07-12 19:45:14 +00:00
end
2016-07-12 19:50:46 +00:00
fpu_lea = ordered_random_merge(fpu, lea)
fpu_lea << ["fpu1", fxsave64(reg_env[0])] # fxsave64 doesn't seem to exist in metasm
2016-07-12 19:50:46 +00:00
key_ins = [["key", assemble("mov "+reg_key+", 0x%x"%state.key)]]
2016-07-12 19:45:14 +00:00
size = []
2016-07-12 19:50:46 +00:00
size << ["size", assemble("xor "+reg_size[0]+", "+reg_size[0])]
size << ["size", assemble("mov "+reg_size[regType]+", 0x%x"% (block.length/8))]
2016-07-12 19:45:14 +00:00
getrip=0
2016-07-12 19:50:46 +00:00
a = ordered_random_merge(size, key_ins)
decode_head_tab = ordered_random_merge(a, fpu_lea)
2016-07-12 19:50:46 +00:00
decode_head_tab.length.times { |i| getrip = i if decode_head_tab[i][0] == "fpu"}
2016-07-12 19:50:46 +00:00
decode_head = decode_head_tab.map { |j,i| i.to_s }.join
2016-07-12 19:50:46 +00:00
flip_coin = rand(2)
2016-07-12 19:50:46 +00:00
if flip_coin==0
decode_head += assemble("mov "+reg_rip+", ["+reg_env[0]+" + 0x8]")
2016-07-12 19:45:14 +00:00
else
2016-07-12 19:50:46 +00:00
decode_head += assemble("add "+reg_env[0]+", 0x8")
decode_head += assemble("mov "+reg_rip+", ["+reg_env[0]+"]")
2016-07-12 19:45:14 +00:00
end
2016-07-12 19:50:46 +00:00
decode_head_size = decode_head.length
getrip.times { |i| decode_head_size -= decode_head_tab[i][1].length }
2016-07-12 19:50:46 +00:00
loop_code = assemble("dec "+reg_size[0])
loop_code += assemble("xor ["+reg_rip+"+("+reg_size[0]+"*8) + 0x7f], "+reg_key)
loop_code += assemble("test "+reg_size[0]+", "+reg_size[0])
2016-07-12 19:50:46 +00:00
payload_offset = decode_head_size+loop_code.length+2
2016-07-12 19:50:46 +00:00
loop_code = assemble("dec "+reg_size[0])
loop_code += assemble("xor ["+reg_rip+"+("+reg_size[0]+"*8) + 0x"+payload_offset.to_s(16)+"], "+reg_key)
loop_code += assemble("test "+reg_size[0]+", "+reg_size[0])
2016-07-12 19:50:46 +00:00
jnz = "\x75"+(0x100-(loop_code.length+2)).chr
2016-07-12 19:50:46 +00:00
decode = decode_head+loop_code+jnz
2016-07-12 19:45:14 +00:00
encode = xor_string(block, [state.key].pack('Q'))
2016-07-12 19:45:14 +00:00
return decode + encode
end
end