#include namespace vm { namespace instrs { std::pair decrypt_operand(transform::map_t &transforms, std::uint64_t operand, std::uint64_t rolling_key) { const auto generic_decrypt_0 = &transforms[transform::type::generic0]; const auto key_decrypt = &transforms[transform::type::rolling_key]; const auto generic_decrypt_1 = &transforms[transform::type::generic1]; const auto generic_decrypt_2 = &transforms[transform::type::generic2]; const auto generic_decrypt_3 = &transforms[transform::type::generic3]; const auto update_key = &transforms[transform::type::update_key]; if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID) { operand = transform::apply(generic_decrypt_0->operands[0].size, generic_decrypt_0->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_0) ? generic_decrypt_0->operands[1].imm.value.u : 0); } // apply transformation with rolling decrypt key... operand = transform::apply(key_decrypt->operands[0].size, key_decrypt->mnemonic, operand, rolling_key); // apply three generic transformations... operand = transform::apply(generic_decrypt_1->operands[0].size, generic_decrypt_1->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_1) ? generic_decrypt_1->operands[1].imm.value.u : 0); operand = transform::apply(generic_decrypt_2->operands[0].size, generic_decrypt_2->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_2) ? generic_decrypt_2->operands[1].imm.value.u : 0); operand = transform::apply(generic_decrypt_3->operands[0].size, generic_decrypt_3->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_3) ? generic_decrypt_3->operands[1].imm.value.u : 0); // update rolling key... auto result = transform::apply(update_key->operands[0].size, update_key->mnemonic, rolling_key, operand); // update decryption key correctly... switch (update_key->operands[0].size) { case 8: rolling_key = (rolling_key & ~0xFFull) + result; break; case 16: rolling_key = (rolling_key & ~0xFFFFull) + result; break; default: rolling_key = result; break; } return {operand, rolling_key}; } std::pair encrypt_operand(transform::map_t &transforms, std::uint64_t operand, std::uint64_t rolling_key) { transform::map_t inverse; inverse_transforms(transforms, inverse); const auto generic_decrypt_0 = &inverse[transform::type::generic0]; const auto key_decrypt = &inverse[transform::type::rolling_key]; const auto generic_decrypt_1 = &inverse[transform::type::generic1]; const auto generic_decrypt_2 = &inverse[transform::type::generic2]; const auto generic_decrypt_3 = &inverse[transform::type::generic3]; const auto update_key = &inverse[transform::type::update_key]; auto result = transform::apply(update_key->operands[0].size, update_key->mnemonic, rolling_key, operand); // make sure we update the rolling decryption key correctly... switch (update_key->operands[0].size) { case 8: rolling_key = (rolling_key & ~0xFFull) + result; break; case 16: rolling_key = (rolling_key & ~0xFFFFull) + result; break; default: rolling_key = result; break; } operand = transform::apply(generic_decrypt_3->operands[0].size, generic_decrypt_3->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_3) ? generic_decrypt_3->operands[1].imm.value.u : 0); operand = transform::apply(generic_decrypt_2->operands[0].size, generic_decrypt_2->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_2) ? generic_decrypt_2->operands[1].imm.value.u : 0); operand = transform::apply(generic_decrypt_1->operands[0].size, generic_decrypt_1->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_1) ? generic_decrypt_1->operands[1].imm.value.u : 0); operand = transform::apply(key_decrypt->operands[0].size, key_decrypt->mnemonic, operand, rolling_key); if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID) { operand = transform::apply(generic_decrypt_0->operands[0].size, generic_decrypt_0->mnemonic, operand, // check to see if this instruction has an IMM... transform::has_imm(generic_decrypt_0) ? generic_decrypt_0->operands[1].imm.value.u : 0); } return {operand, rolling_key}; } bool get_rva_decrypt(const zydis_routine_t &vm_entry, std::vector &transform_instrs) { // find mov esi, [rsp+0xA0] auto result = std::find_if( vm_entry.begin(), vm_entry.end(), [](const zydis_instr_t &instr_data) -> bool { if (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV && instr_data.instr.operand_count == 2 && instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI && instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSP && instr_data.instr.operands[1].mem.disp.has_displacement && instr_data.instr.operands[1].mem.disp.value == 0xA0) return true; return false; }); if (result == vm_entry.end()) return false; // find the next three instruction with ESI as the dest... for (auto idx = 0u; idx < 3; ++idx) { result = std::find_if(++result, vm_entry.end(), [](const zydis_instr_t &instr_data) -> bool { return instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI; }); if (result == vm_entry.end()) return false; transform_instrs.push_back(result->instr); } return true; } } // namespace instrs } // namespace vm