diff --git a/include/vmctx.hpp b/include/vmctx.hpp index 0941aaf..42d2870 100644 --- a/include/vmctx.hpp +++ b/include/vmctx.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace vm { class vmctx_t { @@ -11,12 +12,13 @@ class vmctx_t { std::uintptr_t vm_entry_rva); bool init(); const std::uintptr_t m_module_base, m_image_base, m_vm_entry_rva, - m_image_size; + m_image_size, m_image_load_delta; zydis_reg_t get_vip() const { return m_vip; } zydis_reg_t get_vsp() const { return m_vsp; } zydis_rtn_t get_vm_enter() const { return m_vm_entry; } + const std::array& get_vmentry_push_order() const; private: /// /// m_vip and m_vsp are set to the native registers used for them by the vm @@ -29,5 +31,8 @@ class vmctx_t { /// the virtual machine enter flattened and deobfuscated... /// zydis_rtn_t m_vm_entry; + + //using array container instead of c-style array in order to pass by reference. + std::array vmentry_push_order; }; } // namespace vm \ No newline at end of file diff --git a/src/vmctx.cpp b/src/vmctx.cpp index fd5eaaa..a8aa73e 100644 --- a/src/vmctx.cpp +++ b/src/vmctx.cpp @@ -8,7 +8,8 @@ vmctx_t::vmctx_t(std::uintptr_t module_base, : m_module_base(module_base), m_image_base(image_base), m_vm_entry_rva(vm_entry_rva), - m_image_size(image_size) {} + m_image_size(image_size), + m_image_load_delta(m_module_base - m_image_base) {} bool vmctx_t::init() { vm::utils::init(); @@ -20,6 +21,40 @@ bool vmctx_t::init() { vm::utils::deobfuscate(m_vm_entry); + //Get the order in which native registers are pushed + int push_index = 0; + for (const auto& instr : m_vm_entry) + { + if (instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSH && + instr.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + vm::utils::is_64_bit_gp(instr.instr.operands[0].reg.value)) + { + if (std::find(vmentry_push_order.begin(), vmentry_push_order.begin() + push_index, + instr.instr.operands[0].reg.value) != vmentry_push_order.begin() + push_index) + { + //Every register should only be pushed once + std::printf("Error initializing vmctx_t: vmenter pushes could not be parsed.\n"); + vm::utils::print(m_vm_entry); + return false; + } + vmentry_push_order[push_index++] = instr.instr.operands[0].reg.value; + } + else if (instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ) + { + if (std::find(vmentry_push_order.begin(), vmentry_push_order.begin() + push_index, + instr.instr.operands[0].reg.value) != vmentry_push_order.begin() + push_index) + { + // Same shit + std::printf("Error initializing vmctx_t: vmenter pushes could not be parsed.\n"); + vm::utils::print(m_vm_entry); + return false; + } + vmentry_push_order[push_index++] = ZYDIS_REGISTER_RFLAGS; + } + if (push_index == 16) + break; + } + // find mov reg, [rsp+0x90]. this register will be VIP... const auto vip_fetch = std::find_if( m_vm_entry.begin(), m_vm_entry.end(), @@ -53,4 +88,8 @@ bool vmctx_t::init() { m_vsp = vsp_fetch->instr.operands[0].reg.value; return true; } +const std::array& vm::vmctx_t::get_vmentry_push_order() const +{ + return vmentry_push_order; +} } // namespace vm \ No newline at end of file