#pragma once #include #include #include #include #include #include #include #include #define PAGE_4KB 0x1000 #define STACK_SIZE PAGE_4KB * 512 #define STACK_BASE 0xFFFF000000000000 namespace vm { class emu_t { public: explicit emu_t(vm::vmctx_t* vm_ctx); ~emu_t(); bool init(); bool emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn); private: uc_engine* uc; const vm::vmctx_t* m_vm; zydis_reg_t vip, vsp; /// /// used in branch_pred_spec_exec to count legit SREG virtual instructions... /// std::uint8_t m_sreg_cnt; /// /// current code trace... /// vm::instrs::hndlr_trace_t cc_trace; /// /// current virtual code block... /// block... /// vm::instrs::vblk_t* cc_blk; /// /// current code virtual routine... /// vm::instrs::vrtn_t* cc_vrtn; /// /// unicorn engine hook /// uc_hook code_exec_hook, invalid_mem_hook, int_hook, branch_pred_hook; /// /// code execution callback for executable memory ranges of the vmprotect'ed /// module... essentially used to single step the processor over virtual /// handlers... /// /// /// /// /// /// static bool code_exec_callback(uc_engine* uc, uint64_t address, uint32_t size, emu_t* obj); /// /// branch predicition with speculative execution (emulation)... this callback /// ensures there are at least 10 SREG's and that all of the imm values are /// legit... /// /// /// /// /// /// static bool branch_pred_spec_exec(uc_engine* uc, uint64_t address, uint32_t size, emu_t* obj); /// /// invalid memory access handler. no runtime values can possibly effect the /// decryption of virtual instructions. thus invalid memory accesses can be /// ignored entirely... /// /// uc engine context pointer... /// type of memory access... /// address of the memory access... /// size of the memory access... /// value being read... /// emu_t object pointer... static void invalid_mem(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, emu_t* obj); /// /// interrupt callback for unicorn engine. this is used to advance rip over /// division instructions which div by 0... /// /// the uc engine pointer... /// interrupt number... /// emu_t object... static void int_callback(uc_engine* uc, std::uint32_t intno, emu_t* obj); /// /// determines if there *could* be a JCC in the virtual code block... its not /// 100%... speculative execution is required to ensure that both branches /// discovered are legit... /// /// /// std::optional> could_have_jcc( std::vector& vinstrs); /// /// determines if a branch is legit or not... /// /// /// /// bool legit_branch(vm::instrs::vblk_t& vblk, std::uintptr_t branch_addr); void emulate_branch(uc_context* ctx, std::uint8_t* stack, std::uintptr_t branch_addr, zydis_reg_t vsp, vm::instrs::vblk_t& vblk); }; } // namespace vm