#include "instruction_container_deobfuscator.hpp" #include "instruction_emulator.hpp" void instruction_container_deobfuscator::deobfuscate() { uint32_t pre_deobfuscation_size = 0; do { pre_deobfuscation_size = this->size(); this->deobfuscate_push(); this->deobfuscate_pop(); this->deobfuscate_stack(); this->deobfuscate_xchg_v1(); this->deobfuscate_mov_v1(); this->deobfuscate_xchg_v2(); this->deobfuscate_arithmetics(); this->deobfuscate_offset(); this->deobfuscate_generated_memory(); this->deobfuscate_generated_register(); this->deobfuscate_neg(); if (pre_deobfuscation_size == this->size()) this->deobfuscate_mov_v2(); } while (pre_deobfuscation_size != this->size()); } void instruction_container_deobfuscator::deobfuscate_wild() { uint32_t pre_deobfuscation_size = 0; do { pre_deobfuscation_size = this->size(); this->deobfuscate_push(); this->deobfuscate_pop(); this->deobfuscate_stack(); this->deobfuscate_xchg_v1(); this->deobfuscate_mov_v1(); this->deobfuscate_xchg_v2(); this->deobfuscate_arithmetics(); this->deobfuscate_offset(); this->deobfuscate_generated_memory(); this->deobfuscate_generated_register(); this->deobfuscate_neg(); if (pre_deobfuscation_size == this->size()) { this->deobfuscate_mov_v2(); if (pre_deobfuscation_size == this->size()) { this->deobfuscate_fillers(); //if (pre_deobfuscation_size == instructions.size()) // this->deobfuscate_new_types(instructions); } } } while (pre_deobfuscation_size != this->size()); } void instruction_container_deobfuscator::deobfuscate_push() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: sub esp,02/04 1: mov (d)word ptr [esp],reg */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Isub) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base(0, UD_R_ESP) && this->at(i).is_operand_type(1, UD_OP_IMM) && this->at(i).is_operand_data(1, { 2, 4 }) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, { UD_SIZE_WORD, UD_SIZE_DWORD }) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 1).has_operand_data_not(0) && this->at(i + 1).is_operand_type(1, UD_OP_REG)) { /* 1: mov (d)word ptr [esp],(e)sp */ if (this->at(i + 1).is_operand_base(1, { UD_R_SP, UD_R_ESP })) { /* 2: add unknown ptr [esp],02/04 */ if (this->bounds(i, 2) && this->at(i + 2).is_mnemonic(UD_Iadd) && this->at(i + 2).is_operand_type(0, UD_OP_MEM) && this->at(i + 2).is_operand_base(0, UD_R_ESP) && this->at(i + 2).has_operand_index_not(0) && this->at(i + 2).has_operand_scale_not(0) && this->at(i + 2).has_operand_data_not(0) && this->at(i + 2).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_operand_data(1, { 2, 4 })) { /* 0: push esp */ this->at(i).set_mnemonic(UD_Ipush); this->at(i).set_prefixes(this->at(i + 1)); this->at(i).set_operand(0, this->at(i + 1), 1); this->at(i).set_operand_null(1); this->remove(i + 1, 2); } } else { /* 0: push reg */ this->at(i).set_mnemonic(UD_Ipush); this->at(i).set_prefixes(this->at(i + 1)); this->at(i).set_operand(0, this->at(i + 1), 1); this->at(i).set_operand_null(1); this->remove(i + 1); } } /* 0: push reg/imm 1: mov (d)word ptr [esp],reg */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_IMM }) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, { UD_SIZE_WORD, UD_SIZE_DWORD }) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 1).has_operand_data_not(0) && this->at(i + 1).is_operand_type(1, UD_OP_REG)) { /* 1: mov (d)word ptr [esp],(e)sp */ if (this->at(i + 1).is_operand_base(1, { UD_R_SP, UD_R_ESP })) { /* 2: add unknown ptr [esp],02/04 */ if (this->bounds(i, 2) && this->at(i + 2).is_mnemonic(UD_Iadd) && this->at(i + 2).is_operand_type(0, UD_OP_MEM) && this->at(i + 2).is_operand_base(0, UD_R_ESP) && this->at(i + 2).has_operand_index_not(0) && this->at(i + 2).has_operand_scale_not(0) && this->at(i + 2).has_operand_data_not(0) && this->at(i + 2).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_operand_data(1, { 2, 4 })) { /* 0: push esp */ this->at(i).set_mnemonic(UD_Ipush); this->at(i).set_prefixes(this->at(i + 1)); this->at(i).set_operand(0, this->at(i + 1), 1); this->remove(i + 1, 2); } } else { /* 0: push reg */ this->at(i).set_mnemonic(UD_Ipush); this->at(i).set_prefixes(this->at(i + 1)); this->at(i).set_operand(0, this->at(i + 1), 1); this->remove(i + 1); } } } } void instruction_container_deobfuscator::deobfuscate_pop() { for (std::size_t i = (this->size() - 1); static_cast(i) >= 0; i--) { /* 0: mov reg,(d)word ptr [esp] 1: add esp,02/04 */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Imov) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base_not(0, { UD_R_SP, UD_R_ESP }) && this->at(i).is_operand_type(1, UD_OP_MEM, { UD_SIZE_WORD, UD_SIZE_DWORD }) && this->at(i).is_operand_base(1, UD_R_ESP) && this->at(i).has_operand_index_not(1) && this->at(i).has_operand_scale_not(1) && this->at(i).has_operand_data_not(1) && this->at(i + 1).is_mnemonic(UD_Iadd) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).is_operand_type(1, UD_OP_IMM) && this->at(i + 1).is_operand_data(1, { 2, 4 })) { /* 0: pop reg */ this->at(i).set_mnemonic(UD_Ipop); this->at(i).set_operand_null(1); this->remove(i + 1); } /* 0: mov (e)sp,(d)word ptr [esp] */ if (this->bounds(i) && this->at(i).is_mnemonic(UD_Imov) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base(0, { UD_R_SP, UD_R_ESP }) && this->at(i).is_operand_type(1, UD_OP_MEM, { UD_SIZE_WORD, UD_SIZE_DWORD }) && this->at(i).is_operand_base(1, UD_R_ESP) && this->at(i).has_operand_index_not(1) && this->at(i).has_operand_scale_not(1) && this->at(i).has_operand_data_not(1)) { /* 0: pop (e)sp */ this->at(i).set_mnemonic(UD_Ipop); this->at(i).set_operand_null(1); } } } void instruction_container_deobfuscator::deobfuscate_stack() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: push (reg != esp) 1: mov reg,esp 2: add reg,04 3: add/sub reg,imm 4: xchg reg/(d)word ptr [esp],reg/(d)word ptr [esp] 5: pop esp */ if (this->bounds(i, 5) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base_not(0, UD_R_ESP) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_base(0, this->at(i), 0) && this->at(i + 1).is_operand_type(1, UD_OP_REG) && this->at(i + 1).is_operand_base(1, UD_R_ESP) && this->at(i + 2).is_mnemonic(UD_Iadd) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_operand_base(0, this->at(i), 0) && this->at(i + 2).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_operand_data(1, 4) && this->at(i + 3).is_mnemonic({ UD_Iadd, UD_Isub }) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand_base(0, this->at(i), 0) && this->at(i + 3).is_operand_type(1, UD_OP_IMM) && this->at(i + 4).is_mnemonic(UD_Ixchg) && ((this->at(i + 4).is_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD) && this->at(i + 4).is_operand_base(0, UD_R_ESP) && this->at(i + 4).has_operand_index_not(0) && this->at(i + 4).has_operand_scale_not(0) && this->at(i + 4).has_operand_data_not(0) && this->at(i + 4).is_operand_type(1, UD_OP_REG) && this->at(i + 4).is_operand_base(1, this->at(i), 0)) || (this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i), 0) && this->at(i + 4).is_operand_type(1, UD_OP_MEM, UD_SIZE_DWORD) && this->at(i + 4).is_operand_base(1, UD_R_ESP) && this->at(i + 4).has_operand_index_not(1) && this->at(i + 4).has_operand_scale_not(1) && this->at(i + 4).has_operand_data_not(1))) && this->at(i + 5).is_mnemonic(UD_Ipop) && this->at(i + 5).is_operand_type(0, UD_OP_REG) && this->at(i + 5).is_operand_base(0, UD_R_ESP)) { /* 0: add/sub esp,imm */ this->at(i).set_mnemonic(this->at(i + 3)); this->at(i).set_operand_type(0, UD_OP_REG, UD_SIZE_DWORD); this->at(i).set_operand_base(0, UD_R_ESP); this->at(i).set_operand_type(1, UD_OP_IMM, UD_SIZE_DWORD); this->at(i).set_operand_data(1, this->at(i + 3), 1); this->remove(i + 1, 5); } } } void instruction_container_deobfuscator::deobfuscate_xchg_v1() { for (std::size_t i = (this->size() - 1); static_cast(i) >= 0; i--) { /* 0: xor x1,x2 1: xor x2,x1 2: xor x1,x2 */ if (this->bounds(i, 2) && this->at(i).is_mnemonic(UD_Ixor) && this->at(i + 1).is_mnemonic(UD_Ixor) && this->at(i + 1).is_operand(0, this->at(i), 1) && this->at(i + 1).is_operand(1, this->at(i), 0) && this->at(i + 2).is_mnemonic(UD_Ixor) && this->at(i + 2).is_operand(0, this->at(i + 1), 1) && this->at(i + 2).is_operand(1, this->at(i + 1), 0)) { /* 0: xchg x1,x2 */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(0, this->at(i + 1), 0); this->at(i).set_operand(1, this->at(i + 2), 0); this->remove(i + 1, 2); } /* 0: push reg 1: mov reg,dword ptr [esp+4] 2: pop dword ptr [esp] */ if (this->bounds(i, 2) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base_not(0, UD_R_ESP) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_base(0, this->at(i), 0) && this->at(i + 1).is_operand_type(1, UD_OP_MEM, UD_SIZE_DWORD) && this->at(i + 1).is_operand_base(1, UD_R_ESP) && this->at(i + 1).has_operand_index_not(1) && this->at(i + 1).has_operand_scale_not(1) && this->at(i + 1).is_operand_data(1, 4) && this->at(i + 2).is_mnemonic(UD_Ipop) && this->at(i + 2).is_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD) && this->at(i + 2).is_operand_base(0, UD_R_ESP) && this->at(i + 2).has_operand_index_not(0) && this->at(i + 2).has_operand_scale_not(0) && this->at(i + 2).has_operand_data_not(0)) { /* 0: xchg reg,dword ptr [esp] */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(1, this->at(i + 2), 0); this->remove(i + 1, 2); } /* 0: push reg1 1: mov reg1,x2 2: mov x2,x3 3: mov x3,reg1 4: pop reg1 */ if (this->bounds(i, 4) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_mnemonic(UD_Imov) && this->at(i + 2).is_operand(0, this->at(i + 1), 1) && this->at(i + 3).is_mnemonic(UD_Imov) && this->at(i + 3).is_operand(0, this->at(i + 2), 1) && this->at(i + 3).is_operand_type(1, UD_OP_REG) && this->at(i + 3).is_operand(1, this->at(i + 1), 0) && this->at(i + 4).is_mnemonic(UD_Ipop) && this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i), 0)) { /* 0: xchg x2,x3 */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_prefixes(this->at(i + 3)); this->at(i).set_operand(0, this->at(i + 3), 0); this->at(i).set_operand(1, this->at(i + 2), 0); if (this->at(i).is_operand_type(0, UD_OP_MEM) && this->at(i).is_operand_base(0, UD_R_ESP)) this->at(i).dec_operand_data(0, this->at(i + 4).is_operand_base_size(0, UD_SIZE_DWORD) ? 4 : 2); if (this->at(i).is_operand_type(1, UD_OP_MEM) && this->at(i).is_operand_base(1, UD_R_ESP)) this->at(i).dec_operand_data(1, this->at(i + 4).is_operand_base_size(0, UD_SIZE_DWORD) ? 4 : 2); this->remove(i + 1, 4); } } } void instruction_container_deobfuscator::deobfuscate_mov_v1() { for (std::size_t i = (this->size() - 1); static_cast(i) >= 0; i--) { /* 0: push x1 1: pop x2 */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i + 1).is_mnemonic(UD_Ipop) && ((this->at(i).is_operand_type(0, UD_OP_REG, UD_SIZE_DWORD) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD)) || (this->at(i).is_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD) && this->at(i + 1).is_operand_type(0, UD_OP_REG, UD_SIZE_DWORD)) || (this->at(i).is_operand_type(0, UD_OP_REG, UD_SIZE_WORD) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, UD_SIZE_WORD)) || (this->at(i).is_operand_type(0, UD_OP_MEM, UD_SIZE_WORD) && this->at(i + 1).is_operand_type(0, UD_OP_REG, UD_SIZE_WORD)) || (this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(0, UD_OP_REG)) || (this->at(i).is_operand_type(0, UD_OP_IMM, UD_SIZE_DWORD) && this->at(i + 1).is_operand_type(0, UD_OP_REG)) || (this->at(i).is_operand_type(0, UD_OP_IMM, UD_SIZE_WORD) && this->at(i + 1).is_operand_type(0, UD_OP_REG)))) { /* 0: mov x2,x1 */ this->at(i).set_mnemonic(UD_Imov); this->at(i).set_operand(1, this->at(i), 0); this->at(i).set_operand(0, this->at(i + 1), 0); this->remove(i + 1); } /* 0: push x1 1: sub|add|xor unknown ptr [esp],imm 2: pop x2 3: add|sub|xor x2,imm */ if (this->bounds(i, 3) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && ((this->at(i + 1).is_mnemonic(UD_Isub) && this->at(i + 3).is_mnemonic(UD_Iadd)) || (this->at(i + 1).is_mnemonic(UD_Iadd) && this->at(i + 3).is_mnemonic(UD_Isub)) || (this->at(i + 1).is_mnemonic(UD_Ixor) && this->at(i + 3).is_mnemonic(UD_Ixor))) && this->at(i + 1).is_operand_type(0, UD_OP_MEM) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 1).has_operand_data_not(0) && this->at(i + 1).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_mnemonic(UD_Ipop) && this->at(i + 2).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 3).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 3).is_operand(0, this->at(i + 2), 0) && this->at(i + 3).is_operand_type(1, UD_OP_IMM) && this->at(i + 3).is_operand_data(1, this->at(i + 1), 1)) { /* 0: mov x2,x1 */ this->at(i).set_mnemonic(UD_Imov); this->at(i).set_operand(1, this->at(i), 0); this->at(i).set_operand(0, this->at(i + 2), 0); this->remove(i + 1, 3); } /* 0: push reg 1: mov reg,imm 2: mov x2,imm 3: ___ x2,reg 4: pop reg */ if (this->bounds(i, 4) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_mnemonic(UD_Imov) && this->at(i + 2).is_operand_type(1, UD_OP_IMM) && this->at(i + 3).compare_mnemonic(true, false, true) && this->at(i + 3).is_operand_sib(0, this->at(i + 2), 0) && this->at(i + 3).is_operand_data(0, this->at(i + 2), 0) && this->at(i + 3).is_operand_type(1, UD_OP_REG) && this->at(i + 3).is_operand(1, this->at(i + 1), 0) && this->at(i + 4).is_mnemonic(UD_Ipop) && this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i), 0)) { /* 0: mov x2,imm */ uint32_t imm_product = this->at(i + 2).get_operand_data(1); if (this->at(i + 3).is_operand_type(0, UD_OP_REG)) instruction::emulate(this->at(i + 3).get_mnemonic(), this->at(i + 3).get_base_size(0), this->at(i + 1).get_operand_data(1), &imm_product); else if (this->at(i + 3).is_operand_type(0, UD_OP_MEM)) { /* 3: ___ [esp+xx],x1 */ if (this->at(i + 3).is_operand_base(0, UD_R_ESP)) this->at(i + 3).dec_operand_data(0, this->at(i).is_operand_base_size(0, UD_SIZE_DWORD) ? 4 : 2); instruction::emulate(this->at(i + 3).get_mnemonic(), this->at(i + 3).get_operand_size(0), this->at(i + 1).get_operand_data(1), &imm_product); } this->at(i).set_mnemonic(UD_Imov); this->at(i).set_prefixes(this->at(i + 3)); this->at(i).set_operand(0, this->at(i + 3), 0); this->at(i).set_operand(1, this->at(i + 1), 1); this->at(i).set_operand_data(1, imm_product); this->remove(i + 1, 4); } /* 0: push reg 1: mov reg,imm 2: mov x,imm 3: ___ x,reg 4: ___ x,imm 5: pop reg */ if (this->bounds(i, 5) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_mnemonic(UD_Imov) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_operand_type(1, UD_OP_IMM) && this->at(i + 3).compare_mnemonic(true, false, true) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand_base_not(0, this->at(i + 1), 0) && this->at(i + 3).is_operand_base(0, this->at(i + 2), 0) && this->at(i + 3).is_operand_type(1, UD_OP_REG) && this->at(i + 3).is_operand_base(1, this->at(i + 1), 0) && this->at(i + 4).compare_mnemonic(true, false, true) && this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i + 3), 0) && this->at(i + 4).is_operand_type(1, { UD_OP_IMM, UD_OP_CONST }) && this->at(i + 5).is_mnemonic(UD_Ipop) && this->at(i + 5).is_operand_type(0, UD_OP_REG) && this->at(i + 5).is_operand_base(0, this->at(i), 0)) { /* 0: mov reg2,imm */ uint32_t imm_product = this->at(i + 2).get_operand_data(1); instruction::emulate(this->at(i + 3).get_mnemonic(), this->at(i + 3).get_base_size(0), this->at(i + 1).get_operand_data(1), &imm_product); instruction::emulate(this->at(i + 4).get_mnemonic(), this->at(i + 4).get_base_size(0), this->at(i + 4).get_operand_data(1), &imm_product); this->at(i).set_mnemonic(UD_Imov); this->at(i).set_prefixes(this->at(i + 3)); this->at(i).set_operand(0, this->at(i + 3), 0); this->at(i).set_operand(1, this->at(i + 1), 1); this->at(i).set_operand_data(1, imm_product); this->remove(i + 1, 5); } } } void instruction_container_deobfuscator::deobfuscate_xchg_v2() { for (std::size_t i = (this->size() - 1); static_cast(i) >= 0; i--) { /* 0: xchg x1,x2 1: ___ ___,___ 2: xchg x1,x2 */ if (this->at(i).is_mnemonic(UD_Ixchg) && this->at(i + 1).compare_mnemonic(false, true, true) && this->at(i + 2).is_mnemonic(UD_Ixchg) && ((this->at(i + 2).is_operand(0, this->at(i), 0) && this->at(i + 2).is_operand(1, this->at(i), 1)) || (this->at(i + 2).is_operand(0, this->at(i), 1) && this->at(i + 2).is_operand(1, this->at(i), 0)))) { /* 1: ___ x1,(imm) */ if (this->at(i + 1).is_operand(0, this->at(i), 0) && this->at(i + 1).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { /* 0: ___ x2,(imm) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand(0, this->at(i), 1); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } /* 1: ___ x2,(imm) */ else if (this->at(i + 1).is_operand(0, this->at(i), 1) && this->at(i + 1).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { /* 0: ___ x1,(imm) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand(0, this->at(i), 0); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } } /* 0: xchg x1,x2 1: ___ ___,___ 2: ___ ___,___ 3: xchg x1,x2 */ if (this->bounds(i, 3) && this->at(i).is_mnemonic(UD_Ixchg) && this->at(i + 1).compare_mnemonic(false, true, true) && this->at(i + 2).compare_mnemonic(false, true, true) && this->at(i + 3).is_mnemonic(UD_Ixchg) && ((this->at(i + 3).is_operand(0, this->at(i), 0) && this->at(i + 3).is_operand(1, this->at(i), 1)) || (this->at(i + 3).is_operand(0, this->at(i), 1) && this->at(i + 3).is_operand(1, this->at(i), 0)))) { /* 1: ___ x1,(imm) 2: ___ x1,(imm) */ if (this->at(i + 1).is_operand(0, this->at(i), 0) && this->at(i + 1).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST }) && this->at(i + 2).is_operand(0, this->at(i + 1), 0) && this->at(i + 2).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { /* 0: ___ x2,(imm) 1: ___ x2,(imm) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand(0, this->at(i), 1); this->at(i).set_operand(1, this->at(i + 1), 1); this->at(i + 1).set_mnemonic(this->at(i + 2)); this->at(i + 1).set_operand(0, this->at(i), 0); this->at(i + 1).set_operand(1, this->at(i + 2), 1); this->remove(i + 2, 2); } /* 1: ___ x2,imm */ else if (this->at(i + 1).is_operand(0, this->at(i), 1) && this->at(i + 1).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { /* 0: ___ x1,(imm) 1: ___ x1,___ */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand(0, this->at(i), 0); this->at(i).set_operand(1, this->at(i + 1), 1); this->at(i + 1).set_mnemonic(this->at(i + 2)); this->at(i + 1).set_operand(0, this->at(i), 0); this->at(i + 1).set_operand(1, this->at(i + 2), 1); this->remove(i + 2, 2); } } /* 0: push ___ 1: mov ___,___ 2: pop ___ */ if (this->bounds(i, 2) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 2).is_mnemonic(UD_Ipop)) { /* 0: push reg 1: mov ___,reg */ if (this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_REG)) { /* 0: push x1 1: mov x1,x2 2: pop x2 */ if (this->at(i + 1).is_operand(0, this->at(i), 0) && this->at(i + 2).is_operand(0, this->at(i + 1), 1)) { /* 0: xchg x1,x2 */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } } /* 0: push unknown ptr [mem] 1: mov ___,reg */ else if (this->at(i).is_operand_type(0, UD_OP_MEM) && this->at(i + 1).is_operand_type(1, UD_OP_REG)) { /* 0: push unknown ptr [mem] 1: mov unknown ptr [mem],reg 2: pop reg */ if (this->at(i + 1).is_operand_type(0, this->at(i), 0) && this->at(i + 2).is_operand(0, this->at(i + 1), 1)) { /* 0: push (d)word ptr [esp+xx] 1: mov (d)word ptr [esp+xx+02/04],reg 2: pop reg */ if (this->at(i).is_operand_base(0, UD_R_ESP) && this->at(i).is_operand_index(0, this->at(i + 1), 0) && this->at(i).is_operand_scale(0, this->at(i + 1), 0) && this->at(i).is_operand_data(0, this->at(i + 1).get_operand_data(0) + (this->at(i).is_operand_size(0, UD_SIZE_DWORD) ? 4 : 2))) { /* 0: xchg (d)word ptr [esp+xx],reg */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } /* 0: push unknown ptr [mem] 1: mov unknown ptr [mem],reg 2: pop reg */ else if (this->at(i).is_operand(0, this->at(i + 1), 0)) { /* 0: xchg unknown ptr [mem],reg */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } } } /* 0: push reg 1: mov ___,unknown ptr [mem] */ else if (this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_MEM)) { /* 0: push reg 1: mov reg,unknown ptr [mem] 2: pop unknown ptr [mem] */ if (this->at(i + 1).is_operand(0, this->at(i), 0) && this->at(i + 2).is_operand_type(0, this->at(i + 1), 1)) { /* 0: push reg 1: mov reg,(d)word ptr [esp+xx+04] 2: pop (d)word ptr [esp+xx] */ if (this->at(i + 1).is_operand_base(1, UD_R_ESP) && this->at(i + 1).is_operand_index(1, this->at(i + 2), 0) && this->at(i + 1).is_operand_scale(1, this->at(i + 2), 0) && this->at(i + 1).is_operand_data(1, this->at(i + 2).get_operand_data(0) + (this->at(i + 1).is_operand_size(1, UD_SIZE_DWORD) ? 4 : 2))) { /* 0: xchg reg,(d)word ptr [esp+xx] */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(1, this->at(i + 2), 0); this->remove(i + 1, 2); } /* 0: push reg 1: mov reg,unknown ptr [mem] 2: pop unknown ptr [mem] */ else if (this->at(i + 1).is_operand(1, this->at(i + 2), 0)) { /* 0: xchg reg,unknown ptr [mem] */ this->at(i).set_mnemonic(UD_Ixchg); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } } } } } } void instruction_container_deobfuscator::deobfuscate_arithmetics() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: push reg 1: mov reg,x1 2: ___ x2,reg 3: pop reg */ if (this->bounds(i, 3) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 2).compare_mnemonic(true, false, true) && this->at(i + 2).is_operand_type(1, UD_OP_REG) && this->at(i + 2).is_operand_base(1, this->at(i + 1), 0) && this->at(i + 3).is_mnemonic(UD_Ipop) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand_base(0, this->at(i), 0)) { /* 0: ___ x2,x1 */ if (this->at(i + 2).is_operand_type(0, UD_OP_MEM) && this->at(i + 2).is_operand_base(0, UD_R_ESP)) this->at(i + 2).dec_operand_data(0, this->at(i).is_operand_base_size(0, UD_SIZE_DWORD) ? 4 : 2); this->at(i).set_mnemonic(this->at(i + 2)); this->at(i).set_prefixes(this->at(i + 2)); this->at(i).set_operand(0, this->at(i + 2), 0); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 3); } /* 0: push reg/unknown ptr [mem] 1: ___ esp/unknown ptr [esp+xx],(___) 2: pop reg/unknown ptr [mem] */ if (this->bounds(i, 2) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 1).compare_mnemonic(false, true, true) && this->at(i + 1).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 2).is_mnemonic(UD_Ipop) && this->at(i + 2).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 2).is_operand(0, this->at(i), 0)) { /* 0: push reg 1: ___ byte ptr [esp+01],(___) */ if (this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base_family(0, { UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX }) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, UD_SIZE_BYTE) && this->at(i + 1).is_operand_data(0, 1)) { /* 0: ___ reg,(___) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand_type(0, this->at(i + 2), 0); this->at(i).set_operand_size(0, UD_SIZE_BYTE); this->at(i).set_operand_base(0, this->at(i + 2).get_base_high_type(0)); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } /* 1: ___ esp/unknown ptr [esp],(___) */ else if (this->at(i + 1).has_operand_data_not(0)) { /* 0: ___ reg/unknown ptr [mem],(___) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_prefixes(this->at(i + 1)); this->at(i).set_operand_type(0, this->at(i + 2), 0); if (this->at(i + 2).is_operand_type(0, UD_OP_REG)) { this->at(i).set_operand_size(0, this->at(i + 1).get_operand_size(0)); this->at(i).set_operand_base(0, this->at(i + 2).get_base_size_type(0, this->at(i + 1).get_operand_size(0))); } else { this->at(i).set_operand_type(0, this->at(i + 2).get_operand_type(0), this->at(i + 1).get_operand_size(0)); } this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } } /* 0: push reg 1: ___ esp/unknown ptr [esp+xx],(___) 2: ___ esp/unknown ptr [esp+xx],(___) 3: pop reg */ if (this->bounds(1, 3) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i + 1).compare_mnemonic(false, true, true) && this->at(i + 1).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 2).compare_mnemonic(false, true, true) && this->at(i + 2).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 2).is_operand(0, this->at(i + 1), 0) && this->at(i + 3).is_mnemonic(UD_Ipop) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand(0, this->at(i), 0)) { /* 0: push reg 1: ___ byte ptr [esp+01],(___) 2: ___ byte ptr [esp+01],(___) */ if (this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_base_family(0, { UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX }) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, UD_SIZE_BYTE) && this->at(i + 1).is_operand_data(0, 1)) { /* 0: ___ byte ptr reg,(___) 1: ___ byte ptr reg,(___) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand_type(0, this->at(i + 3), 0); this->at(i).set_operand_size(0, UD_SIZE_BYTE); this->at(i).set_operand_base(0, this->at(i + 3).get_base_high_type(0)); this->at(i).set_operand(1, this->at(i + 1), 1); this->at(i + 1).set_mnemonic(this->at(i + 2)); this->at(i + 1).set_operand_type(0, this->at(i + 3), 0); this->at(i + 1).set_operand_size(0, UD_SIZE_BYTE); this->at(i + 1).set_operand_base(0, this->at(i + 3).get_base_high_type(0)); this->at(i + 1).set_operand(1, this->at(i + 2), 1); this->remove(i + 2, 2); } /* 1: ___ esp/unknown ptr [esp],(___) */ else if (this->at(i + 1).has_operand_data_not(0)) { /* 0: ___ unknown ptr reg,(___) 1: ___ unknown ptr reg,(___) */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_prefixes(this->at(i + 1)); this->at(i).set_operand_type(0, this->at(i + 3), 0); if (this->at(i + 3).is_operand_type(0, UD_OP_REG)) { this->at(i).set_operand_size(0, this->at(i + 1).get_operand_size(0)); this->at(i).set_operand_base(0, this->at(i + 3).get_base_size_type(0, this->at(i + 1).get_operand_size(0))); this->at(i).set_operand_index_null(0); this->at(i).set_operand_scale_null(0); this->at(i).set_operand_data_null(0); } else { this->at(i).set_operand_type(0, this->at(i + 3).get_operand_type(0), this->at(i + 1).get_operand_size(0)); } this->at(i).set_operand(1, this->at(i + 1), 1); this->at(i + 1).set_mnemonic(this->at(i + 2)); this->at(i + 1).set_prefixes(this->at(i + 2)); this->at(i + 1).set_operand_type(0, this->at(i + 3), 0); if (this->at(i + 3).is_operand_type(0, UD_OP_REG)) { this->at(i + 1).set_operand_size(0, this->at(i + 2).get_operand_size(0)); this->at(i + 1).set_operand_base(0, this->at(i + 3).get_base_size_type(0, this->at(i + 2).get_operand_size(0))); this->at(i + 1).set_operand_index_null(0); this->at(i + 1).set_operand_scale_null(0); this->at(i + 1).set_operand_data_null(0); } else { this->at(i + 1).set_operand_type(0, this->at(i + 3).get_operand_type(0), this->at(i + 2).get_operand_size(0)); } this->at(i + 1).set_operand(1, this->at(i + 2), 1); this->remove(i + 2, 2); } } /* 0: push reg 1: mov reg,x 2: ___ reg,___ 3: mov x,reg 4: pop reg */ if (this->bounds(1, 4) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_REG) && (this->at(i + 2).compare_mnemonic(false, true, true) || this->at(i + 2).compare_immediate()) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_mnemonic(UD_Imov) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand_base(0, this->at(i + 1), 1) && this->at(i + 3).is_operand_type(1, UD_OP_REG) && this->at(i + 3).is_operand_base(1, this->at(i + 1), 0) && this->at(i + 3).is_operand_base(1, this->at(i + 2), 0) && this->at(i + 4).is_mnemonic(UD_Ipop) && this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i), 0)) { /* 0: ___ x,___ */ this->at(i).set_mnemonic(this->at(i + 2)); this->at(i).set_prefixes(this->at(i + 2)); this->at(i).set_operand(0, this->at(i + 3), 0); this->at(i).set_operand(1, this->at(i + 2), 1); this->remove(i + 1, 4); } } } void instruction_container_deobfuscator::deobfuscate_offset() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: add|sub x1,imm 1: add/sub x1,___ 2: sub|add x1,imm */ if (this->bounds(i, 2) && ((this->at(i).is_mnemonic(UD_Iadd) && this->at(i + 2).is_mnemonic(UD_Isub)) || (this->at(i).is_mnemonic(UD_Isub) && this->at(i + 2).is_mnemonic(UD_Iadd))) && this->at(i).is_operand_type(1, UD_OP_IMM) && this->at(i + 1).is_mnemonic({ UD_Iadd, UD_Isub }) && this->at(i + 1).is_operand(0, this->at(i), 0) && this->at(i + 1).is_operand_type_not(1, UD_OP_IMM) && this->at(i + 2).is_operand(0, this->at(i + 1), 0) && this->at(i + 2).is_operand_type(1, UD_OP_IMM) && this->at(i + 2).is_operand_data(1, this->at(i), 1)) { /* 0: add/sub x1,___ */ this->at(i).set_mnemonic(this->at(i + 1)); this->at(i).set_operand(1, this->at(i + 1), 1); this->remove(i + 1, 2); } } } void instruction_container_deobfuscator::deobfuscate_generated_memory() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: push reg 1: mov reg,reg/imm */ if (this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, { UD_OP_REG, UD_OP_IMM })) { /* 1: mov reg,reg */ if (this->at(i + 1).is_operand_type(1, UD_OP_REG) && this->at(i + 1).is_operand_base(1, this->at(i + 1), 0)) { continue; } /* 1: mov regx,reg/imm */ if (this->at(i + 1).is_operand_base(0, this->at(i), 0)) { ud_type base_type = UD_NONE; uint32_t registers = 0; /* 0: push regx 1: mov regx,regb */ if (this->at(i + 1).is_operand_base(0, this->at(i), 0) && this->at(i + 1).is_operand_type(1, UD_OP_REG) && this->at(i + 1).is_operand_base_not(1, this->at(i + 1), 0)) { base_type = this->at(i + 1).get_base_type(1); registers++; } bool is_valid = true; std::size_t j = 0; std::size_t index = 0; for (j = 0; j < (this->size() - (i + 2)); j++) { index = (i + 2 + j); /* 2+j: ___ ___,___ */ if (!this->at(index).compare_mnemonic(true, true, true)) { is_valid = false; break; } /* 2+j: (___ != mov) reg,(imm) */ if (this->at(index).is_mnemonic_not(UD_Imov) && this->at(index).is_operand_type(0, UD_OP_REG) && this->at(index).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { /* 2+j: (___ != mov) (reg != regx),(imm) */ if (this->at(index).is_operand_base_not(0, this->at(i + 1), 0)) { is_valid = false; break; } } /* 2+j: (___ != mov) reg,reg */ else if (this->at(index).is_mnemonic_not(UD_Imov) && this->at(index).is_operand_type(0, UD_OP_REG) && this->at(index).is_operand_type(1, UD_OP_REG) && this->at(index).is_operand_base_not(1, this->at(index), 0)) { /* 2+j: (___ != mov) (reg != regx),reg */ if (this->at(index).is_operand_base_not(0, this->at(i + 1), 0)) { is_valid = false; break; } base_type = this->at(index).get_base_type(1); registers++; } else { /* 2+j: ___ reg,unknown ptr [mem] */ if (this->at(index).is_operand_type(0, UD_OP_REG) && this->at(index).is_operand_type(1, UD_OP_MEM)) { /* 2+j: ___ reg,unknown ptr [regx] 2+j+1: pop regx */ if (this->bounds(index, 1) && (this->at(index).is_operand_base(0, this->at(i + 1), 0) || this->at(index).is_operand_base_not(1, this->at(i + 1), 0) || this->at(index).has_operand_index(1) || this->at(index).has_operand_scale(1) || this->at(index).has_operand_data(1) || this->at(index + 1).is_mnemonic_not(UD_Ipop) || this->at(index + 1).is_operand_type_not(0, UD_OP_REG) || this->at(index + 1).is_operand_base_not(0, this->at(index), 1) || this->at(index + 1).is_operand_base_not(0, this->at(i), 0))) { is_valid = false; } } /* 2+j: ___ unknown ptr [mem],reg */ else if (this->at(index).is_operand_type(0, UD_OP_MEM) && this->at(index).is_operand_type(1, UD_OP_REG)) { /* 2+j: ___ unknown ptr [regx],reg 2+j+1: pop regx */ if (this->bounds(index, 1) && (this->at(index).is_operand_base(1, this->at(i + 1), 0) || this->at(index).is_operand_base_not(0, this->at(i + 1), 0) || this->at(index).has_operand_index(0) || this->at(index).has_operand_scale(0) || this->at(index).has_operand_data(0) || this->at(index + 1).is_mnemonic_not(UD_Ipop) || this->at(index + 1).is_operand_type_not(0, UD_OP_REG) || this->at(index + 1).is_operand_base_not(0, this->at(index), 0) || this->at(index + 1).is_operand_base_not(0, this->at(i), 0))) { is_valid = false; } } /* 2+j: ___ unknown ptr [mem],imm */ else if (this->at(index).is_operand_type(0, UD_OP_MEM) && this->at(index).is_operand_type(1, { UD_OP_IMM, UD_OP_CONST })) { /* 2+j: ___ unknown ptr [regx],imm 2+j+1: pop regx */ if (this->bounds(index, 1) && (this->at(index).is_operand_base_not(0, this->at(i + 1), 0) || this->at(index).has_operand_index(0) || this->at(index).has_operand_scale(0) || this->at(index).has_operand_data(0) || this->at(index + 1).is_mnemonic_not(UD_Ipop) || this->at(index + 1).is_operand_type_not(0, UD_OP_REG) || this->at(index + 1).is_operand_base_not(0, this->at(index), 0) || this->at(index + 1).is_operand_base_not(0, this->at(i), 0))) { is_valid = false; } } else { is_valid = false; } break; } } if (is_valid && registers == 1) { this->at(i).set_mnemonic(this->at(index)); this->at(i).set_prefixes(this->at(index)); uint32_t imm_product = 0; ud_size imm_size = UD_SIZE_NONE; for (std::size_t k = 0; k < (j + 1); k++) { if (this->at(i + 1 + k).is_operand_type_not(1, UD_OP_REG)) { if (k == 0) imm_product = this->at(i + 1).get_operand_data(1); else instruction::emulate(this->at(i + 1 + k).get_mnemonic(), this->at(i + 1).get_base_size(0), this->at(i + 1 + k).get_operand_data(1), &imm_product); } } if (this->at(index).is_operand_type(1, UD_OP_MEM)) { /* 0: ___ reg,unknown ptr [regb+d] ; b = regb, d = imm (product) */ this->at(i).set_operand(0, this->at(index), 0); this->at(i).set_operand(1, this->at(index), 1); this->at(i).set_operand_base(1, base_type); this->at(i).set_operand_index_null(1); this->at(i).set_operand_scale_null(1); this->at(i).set_operand_offset(1, UD_SIZE_DWORD); this->at(i).set_operand_data(1, imm_product); } else { /* 0: ___ unknown ptr [regb+d],___ ; b = regb, d = imm (product) */ this->at(i).set_operand(0, this->at(index), 0); this->at(i).set_operand_base(0, base_type); this->at(i).set_operand_index_null(0); this->at(i).set_operand_scale_null(0); this->at(i).set_operand_offset(0, UD_SIZE_DWORD); this->at(i).set_operand_data(0, imm_product); this->at(i).set_operand(1, this->at(index), 1); } this->remove(i + 1, 2 + j + 1); } } } /* 0: push reg (x) 1: mov x,reg (i) 2: shl x,imm (s) 3: add x,imm (d) 4: add x,reg (b) 5: ___ ___,unknown ptr [x] 5: ___ unknown ptr [x],___ 6: pop x */ if (this->bounds(1, 6) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_base(0, this->at(i), 0) && this->at(i + 1).is_operand_type(1, UD_OP_REG) && this->at(i + 1).is_operand_base_not(1, this->at(i + 1), 0) && this->at(i + 2).is_mnemonic(UD_Ishl) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_operand_base(0, this->at(i + 1), 0) && this->at(i + 2).is_operand_type(1, { UD_OP_IMM, UD_OP_CONST }) && this->at(i + 3).is_mnemonic(UD_Iadd) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand_base(0, this->at(i + 2), 0) && this->at(i + 3).is_operand_type(1, UD_OP_IMM) && this->at(i + 4).is_mnemonic(UD_Iadd) && this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i + 3), 0) && this->at(i + 4).is_operand_type(1, UD_OP_REG) && this->at(i + 5).compare_mnemonic(true, false, true) && ((this->at(i + 5).is_operand_type(0, UD_OP_MEM) && this->at(i + 5).is_operand_base(0, this->at(i + 2), 0) && this->at(i + 5).has_operand_index_not(0) && this->at(i + 5).has_operand_scale_not(0) && this->at(i + 5).has_operand_data_not(0)) || (this->at(i + 5).is_operand_type(1, UD_OP_MEM) && this->at(i + 5).is_operand_base(1, this->at(i + 2), 0) && this->at(i + 5).has_operand_index_not(1) && this->at(i + 5).has_operand_scale_not(1) && this->at(i + 5).has_operand_data_not(1))) && this->at(i + 6).is_mnemonic(UD_Ipop) && this->at(i + 6).is_operand_type(0, UD_OP_REG) && this->at(i + 6).is_operand_base(0, this->at(i), 0)) { this->at(i).set_mnemonic(this->at(i + 5)); this->at(i).set_prefixes(this->at(i + 5)); /* 5: ___ ___,unknown ptr [mem] */ if (this->at(i + 5).is_operand_type(1, UD_OP_MEM)) { /* 0: ___ ___,unknown ptr [b+i*s+d] */ if (this->at(i + 5).is_operand_base(1, UD_R_ESP)) this->at(i + 5).dec_operand_data(1, this->at(i).get_base_size(0) == UD_SIZE_DWORD ? 4 : 2); this->at(i).set_operand(0, this->at(i + 5), 0); this->at(i).set_operand_type(1, this->at(i + 5), 1); this->at(i).set_operand_base(1, this->at(i + 4), 1); this->at(i).set_operand_index(1, this->at(i + 1), 1); this->at(i).set_operand_scale_by_exponent(1, this->at(i + 2).get_operand_data(1)); this->at(i).set_operand_data(1, this->at(i + 3), 1); } /* 5: ___ unknown ptr [mem],___ */ else { /* 0: ___ unknown ptr [b+i*s+d],___ */ if (this->at(i + 5).is_operand_base(0, UD_R_ESP)) this->at(i + 5).dec_operand_data(0, this->at(i).get_base_size(0) == UD_SIZE_DWORD ? 4 : 2); this->at(i).set_operand(1, this->at(i + 5), 1); this->at(i).set_operand_type(0, this->at(i + 5), 0); this->at(i).set_operand_base(0, this->at(i + 4), 1); this->at(i).set_operand_index_by_base(0, this->at(i + 1), 1); this->at(i).set_operand_scale_by_exponent(0, this->at(i + 2).get_operand_data(1)); this->at(i).set_operand_data(0, this->at(i + 3), 1); } this->remove(i + 1, 6); } } } void instruction_container_deobfuscator::deobfuscate_generated_register() { for (std::size_t i = (this->size() - 1); static_cast(i) >= 0; i--) { /* 0: push reg 1: mov reg,imm */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_IMM)) { bool is_valid = true; std::size_t j = 0; std::size_t index = 0; for (j = 0; j < (this->size() - (i + 2)); j++) { index = (i + 2 + j); /* 2+j: ___ ___,___ */ if (this->at(index).compare_mnemonic_not(true, true, true)) { is_valid = false; break; } /* 2+j: (___ != mov) reg,(imm) */ if (this->at(index).is_mnemonic_not(UD_Imov) && this->at(index).is_operand_type(0, UD_OP_REG) && this->at(index).is_operand_type(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { if (this->at(index).is_operand_base_not(0, this->at(i + 1), 0)) { is_valid = false; break; } } else { /* 2+j: ___ reg,reg */ if (this->at(index).is_operand_type(0, UD_OP_REG) && this->at(index).is_operand_type(1, UD_OP_REG)) { if (this->bounds(index, 1) && this->at(index).is_operand_base(0, this->at(i + 1), 0) || this->at(index + 1).is_mnemonic_not(UD_Ipop) || this->at(index + 1).is_operand_type_not(0, UD_OP_REG) || this->at(index + 1).is_operand_base_not(0, this->at(i), 0) || this->at(index + 1).compare_base_not(0, this->at(index), 1)) { is_valid = false; } } /* 2+j: ___ unknown ptr [mem],reg */ else if (this->at(index).is_operand_type(0, UD_OP_MEM) && this->at(index).is_operand_type(1, UD_OP_REG)) { if (this->bounds(index, 1) && this->at(index + 1).is_mnemonic_not(UD_Ipop) || this->at(index + 1).is_operand_type_not(0, UD_OP_REG) || this->at(index + 1).is_operand_base_not(0, this->at(i), 0) || this->at(index + 1).compare_base_not(0, this->at(index), 1)) { is_valid = false; } } else { is_valid = false; } break; } } if (is_valid) { this->at(i).set_mnemonic(this->at(index)); this->at(i).set_prefixes(this->at(index)); this->at(i).set_operand(0, this->at(index), 0); this->at(i).set_operand(1, this->at(i + 1), 1); uint32_t imm_product = this->at(i + 1).get_operand_data(1); for (std::size_t k = 0; k < j; k++) instruction::emulate(this->at(i + 2 + k).get_mnemonic(), this->at(i + 1).get_base_size(0), this->at(i + 2 + k).get_operand_data(1), &imm_product); this->at(i).set_operand_data(1, imm_product); if (this->at(i).is_operand_type(0, UD_OP_MEM) && this->at(i).is_operand_base(0, UD_R_ESP)) this->at(i).dec_operand_data(0, this->at(index + 1).is_operand_base_size(0, UD_SIZE_DWORD) ? 4 : 2); this->remove(i + 1, 2 + j + 1); } } } } void instruction_container_deobfuscator::deobfuscate_neg() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: push 0 1: sub unknown ptr [esp],reg 2: pop reg */ if (this->bounds(i, 2) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_IMM) && this->at(i).is_operand_data(0, 0) && this->at(i + 1).is_mnemonic(UD_Isub) && this->at(i + 1).is_operand_type(0, UD_OP_MEM) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 1).has_operand_data_not(0) && this->at(i + 1).is_operand_type(1, UD_OP_REG) && this->at(i + 1).is_operand_base_not(1, UD_R_ESP) && this->at(i + 2).is_mnemonic(UD_Ipop) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_operand_base(0, this->at(i + 1), 1)) { /* 0: neg reg */ this->at(i).set_mnemonic(UD_Ineg); this->at(i).set_operand(0, this->at(i + 1), 1); this->remove(i + 1, 2); } /* 0: not ___ */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Inot)) { /* 1: inc ___ */ if (this->at(i + 1).is_mnemonic(UD_Iinc)) { /* 0: not reg/unknown ptr [mem] 1: inc reg/unknown ptr [mem] */ if (this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i).is_operand(0, this->at(i + 1), 0)) { /* 0: neg reg/unknown ptr [mem] */ this->at(i).set_mnemonic(UD_Ineg); this->remove(i + 1); } } /* 1: add ___,___ */ else if (this->at(i + 1).is_mnemonic(UD_Iadd)) { /* 0: not reg/unknown ptr [mem] 1: add reg/unknown ptr [mem],1 */ if (this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i).is_operand(0, this->at(i + 1), 0) && this->at(i + 1).is_operand_type(1, UD_OP_IMM) && this->at(i + 1).is_operand_data(1, 1)) { /* 0: neg reg/unknown ptr [mem] */ this->at(i).set_mnemonic(UD_Ineg); this->remove(i + 1); } } /* 1: sub ___,___ */ else if (this->at(i + 1).is_mnemonic(UD_Isub)) { /* 0: not reg/unknown ptr [mem] 1: sub reg/unknown ptr [mem],-1 */ if (this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i).is_operand(0, this->at(i + 1), 0) && this->at(i + 1).is_operand_type(1, UD_OP_IMM, UD_SIZE_BYTE) && this->at(i + 1).is_operand_data(1, { 255, -1 })) { /* 0: neg reg/unknown ptr [mem] */ this->at(i).set_mnemonic(UD_Ineg); this->remove(i + 1); } } } /* 1: not ___ */ if (this->bounds(i, 1) && this->at(i + 1).is_mnemonic(UD_Inot)) { /* 0: dec ___ */ if (this->at(i).is_mnemonic(UD_Idec)) { /* 0: dec reg/unknown ptr [mem] 1: not reg/unknown ptr [mem] */ if (this->at(i + 1).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 1).is_operand(0, this->at(i), 0)) { /* 0: neg reg/unknown ptr [mem] */ this->at(i).set_mnemonic(UD_Ineg); this->remove(i + 1); } } /* 0: add ___ 1: not ___ */ else if (this->at(i).is_mnemonic(UD_Iadd)) { /* 0: add reg/unknown ptr [mem],255/-1 1: not reg/unknown ptr [mem] */ if (this->at(i).is_operand_type(1, UD_OP_IMM, UD_SIZE_BYTE) && this->at(i).is_operand_data(1, { 255, -1 }) && this->at(i + 1).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 1).is_operand(0, this->at(i), 0)) { /* 0: neg reg/unknown ptr [mem] */ this->at(i).set_mnemonic(UD_Ineg); this->at(i).set_operand_null(1); this->remove(i + 1); } } /* 0: sub ___,___ */ else if (this->at(i).is_mnemonic(UD_Isub)) { /* 0: sub reg/unknown ptr [mem],1 1: not reg/unknown ptr [mem] */ if (this->at(i).is_operand_type(1, UD_OP_IMM) && this->at(i).is_operand_data(1, 1) && this->at(i + 1).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 1).is_operand(0, this->at(i), 0)) { /* 0: neg [mem]/reg */ this->at(i).set_mnemonic(UD_Ineg); this->at(i).set_operand_null(1); this->remove(i + 1); } } } /* 0: push 0 1: sub byte ptr [esp],(reg != esp) 2: mov reg,byte ptr [esp] 3: add esp,02/04 */ if (this->bounds(i, 3) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_IMM) && this->at(i).is_operand_data(0, 0) && this->at(i + 1).is_mnemonic(UD_Isub) && this->at(i + 1).is_operand_type(0, UD_OP_MEM, UD_SIZE_BYTE) && this->at(i + 1).is_operand_base(0, UD_R_ESP) && this->at(i + 1).has_operand_index_not(0) && this->at(i + 1).has_operand_scale_not(0) && this->at(i + 1).has_operand_data_not(0) && this->at(i + 1).is_operand_type(1, UD_OP_REG) && this->at(i + 1).is_operand_base_not(1, UD_R_ESP) && this->at(i + 2).is_mnemonic(UD_Imov) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_operand_base(0, this->at(i + 1), 1) && this->at(i + 2).is_operand_type(1, UD_OP_MEM, UD_SIZE_BYTE) && this->at(i + 2).is_operand_base(1, UD_R_ESP) && this->at(i + 2).has_operand_index_not(1) && this->at(i + 2).has_operand_scale_not(1) && this->at(i + 2).has_operand_data_not(1) && this->at(i + 3).is_mnemonic(UD_Iadd) && this->at(i + 3).is_operand_type(0, UD_OP_REG) && this->at(i + 3).is_operand_base(0, UD_R_ESP) && this->at(i + 3).is_operand_type(1, UD_OP_IMM) && ((this->at(i + 3).is_operand_data(1, 2) && this->at(i).is_operand_size(0, UD_SIZE_WORD)) || (this->at(i + 3).is_operand_data(1, 4) && this->at(i).is_operand_size(0, UD_SIZE_DWORD)))) { /* 0: neg reg */ this->at(i).set_mnemonic(UD_Ineg); this->at(i).set_operand(0, this->at(i + 1), 1); this->remove(i + 1, 3); } /* 0: push reg 1: mov reg,0 2: sub reg,x1 3: mov/xchg reg/unknown ptr [mem],reg/unknown ptr [mem] 4: pop reg */ if (this->bounds(i, 4) && this->at(i).is_mnemonic(UD_Ipush) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).compare_base(0, this->at(i + 1), 0) && this->at(i + 1).is_mnemonic(UD_Imov) && this->at(i + 1).is_operand_type(0, UD_OP_REG) && this->at(i + 1).is_operand_type(1, UD_OP_IMM) && this->at(i + 1).is_operand_data(1, 0) && this->at(i + 2).is_mnemonic(UD_Isub) && this->at(i + 2).is_operand_type(0, UD_OP_REG) && this->at(i + 2).is_operand_base(0, this->at(i + 1), 0) && this->at(i + 2).is_operand_type(1, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 2).is_operand_base_not(1, this->at(i + 2), 0) && this->at(i + 3).is_mnemonic({ UD_Imov, UD_Ixchg }) && this->at(i + 3).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 3).is_operand_type(1, { UD_OP_REG, UD_OP_MEM }) && this->at(i + 4).is_mnemonic(UD_Ipop) && this->at(i + 4).is_operand_type(0, UD_OP_REG) && this->at(i + 4).is_operand_base(0, this->at(i), 0)) { /* 3: mov x1,reg */ if (this->at(i + 3).is_mnemonic(UD_Imov) && this->at(i + 3).is_operand_sib(0, this->at(i + 2), 1) && this->at(i + 3).is_operand_data(0, this->at(i + 2), 1) && this->at(i + 3).is_operand_base(1, this->at(i + 2), 0)) { /* 0: neg x1 */ this->at(i).set_mnemonic(UD_Ineg); this->at(i).set_prefixes(this->at(i + 2)); this->at(i).set_operand(0, this->at(i + 2), 1); this->remove(i + 1, 4); } /* 3: xchg x1|reg,reg|x1 */ else if (this->at(i + 3).is_mnemonic(UD_Ixchg) && ((this->at(i + 3).is_operand(0, this->at(i + 2), 1) && this->at(i + 3).is_operand_base(1, this->at(i + 2), 0)) || (this->at(i + 3).is_operand(1, this->at(i + 2), 1) && this->at(i + 3).is_operand_base(0, this->at(i + 2), 0)))) { /* 0: neg x1 */ this->at(i).set_mnemonic(UD_Ineg); this->at(i).set_prefixes(this->at(i + 2)); this->at(i).set_operand(0, this->at(i + 2), 1); this->remove(i + 1, 4); } } } } void instruction_container_deobfuscator::deobfuscate_mov_v2() { for (std::size_t i = (this->size() - 1); static_cast(i) >= 0; i--) { /* 0: mov reg/unknown ptr [mem],imm 1: (___ != mov) reg/unknown ptr [mem],___ */ if (this->bounds(i, 1) && this->at(i).is_mnemonic(UD_Imov) && this->at(i).is_operand_type(0, { UD_OP_REG, UD_OP_MEM }) && this->at(i).is_operand_type(1, UD_OP_IMM) && this->at(i + 1).is_mnemonic_not(UD_Imov) && this->at(i + 1).is_operand_sib(0, this->at(i), 0) && this->at(i + 1).is_operand_data(0, this->at(i), 0)) { std::size_t j = 0; std::size_t index = 0; for (j = 0; j < (this->size() - (i + 1)); j++) { index = (i + 1 + j); /* ___ reg/unknown ptr [mem],(imm) */ if (this->at(index).compare_mnemonic_not(false, true, true) || this->at(index).is_operand_not(0, this->at(i), 0) || this->at(index).is_operand_type_not(1, { UD_NONE, UD_OP_IMM, UD_OP_CONST })) { break; } } if (j != 0) { uint32_t imm_product = this->at(i).get_operand_data(1); for (std::size_t k = 0; k < j; k++) { if (this->at(i).is_operand_type(0, UD_OP_REG)) instruction::emulate(this->at(i + 1 + k).get_mnemonic(), this->at(i).get_base_size(0), this->at(i + 1 + k).get_operand_data(1), &imm_product); else instruction::emulate(this->at(i + 1 + k).get_mnemonic(), this->at(i).get_operand_size(0), this->at(i + 1 + k).get_operand_data(1), &imm_product); } this->at(i).set_operand_data(1, imm_product); this->remove(i + 1, j); } } } } void instruction_container_deobfuscator::deobfuscate_fillers() { for (std::size_t i = 0; i < this->size(); i++) { /* 0: mov reg,reg */ if (this->at(i).is_mnemonic(UD_Imov) && this->at(i).is_operand_type(0, UD_OP_REG) && this->at(i).is_operand_type(1, UD_OP_REG) && this->at(i).is_operand_base(1, this->at(i), 0)) { this->remove(i--); } //try //{ // /* // 0: pushad // 1: popad // */ // if (instructions.at(i).mnemonic == MNEMONIC_PUSHA && // instructions.at(i + 1).mnemonic == MNEMONIC_POPA) // { // this->remove_instructions(instructions, i, 2); // } //} //catch (std::out_of_range const& e) //{ // UNREFERENCED_PARAMETER(e); // /* Ignore out-of-range exceptions. They occur when (index >= size). */ //} // //try //{ // /* // 0: pushfd // 1: popfd // */ // if (instructions.at(i).mnemonic == MNEMONIC_PUSHF && // instructions.at(i + 1).mnemonic == MNEMONIC_POPF) // { // this->remove_instructions(instructions, i, 2); // } //} //catch (std::out_of_range const& e) //{ // UNREFERENCED_PARAMETER(e); // /* Ignore out-of-range exceptions. They occur when (index >= size). */ //} // //try //{ // /* // 0: push x1 // 1: pop x1 // */ // if (instructions.at(i).mnemonic == MNEMONIC_PUSH && // instructions.at(i + 1).mnemonic == MNEMONIC_POP && // instructions.at(i).operands[0].type == instructions.at(i + 1).operands[0].type && // instructions.at(i).operands[0].size == instructions.at(i + 1).operands[0].size && // instructions.at(i).operands[0].base.type == instructions.at(i + 1).operands[0].base.type && // instructions.at(i).operands[0].base.size == instructions.at(i + 1).operands[0].base.size && // instructions.at(i).operands[0].index.type == instructions.at(i + 1).operands[0].index.type && // instructions.at(i).operands[0].index.size == instructions.at(i + 1).operands[0].index.size && // instructions.at(i).operands[0].scale == instructions.at(i + 1).operands[0].scale && // instructions.at(i).operands[0].data.dword == instructions.at(i + 1).operands[0].data.dword) // { // this->remove_instructions(instructions, i, 2); // } //} //catch (std::out_of_range const& e) //{ // UNREFERENCED_PARAMETER(e); // /* Ignore out-of-range exceptions. They occur when (index >= size). */ //} } } // //void oreans_deobfuscator::deobfuscate_new_types(std::vector& instructions) //{ // for (std::size_t i = 0; i < instructions.size(); i++) // { // try // { // /* // 0: push reg // 1: mov [esp],imm32 // */ // if (instructions.at(i).mnemonic == MNEMONIC_PUSH && // instructions.at(i).operands[0].type == OPERAND_TYPE_REGISTER && // instructions.at(i + 1).mnemonic == MNEMONIC_MOV && // instructions.at(i + 1).operands[0].is_type(OPERAND_TYPE_MEMORY, OPERAND_SIZE_DWORD) && // instructions.at(i + 1).operands[0].has_params(true, false, false, false) && // instructions.at(i + 1).operands[0].base.is_type(REGISTER_ESP, OPERAND_SIZE_DWORD) && // instructions.at(i + 1).operands[1].is_type(OPERAND_TYPE_IMMEDIATE)) // { // /* 0: push imm32 */ // instructions.at(i).mnemonic = MNEMONIC_PUSH; // instructions.at(i).operands[0].set_type(instructions.at(i + 1).operands[1]); // instructions.at(i).operands[0].data.dword = instructions.at(i + 1).operands[1].data.dword; // // this->remove_instructions(instructions, i + 1); // } // } // catch (std::out_of_range const& e) // { // UNREFERENCED_PARAMETER(e); // /* Ignore out-of-range exceptions. They occur when (index >= size). */ // } // } //}