Files
libradhook/include/radhook/api.h

415 lines
9.2 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,
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();
#endif // __LIBRADHOOK_API_H__