#pragma once #include #include "lsplant.hpp" #include "jni_helper.hpp" #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: inline static constexpr 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_v) { 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))) { __android_log_print(ANDROID_LOG_ERROR, #ifdef LOG_TAG LOG_TAG, #else "HookHelper", #endif "Hook Fails: %*s", static_cast(first.sym.size()), first.sym.data()); return false; } return true; } } // namespace lsplant