#pragma once #include #include #include #include #include namespace vm { namespace transform { // taken from ida... template inline T __ROL__(T value, int count) { const unsigned int nbits = sizeof(T) * 8; if (count > 0) { count %= nbits; T high = value >> (nbits - count); if (T(-1) < 0) // signed value high &= ~((T(-1) << count)); value <<= count; value |= high; } else { count = -count % nbits; T low = value << (nbits - count); value >>= count; value |= low; } return value; } // taken from ida... inline u8 __ROL1__(u8 value, int count) { return __ROL__((u8)value, count); } inline u16 __ROL2__(u16 value, int count) { return __ROL__((u16)value, count); } inline u32 __ROL4__(u32 value, int count) { return __ROL__((u32)value, count); } inline u64 __ROL8__(u64 value, int count) { return __ROL__((u64)value, count); } inline u8 __ROR1__(u8 value, int count) { return __ROL__((u8)value, -count); } inline u16 __ROR2__(u16 value, int count) { return __ROL__((u16)value, -count); } inline u32 __ROR4__(u32 value, int count) { return __ROL__((u32)value, -count); } inline u64 __ROR8__(u64 value, int count) { return __ROL__((u64)value, -count); } template using transform_t = std::function; enum class type { rolling_key, generic1, generic2, generic3, update_key }; using map_t = std::map; template inline const auto _bswap = [](T a, T b) -> T { if constexpr (std::is_same_v) return _byteswap_uint64(a); if constexpr (std::is_same_v) return _byteswap_ulong(a); if constexpr (std::is_same_v) return _byteswap_ushort(a); throw std::invalid_argument("invalid type size..."); }; template inline const auto _add = [](T a, T b) -> T { return a + b; }; template inline const auto _xor = [](T a, T b) -> T { return a ^ b; }; template inline const auto _sub = [](T a, T b) -> T { return a - b; }; template inline const auto _neg = [](T a, T b) -> T { return a * -1; }; template inline const auto _not = [](T a, T b) -> T { return ~a; }; template inline const auto _ror = [](T a, T b) -> T { if constexpr (std::is_same_v) return __ROR8__(a, b); if constexpr (std::is_same_v) return __ROR4__(a, b); if constexpr (std::is_same_v) return __ROR2__(a, b); if constexpr (std::is_same_v ) return __ROR1__(a, b); throw std::invalid_argument("invalid type size..."); }; template inline const auto _rol = [](T a, T b) -> T { if constexpr (std::is_same_v) return __ROL8__(a, b); if constexpr (std::is_same_v) return __ROL4__(a, b); if constexpr (std::is_same_v) return __ROL2__(a, b); if constexpr (std::is_same_v ) return __ROL1__(a, b); throw std::invalid_argument("invalid type size..."); }; template inline const auto _inc = [](T a, T b) -> T { return a + 1; }; template inline const auto _dec = [](T a, T b) -> T { return a - 1; }; template inline std::map> transforms = { { ZYDIS_MNEMONIC_ADD, _add }, { ZYDIS_MNEMONIC_XOR, _xor }, { ZYDIS_MNEMONIC_BSWAP, _bswap }, { ZYDIS_MNEMONIC_SUB, _sub}, { ZYDIS_MNEMONIC_NEG, _neg}, { ZYDIS_MNEMONIC_NOT, _not}, { ZYDIS_MNEMONIC_ROR, _ror}, { ZYDIS_MNEMONIC_ROL, _rol}, { ZYDIS_MNEMONIC_INC, _inc}, { ZYDIS_MNEMONIC_DEC, _dec} }; inline std::map inverse = { {ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB}, {ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR}, {ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP}, {ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD}, {ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG}, {ZYDIS_MNEMONIC_NOT, ZYDIS_MNEMONIC_NOT}, {ZYDIS_MNEMONIC_ROR, ZYDIS_MNEMONIC_ROL}, {ZYDIS_MNEMONIC_ROL, ZYDIS_MNEMONIC_ROR}, {ZYDIS_MNEMONIC_INC, ZYDIS_MNEMONIC_DEC}, {ZYDIS_MNEMONIC_DEC, ZYDIS_MNEMONIC_INC} }; // max size of a and b is 64 bits, a and b is then converted to // the number of bits in bitsize, the transformation is applied, // finally the result is converted back to 64bits... zero extended... inline auto apply(std::uint8_t bitsize, ZydisMnemonic op, std::uint64_t a, std::uint64_t b) -> std::uint64_t { switch (bitsize) { case 8: return transforms[op](a, b); case 16: return transforms[op](a, b); case 32: return transforms[op](a, b); case 64: return transforms[op](a, b); default: throw std::invalid_argument("invalid bit size..."); } } inline bool has_imm(ZydisDecodedInstruction* instr) { return instr->operand_count > 1 && (instr->operands[1].type & ZYDIS_OPERAND_TYPE_IMMEDIATE); } } }