#pragma once #include #include namespace vm::instrs { /// /// mnemonic representation of supported virtual instructions... /// enum class mnemonic_t { unknown, sreg, lreg, lconst, add, div, idiv, mul, imul, nand, read, write, shl, shld, shr, shrd, lvsp, svsp, writecr3, readcr3, writecr8, readcr8, cpuid, rdtsc, call, jmp, vmexit }; /// /// the main virtual instruction structure which is returned by profilers... /// struct vinstr_t { /// /// mnemonic of the virtual instruction... /// mnemonic_t mnemonic; /// /// size varient of the virtual instruction... I.E SREGQ would have a value of /// "64" here...where the SREGDW varient would have a "32" here... /// u8 size; struct { /// /// true if the virtual instruction has an imm false if not... /// bool has_imm; /// /// size in bits of the imm... 8, 16, 32, 64... /// u8 size; /// /// imm value... /// u64 val; } imm; }; /// /// emu instruction containing current cpu register values and such... /// struct emu_instr_t { zydis_decoded_instr_t m_instr; uc_context* m_cpu; }; /// /// handler trace containing information about a stream of instructions... also /// contains some information about the virtual machine such as vip and vsp... /// struct hndlr_trace_t { std::uintptr_t m_hndlr_addr; zydis_reg_t m_vip, m_vsp; std::vector m_instrs; }; /// /// matcher function which returns true if an instruction matches a desired /// one... /// using matcher_t = std::function; /// /// virtual instruction structure generator... this can update the vip and vsp /// argument... it cannot update the instruction stream (hndlr)... /// using vinstr_gen_t = std::function(zydis_reg_t& vip, zydis_reg_t& vsp, hndlr_trace_t& hndlr)>; /// /// each virtual instruction has its own profiler_t structure which can generate /// all varients of the virtual instruction for each size... /// struct profiler_t { /// /// string name of the virtual instruction that this profile generates for... /// std::string name; /// /// mnemonic representation of the virtual instruction... /// mnemonic_t mnemonic; /// /// vector of matcher lambda's which return true if a given instruction /// matches... /// std::vector matchers; /// /// generates a virtual instruction structure... /// vinstr_gen_t generate; }; /// /// list of all profiles here... /// extern profiler_t jmp; extern profiler_t sreg; /// /// unsorted vector of profiles... they get sorted once at runtime... /// inline std::vector profiles = {&jmp}; /// /// sorts the profiles by descending order of matchers... this will prevent a /// smaller profiler with less matchers from being used when it should not be... /// /// this function can be called multiple times... /// inline void init() { if (static std::atomic_bool once = true; once.exchange(false)) std::sort(profiles.begin(), profiles.end(), [&](profiler_t* a, profiler_t* b) -> bool { return a->matchers.size() > b->matchers.size(); }); } /// /// determines the virtual instruction for the vm handler given vsp and vip... /// /// vip native register... /// vsp native register... /// /// returns vinstr_t structure... inline vinstr_t determine(zydis_reg_t& vip, zydis_reg_t& vsp, hndlr_trace_t& hndlr) { const auto& instrs = hndlr.m_instrs; const auto profile = std::find_if( profiles.begin(), profiles.end(), [&](profiler_t* profile) -> bool { for (auto& matcher : profile->matchers) { const auto matched = std::find_if(instrs.begin(), instrs.end(), [&](const emu_instr_t& instr) -> bool { const auto& i = instr.m_instr; return matcher(vip, vsp, i); }); if (matched == instrs.end()) return false; } return true; }); if (profile == profiles.end()) return vinstr_t{mnemonic_t::unknown}; auto result = (*profile)->generate(vip, vsp, hndlr); return result.has_value() ? result.value() : vinstr_t{mnemonic_t::unknown}; } /// /// get profile from mnemonic... /// /// mnemonic of the profile to get... /// pointer to the profile... inline profiler_t* get_profile(mnemonic_t mnemonic) { if (mnemonic == mnemonic_t::unknown) return nullptr; const auto res = std::find_if(profiles.begin(), profiles.end(), [&](profiler_t* profile) -> bool { return profile->mnemonic == mnemonic; }); return res == profiles.end() ? nullptr : *res; } } // namespace vm::instrs