Untitled
unknown
c_cpp
a year ago
7.1 kB
11
Indexable
#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;
}Editor is loading...
Leave a Comment