#pragma once #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER #include #define bswap_32(x) _byteswap_ulong(x) #define bswap_64(x) _byteswap_uint64(x) #define bswap_16(x) _byteswap_ushort(x) #elif defined(__APPLE__) // Mac OS X / Darwin features #include #define bswap_32(x) OSSwapInt32(x) #define bswap_64(x) OSSwapInt64(x) #elif defined(__sun) || defined(sun) #include #define bswap_32(x) BSWAP_32(x) #define bswap_64(x) BSWAP_64(x) #elif defined(__FreeBSD__) #include #define bswap_32(x) bswap32(x) #define bswap_64(x) bswap64(x) #elif defined(__OpenBSD__) #include #define bswap_32(x) swap32(x) #define bswap_64(x) swap64(x) #elif defined(__NetBSD__) #include #include #if defined(__BSWAP_RENAME) && !defined(__bswap_32) #define bswap_32(x) bswap32(x) #define bswap_64(x) bswap64(x) #endif #else #include #endif using u8 = unsigned char; using u16 = unsigned short; using u32 = unsigned int; using u64 = unsigned long long; using u128 = __m128; using zydis_decoded_instr_t = ZydisDecodedInstruction; using zydis_register_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_routine_t = std::vector; /// /// utils used by the other cpp files... misc things that get used a lot... /// namespace vm::util { inline thread_local std::shared_ptr g_decoder = nullptr; inline thread_local std::shared_ptr g_formatter = nullptr; inline void init() { if (!vm::util::g_decoder && !vm::util::g_formatter) { vm::util::g_decoder = std::make_shared(); vm::util::g_formatter = std::make_shared(); ZydisDecoderInit(vm::util::g_decoder.get(), ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64); ZydisFormatterInit(vm::util::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; } /// /// 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_register_t to64(zydis_register_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_register_t a, zydis_register_t b); } // namespace reg /// /// get the instruction that fetches an operand out of VIP... /// /// this is a deobfuscated, flattened, view of any set of /// native instructions that read an operand out of VIP... can be calc_jmp, /// vm_entry, or vm handlers... /// returns true of the fetch operand native instruction is /// found... bool get_fetch_operand(const zydis_routine_t &routine, zydis_instr_t &fetch_instr); /// /// gets the instruction that fetches an operand out of VIP and returns an /// iterator to it... /// /// this is a deobfuscated, flattened, view of any set of /// native instructions that read an operand out of VIP... can be calc_jmp, /// vm_entry, or vm handlers... returns the iterator of the /// native instruction, else an empty std::optional... std::optional get_fetch_operand( zydis_routine_t &routine); /// /// prints a disassembly view of a routine... /// /// reference to a zydis_routine_t to be /// printed... void print(zydis_routine_t &routine); /// /// prints a single disassembly view of an instruction... /// /// instruction to print... void print(const zydis_decoded_instr_t &instr); /// /// determines if a given decoded native instruction is a JCC... /// /// /// bool is_jmp(const zydis_decoded_instr_t &instr); /// /// 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_routine_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_routine_t &routine); } // namespace vm::util