#ifndef __LIBRADHOOK_API_H__ #define __LIBRADHOOK_API_H__ #include #include #include #ifndef RADHOOK_API # define RADHOOK_API #endif // RADHOOK_API // versioning #define RADHOOK_VERSION_MAJOR 1 #define RADHOOK_VERSION_MINOR 1 #define RADHOOK_VERSION_PATCH 0 #if _MSC_VER # include // for source code annotations #else # define _In_ # define _In_opt_ # define _Out_ # define _Out_opt_ # define _Outptr_ # define _Ret_z_ # define _Success_(expr) # define _Out_writes_to_(size, count) #endif enum class RadHookResult : int { Success = 0, AlreadyInstalled, NotInstalled, AlreadyEnabled, AlreadyDisabled, MemoryAllocFailed, MemoryProtectFailed, DisassemblyFailed, InvalidTarget, InvalidDetour, InvalidHandle, TrampolineTooFar, TargetTooSmall, UnknownTarget, Unknown, }; _Ret_z_ /** * @brief Creates a human readable name for a status code. * * @param result Status code returned by a RadHook API function. * @return Null-terminated string describing the status code. */ RADHOOK_API const char* RadHookResultToString( RadHookResult result ); struct RadHookOpaque; using RadHookHandle = RadHookOpaque*; _Success_(return == RadHookResult::Success) /** * @brief Creates and installs a hook. * * Redirects execution from @p target to @p detour and enables the hook * immediately upon successful creation. * * @param target Function or address to hook. * @param detour Replacement function to execute. * @param outHandle Receives the created hook handle on success. Set to * nullptr on failure. * * @return Operation result. */ RADHOOK_API RadHookResult RadHookCreate( _In_ void* target, _In_ void* detour, _Out_ RadHookHandle* outHandle ); _Success_(return == RadHookResult::Success) /** * @brief Creates and installs a hook from a function pointer. * * Convenience overload that accepts a typed function pointer for the target. * * @tparam TargetFn Target function pointer type. * @param target Target function to hook. * @param detour Replacement function. * @param outHandle Receives the created hook handle on success. * * @return Operation result. */ template requires std::is_function_v> RadHookResult RadHookCreate( TargetFn target, _In_ void* detour, _Out_ RadHookHandle* outHandle ) { return RadHookCreate( reinterpret_cast(target), detour, outHandle ); } /** * @brief Enables an installed hook. * * Re-applies the jump from the target function to its detour. * * @param handle Hook handle. * * @return RadHookResult::AlreadyEnabled if the hook is already enabled; * otherwise the result of the operation. */ RADHOOK_API RadHookResult RadHookEnable( _In_ RadHookHandle handle ); /** * @brief Disables an installed hook. * * Restores the original bytes at the target function. * * @param handle Hook handle. * * @return RadHookResult::AlreadyDisabled if the hook is already disabled; * otherwise the result of the operation. */ RADHOOK_API RadHookResult RadHookDisable( _In_ RadHookHandle handle ); /** * @brief Destroys a hook. * * Disables the hook if necessary, releases any allocated resources, * and invalidates the handle. * * @param handle Hook handle. * * @return Operation result. */ RADHOOK_API RadHookResult RadHookDestroy( _In_ RadHookHandle handle ); /** * @brief Enables every registered hook. * * Hooks that are already enabled are left unchanged. * * @return Operation result. */ RADHOOK_API RadHookResult RadHookEnableAll(); /** * @brief Disables every registered hook. * * Hooks that are already disabled are left unchanged. * * @return Operation result. */ RADHOOK_API RadHookResult RadHookDisableAll(); /** * @brief Returns the number of currently registered hooks. * * Destroyed hooks are not included. * * @return Number of registered hooks. */ RADHOOK_API size_t RadHookGetCount(); _Out_writes_to_(maxCount, return) /** * @brief Retrieves registered hook handles. * * Copies up to @p maxCount currently registered hook handles into * @p outHandles. * * @param outHandles Destination buffer. * @param maxCount Maximum number of handles to copy. * * @return Number of handles copied. */ RADHOOK_API size_t RadHookGetHandles( _Out_ RadHookHandle* outHandles, _In_ size_t maxCount ); /** * @brief Checks whether a hook handle is valid. * * @param handle Hook handle. * * @return true if the handle refers to a registered hook; otherwise false. */ RADHOOK_API bool RadHookIsValid( _In_ RadHookHandle handle ); /** * @brief Checks whether a hook is currently enabled. * * @param handle Hook handle. * * @return true if the hook is enabled; otherwise false. */ RADHOOK_API bool RadHookIsEnabled( _In_ RadHookHandle handle ); /** * @brief Returns the hooked target function. * * @param handle Hook handle. * * @return Pointer to the original target function, or nullptr if the handle * is invalid. */ RADHOOK_API void* RadHookGetTarget( _In_ RadHookHandle handle ); /** * @brief Returns the detour function. * * @param handle Hook handle. * * @return Pointer to the detour function, or nullptr if the handle is * invalid. */ RADHOOK_API void* RadHookGetDetour( _In_ RadHookHandle handle ); /** * @brief Returns the trampoline containing the relocated original code. * * Calling the returned function executes the original implementation while * bypassing the installed hook. * * @param handle Hook handle. * * @return Pointer to the trampoline, or nullptr if unavailable. */ RADHOOK_API void* RadHookGetOriginal( _In_ RadHookHandle handle ); /** * @brief Returns the trampoline cast to a function pointer type. * * @tparam FnPtr Desired function pointer type. * @param handle Hook handle. * * @return Trampoline cast to @p FnPtr. */ template FnPtr RadHookGetOriginalAs( _In_ RadHookHandle handle ) { return reinterpret_cast(RadHookGetOriginal(handle)); } _Out_writes_to_(maxCount, return) /** * @brief Enumerates currently registered hooks. * * Copies up to @p maxCount active hook handles into @p out. * Handles are written in no particular order. * * This function only returns hooks that are currently registered * and not destroyed. * * @param out Destination buffer for hook handles. * @param maxCount Maximum number of handles to copy. * * @return Number of hook handles written into @p out. */ RADHOOK_API size_t RadHookEnumerate( _Out_ RadHookHandle* out, _In_ size_t maxCount ); /** * @brief Returns the library version. * * Any of the output parameters may be nullptr if that component is not * needed. Useful for verifying ABI compatibility when radhook is loaded * as a shared library independently of the consuming module. * * @param outMajor Receives the major version, or nullptr. * @param outMinor Receives the minor version, or nullptr. * @param outPatch Receives the patch version, or nullptr. */ RADHOOK_API void RadHookGetVersion( _Out_opt_ int* outMajor, _Out_opt_ int* outMinor, _Out_opt_ int* outPatch ); _Success_(return == RadHookResult::Success) /** * @brief Creates and installs a hook on a vtable slot. * * @param vtable Pointer to the base of the vtable. * @param index Index of the slot to hook. * @param detour Replacement function. * @param outHandle Receives the created hook handle on success. Set to nullptr on failure. * * @return InvalidTarget if @p vtable is nullptr or the slot * at @p index is empty; otherwise the result of the operation. */ RADHOOK_API RadHookResult RadHookVTableCreate( _In_ void** vtable, _In_ size_t index, _In_ void* detour, _Out_ RadHookHandle* outHandle ); /** * @brief Queues a hook to be enabled on the next RadHookApplyQueued call. * * Does not modify the hook itself. If the same handle is queued for both * enable and disable before RadHookApplyQueued runs, the most recent call * wins. * * @param handle Hook handle. * * @return RadHookResult::InvalidHandle if the handle is not registered; * otherwise RadHookResult::Success. */ RADHOOK_API RadHookResult RadHookQueueEnable( _In_ RadHookHandle handle ); /** * @brief Queues a hook to be disabled on the next RadHookApplyQueued call. * * Does not modify the hook itself. If the same handle is queued for both * enable and disable before RadHookApplyQueued runs, the most recent call * wins. * * @param handle Hook handle. * * @return RadHookResult::InvalidHandle if the handle is not registered; * otherwise RadHookResult::Success. */ RADHOOK_API RadHookResult RadHookQueueDisable( _In_ RadHookHandle handle ); /** * @brief Applies all queued enable/disable operations. * * Every hook with a pending queued action has that action applied and its * queue cleared, regardless of individual outcomes. Hooks with no queued * action are left untouched. * * @return The result of the first queued operation that did not succeed * (ignoring RadHookResult::AlreadyEnabled / RadHookResult::AlreadyDisabled), * or RadHookResult::Success if all applied cleanly. */ RADHOOK_API RadHookResult RadHookApplyQueued(); _Success_(return == RadHookResult::Success) /** * @brief Finds a hook handle from a specified target. * * @param target Target. * @param outHandle Receives the hook handle on success. * * @return Operation result. */ RADHOOK_API RadHookResult RadHookGetHandleFromTarget( _In_ void* target, _Out_ RadHookHandle* outHandle ); _Success_(return == RadHookResult::Success) /** * @brief Finds a hook handle from a specified target function pointer. * * Convenience overload that accepts a typed function pointer for the target. * * @tparam TargetFn Target function pointer type. * @param target Target function. * @param outHandle Receives the hook handle on success. * * @return Operation result. */ template requires std::is_function_v> RadHookResult RadHookGetHandleFromTarget( TargetFn target, _Out_ RadHookHandle* outHandle ) { return RadHookGetHandleFromTarget( reinterpret_cast(target), outHandle ); } #endif // __LIBRADHOOK_API_H__