#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(); void emulate(); /// /// emulates a single virtual instruction and returns it... this function is /// used internally to determine if virtual JCC addresses are legit... /// /// returns the single virtual instruction that was /// emulated... vm::instrs::vinstr_t step(); private: uc_engine* uc; const vm::vmctx_t* m_vm; zydis_reg_t vip, vsp; /// /// single step structure information... /// struct { bool m_toggle; uc_context* cpu_context; std::uint8_t stack[STACK_SIZE]; } m_single_step; std::vector vinstrs; vm::instrs::hndlr_trace_t cc_trace; /// /// unicorn engine hook /// uc_hook code_exec_hook, invalid_mem_hook, int_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); /// /// 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 is a JCC in the virtual instruction stream, if there /// is returns a pair of image based addresses for both of the branches... /// /// vector of virtual instructions... /// returns a pair of imaged based addresses, one for each branch /// address... if there is no jcc then it returns nothing... std::optional> has_jcc( std::vector& vinstrs); }; } // namespace vm