Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/encoders/x86/xor_poly.rb
Views: 11779
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Encoder::Xor67def initialize8super(9'Name' => 'XOR POLY Encoder',10'Description' => 'An x86 Simple POLY Xor encoding method. using polymorphism Register swapping, and instructions modification',11'Author' => [ 'Arthur RAOUT' ],12'Arch' => ARCH_X86,13'License' => MSF_LICENSE,14'Decoder' => {15'KeySize' => 4,16'BlockSize' => 4,17'KeyPack' => 'V'18}19)20end2122# Indicate that this module can preserve the registers used23def can_preserve_registers?24true25end2627# select a permutation from table28def choose_permutation(state, table)29table = table.shuffle30for i in 0..table.length - 131if table[i].count(state.badchars).zero?32return table[i]33end34end35raise 'No permutation found for the badchar set :' + state.badchars.inspect36end3738# generate instruction for a push39def register_preservation_generate(flag, regs)40ret = ''41pop = 0b0101_100042push = 0b0101_000043if flag == 044for r in regs45ret += [push | r].pack('C')46end47end48if flag == 149for r in regs.reverse50ret += [pop | r].pack('C')51end52end53return ret54end5556def decoder_stub(state)57state.decoder_key_size = 458state.decoder_key_pack = 'V'59# calculate the (negative) and positive block count.60block_count = [-(((state.buf.length - 1) / state.decoder_key_size) + 1)].pack('V')61block_count_positive = [(((state.buf.length - 1) / state.decoder_key_size) + 1)].pack('V')6263regs = [0b0000, 0b0001, 0b0010, 0b0011, 0b0110, 0b0111]6465pop = 0b0101_100066push = 0b0101_000067mov = 0b1011_10006869reg1 = regs[rand(6)]70regs.delete(reg1)71reg2 = regs[rand(5)]72regs.delete(reg2)73reg3 = regs[rand(4)]74regs.delete(reg3)75reg4 = regs[rand(3)] # reg4 is useless and used for nopLike operations76regs.delete(reg4)7778# NOPS79nop_nop_nop_nop = "\x90\x90\x90\x90" # 4 bytes80push_pop12 = [push | reg1, push | reg2, pop | reg2, pop | reg1].pack('CCCC') # 4 bytes81push_pop34 = [push | reg3, push | reg4, pop | reg4, pop | reg3].pack('CCCC') # 4 bytes82push_pop56 = [push | reg4, push | reg1, pop | reg1, pop | reg4].pack('CCCC') # 4 bytes8384sub_reg_0 = [0x83, (0xE8 | rand(6)), 0x00].pack('CCC') # 3 bytes85add_reg_0 = [0x83, (0xc0 | rand(6)), 0x00].pack('CCC') # 3 bytes86add_reg4_1 = [0x83, (0xc0 | reg4), 0x01].pack('CCC') # 3 bytes87add_reg4_33 = [0x83, (0xc0 | reg4), 0x33].pack('CCC') # 3 bytes88add_reg4_f1 = [0x83, (0xc0 | reg4), 0xf1].pack('CCC') # 3 bytes89nop_nop_nop = "\x90\x90\x90" # 3 bytes9091push_pop1 = [push | reg1, pop | reg1].pack('CC') # 2 bytes92push_pop2 = [push | reg2, pop | reg2].pack('CC') # 2 bytes93push_pop3 = [push | reg3, pop | reg3].pack('CC') # 2 bytes94push_pop4 = [push | reg4, pop | reg4].pack('CC') # 2 bytes95inc_reg1_dec_reg1 = [0x40 | reg1, 0x48 | reg1].pack('CC') # 2 bytes96inc_reg2_dec_reg2 = [0x40 | reg2, 0x48 | reg2].pack('CC') # 2 bytes97inc_reg3_dec_reg3 = [0x40 | reg3, 0x48 | reg3].pack('CC') # 2 bytes98inc_reg4_dec_reg4 = [0x40 | reg4, 0x48 | reg4].pack('CC') # 2 bytes99100# nops tables by size101nops_2_bytes = [push_pop1, push_pop2, push_pop3, push_pop4, "\x90\x90", inc_reg1_dec_reg1, inc_reg2_dec_reg2, inc_reg3_dec_reg3, inc_reg4_dec_reg4]102nops_3_bytes = [nop_nop_nop, push_pop1 + "\x90", push_pop2 + "\x90", push_pop3 + "\x90", push_pop4 + "\x90", sub_reg_0, add_reg_0, choose_permutation(state, nops_2_bytes) + "\x90", add_reg4_1, add_reg4_33, add_reg4_f1]103nops_4_bytes = [nop_nop_nop_nop, push_pop12, push_pop34, push_pop56, choose_permutation(state, nops_2_bytes) + choose_permutation(state, nops_2_bytes), choose_permutation(state, nops_3_bytes) + "\x90"]104105# THE DECODER CODE106pop_reg1 = [pop | reg1].pack('C')107108# sub 5 from reg1 on 5 byte109sub_reg1_5 = [0x83, (0xE8 | reg1), 0x05].pack('CCC') + choose_permutation(state, nops_2_bytes) # 5 bytes110add_reg1_neg5 = [0x83, (0xc0 | reg1), 0xfb].pack('CCC') + choose_permutation(state, nops_2_bytes) # 5 bytes111dec_reg1_5 = [0x48 | reg1, 0x48 | reg1, 0x48 | reg1, 0x48 | reg1, 0x48 | reg1].pack('CCCCC') # 5 bytes112113# set reg2 to 0, on 6 bytes114xor_reg2_reg2 = [0x31, (0xC0 | (reg2 << 3) | reg2)].pack('CC') + choose_permutation(state, nops_4_bytes) # 6 bytes115and_reg2_0 = [0x83, (0xE0 | reg2), 0x00].pack('CCC') + choose_permutation(state, nops_3_bytes) # 6 bytes116lea_reg2_0 = [0x8D, (0x05 | (reg2 << 3)), 0x00, 0x00, 0x00, 0x00].pack('CCCCCC')117imul_reg2_reg2_0 = [0x6b, (0xC0 | (reg2 << 3) | reg2), 0x00].pack('CCC') + choose_permutation(state, nops_3_bytes) # 6 bytes118sub_reg2_reg2 = [0x29, (0xC0 | (reg2 << 3) | reg2)].pack('CC') + choose_permutation(state, nops_4_bytes) # 6 bytes119push0_popreg2 = [0x6A, 0x00, (0x58 | reg2)].pack('CCC') + choose_permutation(state, nops_3_bytes) # 6 bytes120121# SET REG2 TO BLOCK_COUNT122sub_reg2_bc = [0x81, (0xe8 | reg2)].pack('CC') + block_count123add_reg2_bc = [0x81, (0xc0 | reg2)].pack('CC') + block_count_positive124125mov_reg3 = [mov | reg3].pack('C')126xor_rel_reg1_reg3 = [0x31, (0x40 | (reg3 << 3 | reg1))].pack('cc')127128# ADD 4 TO REG1129add_reg1_4 = [0x83, (0xC0 | reg1), 0x04].pack('CCC') + choose_permutation(state, nops_3_bytes) # 6 bytes130sub_reg1_neg4 = [0x83, (0xE8 | reg1), 0xFC].pack('CCC') + choose_permutation(state, nops_3_bytes) # 6 bytes131inc_reg1_4 = [0x40 | reg1, 0x40 | reg1, 0x40 | reg1, 0x40 | reg1].pack('CCCC') + choose_permutation(state, nops_2_bytes) # 6 bytes132133# sub 1 from reg2 on 6 bytes134dec_r2 = [0xFF, (0xC8 | reg2)].pack('CC')135sub_reg2_1 = [0x83, (0xE8 | reg2), 0x01].pack('CCC')136add_reg2_neg1 = [0x83, (0xC0 | reg2), 0xFF].pack('CCC')137138set_reg2_0 = [xor_reg2_reg2, and_reg2_0, lea_reg2_0, imul_reg2_reg2_0, sub_reg2_reg2, push0_popreg2]139sub_reg1_0x5 = [sub_reg1_5, add_reg1_neg5, dec_reg1_5]140set_reg2_bc = [sub_reg2_bc, add_reg2_bc]141142# GET EIP TO REG1143call_pop = [0xE8, 0x00, 0x00, 0x00, 0x00].pack('CCCCC') + pop_reg1 + choose_permutation(state, sub_reg1_0x5)144fpu_inst = ["\xD9\xE0", "\xDF\xE9", "\xDB\xC9", "\xDA\xD9", "\xDA\xC1", "\xDA\xD1", "\xDB\xD9"] # 2 bytes145fnstenv_pop = choose_permutation(state, fpu_inst) + "\xD9\x74\x24\xF4" + pop_reg1146add_reg1_0x4 = [add_reg1_4, sub_reg1_neg4, inc_reg1_4]147dec_reg2 = [dec_r2, sub_reg2_1, add_reg2_neg1]148get_eip = [call_pop, fnstenv_pop]149150small_junk = [choose_permutation(state, nops_2_bytes), choose_permutation(state, nops_3_bytes), choose_permutation(state, nops_4_bytes)]151152reg_for_preservation = [reg1, reg2, reg3, reg4].shuffle153reg_push = register_preservation_generate(0, reg_for_preservation)154reg_pop = register_preservation_generate(1, reg_for_preservation)155geip = choose_permutation(state, get_eip)156junk = choose_permutation(state, small_junk)157reg2_0 = choose_permutation(state, set_reg2_0)158block_count_set = choose_permutation(state, set_reg2_bc)159reg1_add4 = choose_permutation(state, add_reg1_0x4)160decrement_reg2 = choose_permutation(state, dec_reg2)161162decoder = reg_push +163geip + # get EIP into REG1164junk + # small junk165reg2_0 + # set REG2 to 0166block_count_set + # sub reg2, block_count167mov_reg3 + 'XXXX' + # mov reg3, 0xKEY_KEY_KEY_KEY168xor_rel_reg1_reg3 + 'LL' + # xor [reg1+DECODER_LEN], reg3169reg1_add4 + # add reg1, 4170decrement_reg2 + # dec reg2171"\x75" + 'SS' + # jnz to xor172reg_pop173174decoder_len = decoder.size175jmp = decoder.index(xor_rel_reg1_reg3) - decoder.index('SS')176decoder.sub! 'SS', [jmp].pack('C')177decoder.sub! 'LL', [decoder_len - 6].pack('C')178# example of decoder generated179# e800000000 call loc._start.continue180# 58 pop eax181# 83e805 sub eax, 5182# 31c9 xor ecx, ecx183# 81e9bbbbbbbb sub ecx, 0xbbbbbbbb184# bbaaaaaaaa mov ebx, 0xaaaaaaaa185# 31581f xor dword [eax + 0x1f], ebx186# 83e8f4 sub eax, 0xfffffff4187# e2f8 loop loc._start.check188state.decoder_key_offset = decoder.index('XXXX')189return decoder190end191end192193194