Untitled
unknown
c_cpp
a month ago
7.1 kB
3
Indexable
Never
#include <iostream> #include <type_traits> #include <utility> struct Parameters { template<typename T> void setArg(const uint8_t idx, const T val) const { *(T*)getArgPtr(idx) = val; } template<typename T> T getArg(const uint8_t idx) const { return *(T*)getArgPtr(idx); } // asm depends on this specific type // we the ILCallback allocates stack space that is set to point here volatile uint64_t m_arguments; private: // must be char* for aliasing rules to work when reading back out char* getArgPtr(const uint8_t idx) const { return ((char*)&m_arguments) + sizeof(uint64_t) * idx; } }; struct ReturnValue { template<typename T> void setRet(const T val) const { *(T*)getRetPtr() = val; } template<typename T> T getRet() const { return *(T*)getRetPtr(); } unsigned char* getRetPtr() const { return (unsigned char*)&m_retVal; } uint64_t m_retVal; }; typedef void(*tUserCallback)(const Parameters* params, const uint8_t count, const ReturnValue* ret); namespace dyno { enum class DataType; template<typename T> constexpr DataType GetType() { if constexpr (std::is_same_v<T, void>) return DataType::Void; else if constexpr (std::is_same_v<T, bool>) return DataType::Bool; else if constexpr (std::is_same_v<T, int8_t>) return DataType::Int8; else if constexpr (std::is_same_v<T, uint8_t>) return DataType::UInt8; else if constexpr (std::is_same_v<T, int16_t>) return DataType::Int16; else if constexpr (std::is_same_v<T, uint16_t>) return DataType::UInt16; else if constexpr (std::is_same_v<T, int32_t>) return DataType::Int32; else if constexpr (std::is_same_v<T, uint32_t>) return DataType::UInt32; else if constexpr (std::is_same_v<T, int64_t>) return DataType::Int64; else if constexpr (std::is_same_v<T, uint64_t> || std::is_same_v<T, unsigned long>) return DataType::UInt64; else if constexpr (std::is_same_v<T, float>) return DataType::Float; else if constexpr (std::is_same_v<T, double>) return DataType::Double; else if constexpr (std::is_same_v<T, const char*>) return DataType::String; else if constexpr (std::is_same_v<T, const wchar_t*>) return DataType:: WString; else if constexpr (std::is_pointer<T>::value || std::is_reference_v<T>) return DataType::Pointer; else { if (sizeof(T) > sizeof(uint64_t)) { return DataType::Pointer; } else if constexpr (sizeof(T) > sizeof(uint32_t)) { return DataType::UInt64; } else if constexpr (sizeof(T) > sizeof(uint16_t)) { return DataType::UInt32; } else if constexpr (sizeof(T) > sizeof(uint8_t)) { return DataType::UInt16; } else if constexpr (sizeof(T) > sizeof(bool)) { return DataType::UInt8; } return DataType::Bool; } } template<typename Function> struct function_traits; template<typename Ret, typename... Args> struct function_traits<Ret(*)(Args...)> { static constexpr size_t arity = sizeof...(Args); using result_type = Ret; using argument_types = std::tuple<Args...>; using index_sequence_for = std::index_sequence_for<Args...>; static std::array<DataType, arity> args() { return { GetType<Args>() ...}; } static DataType ret() { return GetType<Ret>(); } }; template<typename Class, typename Ret, typename... Args> struct function_traits<Ret(Class::*)(Args...)> { static constexpr size_t arity = sizeof...(Args); using result_type = Ret; using argument_types = std::tuple<Class*, Args...>; using index_sequence_for = std::index_sequence_for<Class*, Args...>; static std::array<DataType, arity + 1> args() { std::array<DataType, arity> originalArgs = { GetType<Args>() ... }; std::array<DataType, arity + 1> result; result[0] = DataType::Pointer; std::copy(originalArgs.begin(), originalArgs.end(), result.begin() + 1); return result; } static DataType ret() { return GetType<Ret>(); } }; template <typename Class, typename Ret, typename... Args> class function_traits<Ret (Class::*)(Args...) const> : public function_traits<Ret (Class::*)(Args...)> {}; template <typename Class, typename Ret, typename... Args> class function_traits<Ret (Class::*)(Args...) volatile> : public function_traits<Ret (Class::*)(Args...)> {}; template <typename Class, typename Ret, typename... Args> class function_traits<Ret (Class::*)(Args...) const volatile> : public function_traits<Ret (Class::*)(Args...)> {}; template<typename Ret, typename... Args> struct function_traits<Ret(Args...)> { static constexpr size_t arity = sizeof...(Args); using result_type = Ret; using argument_types = std::tuple<Args...>; using index_sequence_for = std::index_sequence_for<Args...>; static std::array<DataType, arity> args() { return { GetType<Args>() ...}; } static DataType ret() { return GetType<Ret>(); } }; template<class Ret, class... Args> class function_traits<Ret(Args...) const> : public function_traits<Ret(Args...)> {}; template<class Ret, class... Args> class function_traits<Ret(Args...) volatile> : public function_traits<Ret(Args...)> {}; template<class Ret, class... Args> class function_traits<Ret(Args...) const volatile> : public function_traits<Ret(Args...)> {}; } // Helper function to cast void* to the correct type and fill the tuple template <typename T, typename Tuple, std::size_t I> void fill_tuple_element(Tuple& t, const Parameters& params) { std::get<I>(t) = params.getArg<T>(I); } // Recursive template to unpack and fill each element of the tuple template <typename Tuple, std::size_t... I> void fill_tuple(Tuple& t, const Parameters& params, std::index_sequence<I...>) { (fill_tuple_element<std::tuple_element_t<I, Tuple>, Tuple, I>(t, params), ...); } enum class ReturnAction : int { Override = 3, }; template<typename F, typename C> auto make_callback(F, C callback) { using traits = dyno::function_traits<F>; return [&](const Parameters& params, const uint8_t count, const ReturnValue& ret) -> ReturnAction { typename traits::argument_types args; fill_tuple(args, params, typename traits::index_sequence_for{}); if constexpr (std::is_same_v<traits::result_type, void>) { return std::apply(callback, args); } else { auto [action, output] = std::apply(callback, args); if (action >= ReturnAction::Override) { ret.setRet(output); } return action; } }; } /* Hook Signature */ class Ex { public: int func(int, float, double, void*); }; int func(int, float, double, void*); /* Hook Callback */ std::pair<ReturnAction, int> FunctionWhichShouldCalledInside(int, float, double, void*) {} std::pair<ReturnAction, int> FunctionWhichShouldCalledInside2(Ex* ex, int, float, double, void*) {} int main() { auto cb = make_callback(&func, &FunctionWhichShouldCalledInside); Parameters p; int count; ReturnValue r; cb(p, count, r); auto cb2 = make_callback(&Ex::func, &FunctionWhichShouldCalledInside2); cb2(p, count, r); return 0; }
Leave a Comment