mirror of
https://git.recroomarchive.org/Radium/libradhook.git
synced 2026-08-07 09:10:59 +00:00
458 lines
10 KiB
C++
458 lines
10 KiB
C++
#ifndef __LIBRADHOOK_API_H__
|
|
#define __LIBRADHOOK_API_H__
|
|
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
|
|
#include <type_traits>
|
|
|
|
#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 <sal.h> // 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 <typename TargetFn>
|
|
requires std::is_function_v<std::remove_pointer_t<TargetFn>>
|
|
RadHookResult
|
|
RadHookCreate(
|
|
TargetFn target,
|
|
_In_ void* detour,
|
|
_Out_ RadHookHandle* outHandle
|
|
)
|
|
{
|
|
return RadHookCreate(
|
|
reinterpret_cast<void*>(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 <typename FnPtr>
|
|
FnPtr
|
|
RadHookGetOriginalAs(
|
|
_In_ RadHookHandle handle
|
|
)
|
|
{
|
|
return reinterpret_cast<FnPtr>(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 <typename TargetFn>
|
|
requires std::is_function_v<std::remove_pointer_t<TargetFn>>
|
|
RadHookResult
|
|
RadHookGetHandleFromTarget(
|
|
TargetFn target,
|
|
_Out_ RadHookHandle* outHandle
|
|
)
|
|
{
|
|
return RadHookGetHandleFromTarget(
|
|
reinterpret_cast<void*>(target),
|
|
outHandle
|
|
);
|
|
}
|
|
|
|
#endif // __LIBRADHOOK_API_H__
|