#pragma once #include "logging.hpp" #include "jni_helper.hpp" #include "hook_helper.hpp" #include #define CONCATENATE(a, b) a##b #define CREATE_HOOK_STUB_ENTRY(SYM, RET, FUNC, PARAMS, DEF) \ inline static struct : public lsplant::Hooker{ \ inline static RET replace PARAMS DEF \ } FUNC #define CREATE_MEM_HOOK_STUB_ENTRY(SYM, RET, FUNC, PARAMS, DEF) \ inline static struct : public lsplant::MemHooker{ \ inline static RET replace PARAMS DEF \ } FUNC #define RETRIEVE_FUNC_SYMBOL(name, ...) \ (name##Sym = reinterpret_cast( \ lsplant::Dlsym(handler, __VA_ARGS__))) #define RETRIEVE_MEM_FUNC_SYMBOL(name, ...) \ (name##Sym = reinterpret_cast( \ lsplant::Dlsym(handler, __VA_ARGS__))) #define RETRIEVE_FIELD_SYMBOL(name, ...) \ (name = reinterpret_cast(lsplant::Dlsym(handler, __VA_ARGS__))) #define CREATE_FUNC_SYMBOL_ENTRY(ret, func, ...) \ typedef ret (*func##Type)(__VA_ARGS__); \ inline static ret (*func##Sym)(__VA_ARGS__); \ inline static ret func(__VA_ARGS__) #define CREATE_MEM_FUNC_SYMBOL_ENTRY(ret, func, thiz, ...) \ using func##Type = lsplant::MemberFunction; \ inline static func##Type func##Sym; \ inline static ret func(thiz, ## __VA_ARGS__) namespace lsplant { using HookHandler = InitInfo; template struct tstring : public std::integer_sequence { inline constexpr static const char *c_str() { return str_; } inline constexpr operator std::string_view() const { return { c_str(), sizeof...(chars) }; } private: constexpr static char str_[]{ chars..., '\0' }; }; template inline constexpr tstring operator ""_tstr() { return {}; } template inline constexpr tstring operator+(const tstring &, const tstring &) { return {}; } template inline constexpr auto operator+(const std::string &a, const tstring &) { char b[]{ as..., '\0' }; return a + b; } template inline constexpr auto operator+(const tstring &, const std::string &b) { char a[]{ as..., '\0' }; return a + b; } inline void *Dlsym(const HookHandler &handle, const char *name) { return handle.art_symbol_resolver(name); } template requires (std::is_same_v || std::is_same_v) inline static auto memfun_cast(Return (*func)(T *, Args...)) { union { Return (Class::*f)(Args...); struct { decltype(func) p; std::ptrdiff_t adj; } data; } u{ .data = { func, 0 }}; static_assert(sizeof(u.f) == sizeof(u.data), "Try different T"); return u.f; } template T, typename Return, typename... Args> inline auto memfun_cast(Return (*func)(T *, Args...)) { return memfun_cast(func); } template class MemberFunction; template class MemberFunction { using SelfType = MemberFunction; using ThisType = std::conditional_t, SelfType, This>; using MemFunType = Return(ThisType::*)(Args...); public: using FunType = Return (*)(This *, Args...); private: MemFunType f_ = nullptr; public: MemberFunction() = default; MemberFunction(FunType f) : f_(memfun_cast(f)) {} MemberFunction(MemFunType f) : f_(f) {} Return operator()(This *thiz, Args... args) { return (reinterpret_cast(thiz)->*f_)(std::forward(args)...); } inline operator bool() { return f_ != nullptr; } }; // deduction guide template MemberFunction(Return(*f)(This *, Args...)) -> MemberFunction; template MemberFunction(Return(This::*f)(Args...)) -> MemberFunction; template struct Hooker; template struct Hooker> { inline static Ret (*backup)(Args...) = nullptr; inline static constexpr std::string_view sym = tstring{}; }; template struct MemHooker; template struct MemHooker> { inline static MemberFunction backup; inline static constexpr std::string_view sym = tstring{}; }; template concept HookerType = requires(T a) { a.backup; a.replace; }; template inline static bool HookSymNoHandle(const HookHandler &handler, void *original, T &arg) { if (original) { if constexpr(is_instance::value) { void *backup = handler.inline_hooker(original, reinterpret_cast(arg.replace)); arg.backup = reinterpret_cast(backup); } else { arg.backup = reinterpret_cast(handler.inline_hooker(original, reinterpret_cast(arg.replace))); } return true; } else { return false; } } template inline static bool HookSym(const HookHandler &handler, T &arg) { auto original = handler.art_symbol_resolver(arg.sym); return HookSymNoHandle(handler, original, arg); } template inline static bool HookSyms(const HookHandler &handle, T &first, Args &...rest) { if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) { LOGW("Hook Fails: %*s", static_cast(first.sym.size()), first.sym.data()); return false; } return true; } }