#pragma once #include #include #include #include #include #include #include #include #include #include using u8 = unsigned char; using u16 = unsigned short; using u32 = unsigned int; using u64 = unsigned long long; using zydis_decoded_instr_t = ZydisDecodedInstruction; using zydis_reg_t = ZydisRegister; using zydis_mnemonic_t = ZydisMnemonic; using zydis_decoded_operand_t = ZydisDecodedOperand; struct zydis_instr_t { zydis_decoded_instr_t instr; std::vector raw; std::uintptr_t addr; }; using zydis_rtn_t = std::vector; namespace vm::utils { inline thread_local std::shared_ptr g_decoder = nullptr; inline thread_local std::shared_ptr g_formatter = nullptr; inline void init() { if (!vm::utils::g_decoder && !vm::utils::g_formatter) { vm::utils::g_decoder = std::make_shared(); vm::utils::g_formatter = std::make_shared(); ZydisDecoderInit(vm::utils::g_decoder.get(), ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64); ZydisFormatterInit(vm::utils::g_formatter.get(), ZYDIS_FORMATTER_STYLE_INTEL); } } inline bool open_binary_file(const std::string& file, std::vector& data) { std::ifstream fstr(file, std::ios::binary); if (!fstr.is_open()) return false; fstr.unsetf(std::ios::skipws); fstr.seekg(0, std::ios::end); const auto file_size = fstr.tellg(); fstr.seekg(NULL, std::ios::beg); data.reserve(static_cast(file_size)); data.insert(data.begin(), std::istream_iterator(fstr), std::istream_iterator()); return true; } /// /// determines if a given decoded native instruction is a JCC... /// /// /// bool is_jmp(const zydis_decoded_instr_t& instr); /// /// used by profiles to see if an instruction is a MOV/SX/ZX... /// /// /// bool is_mov(const zydis_decoded_instr_t& instr); /// /// prints a disassembly view of a routine... /// /// reference to a zydis_routine_t to be /// printed... void print(zydis_rtn_t& routine); /// /// prints a single disassembly view of an instruction... /// /// instruction to print... void print(const zydis_decoded_instr_t& instr); /// /// utils pertaining to native registers... /// namespace reg { /// /// converts say... AL to RAX... /// /// a zydis decoded register value... /// returns the largest width register of the given register... AL /// gives RAX... zydis_reg_t to64(zydis_reg_t reg); /// /// compares to registers with each other... calls to64 and compares... /// /// register a... /// register b... /// returns true if register to64(a) == to64(b)... bool compare(zydis_reg_t a, zydis_reg_t b); } // namespace reg /// /// flatten native instruction stream, takes every JCC (follows the branch)... /// /// filled with decoded instructions... /// linear virtual address to start flattening /// from... keep JCC's in the flattened /// instruction stream... returns true if flattened was /// successful... bool flatten(zydis_rtn_t& routine, std::uintptr_t routine_addr, bool keep_jmps = false, std::uint32_t max_instrs = 500, std::uintptr_t module_base = 0ull); /// /// deadstore deobfuscation of a flattened routine... /// /// reference to a flattened instruction vector... void deobfuscate(zydis_rtn_t& routine); /// /// small namespace that contains function wrappers to determine the validity of /// linear virtual addresses... /// namespace scn { /// /// determines if a pointer lands inside of a section that is readonly... /// /// this also checks to make sure the section is not discardable... /// /// linear virtual address of the module.... /// linear virtual address /// returns true if ptr lands inside of a readonly section of the /// module bool read_only(std::uint64_t module_base, std::uint64_t ptr); /// /// determines if a pointer lands inside of a section that is executable... /// /// this also checks to make sure the section is not discardable... /// /// /// /// bool executable(std::uint64_t module_base, std::uint64_t ptr); } // namespace scn } // namespace vm::utils