Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 39 additions & 41 deletions include/plib/pe/export_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ namespace plib::pe::export_table
{
class ExportDirectory;

/// @brief Represents an entry in the function table of an export directory.
struct FunctionTableEntry
{
const intptr_t va;
const DWORD ordinal;
const DWORD rva;
const std::string_view name;
const bool isForwarded;

const intptr_t va; ///< Virtual address of the function.
const DWORD ordinal; ///< Ordinal number of the function.
const DWORD rva; ///< Relative virtual address of the function.
const std::string_view name; ///< Name of the function.
const bool isForwarded; ///< Indicates if the function is forwarded.

/// @brief Retrieves the function address as a specific type.
/// @tparam T The type to cast the address to.
/// @return the function address cast to type T.
/// @throws std::runtime_error if the function is forwarded (in debug mode).
template <typename T>
PLIB_FORCEINLINE T get() const
{
Expand All @@ -36,25 +41,36 @@ namespace plib::pe::export_table
return reinterpret_cast<T>(va);
}

/// @brief Checks if the entry is valid.
/// @return true if the entry is valid, false otherwise.
PLIB_FORCEINLINE constexpr operator bool() const noexcept
{
return rva != 0 && !name.empty();
}


/// @brief Constructs a function table entry.
/// @param va The virtual address of the function.
/// @param ord The ordinal number of the function.
/// @param rva The relative virtual address of the function.
/// @param name The name of the function.
/// @param isForwarded Indicates if the function is forwarded.
constexpr FunctionTableEntry(intptr_t va, WORD ord, DWORD rva, std::string_view name, bool isForwarded) noexcept
: va(va), ordinal(ord), rva(rva), name(name), isForwarded(isForwarded) {}

/// @brief Default constructor for an invalid function table entry.
constexpr FunctionTableEntry()
: va(0), ordinal(0), rva(0), name(""), isForwarded(false) {}

constexpr ~FunctionTableEntry() = default;
};

/// @brief Iterator for traversing the function table of an export directory.
class ExportDirectoryFunctionTableIterator
{
private:
const ExportDirectory* exportDir_;
DWORD ordinalIndex_;
const ExportDirectory* exportDir_; ///< Pointer to the export directory being iterated.
DWORD ordinalIndex_; ///< Current index in the function table.

friend class ExportDirectory;

constexpr ExportDirectoryFunctionTableIterator(const ExportDirectory& exportDir) noexcept
Expand All @@ -79,19 +95,24 @@ namespace plib::pe::export_table
PLIB_FORCEINLINE FunctionTableEntry operator->() const;
};

/// @brief Represents the export directory of a PE file.
class ExportDirectory
{
private:
const BYTE* _base;
const IMAGE_EXPORT_DIRECTORY* _ied;
const size_t _ied_size;
const BYTE* _base; ///< Base address of the PE image
const IMAGE_EXPORT_DIRECTORY* _ied; ///< Pointer to the IMAGE_EXPORT_DIRECTORY structure
const size_t _ied_size; ///< Size of the IMAGE_EXPORT_DIRECTORY structure
friend class ExportDirectoryFunctionTableIterator;

ExportDirectory(const BYTE* base, const IMAGE_EXPORT_DIRECTORY* exportDir, size_t ied_size)
: _base(base), _ied(exportDir), _ied_size(ied_size) {}
public:
~ExportDirectory() = default;

/// @brief Creates an ExportDirectory from a base address.
/// @tparam T The type of the base address.
/// @param base The base address of the PE image.
/// @return An ExportDirectory object.
template<class T>
requires types::HandleLike<T>
PLIB_FORCEINLINE static ExportDirectory FromBase(T base)
Expand Down Expand Up @@ -186,6 +207,12 @@ namespace plib::pe::export_table
}
};

/// @brief Get a module export entry by name.
/// @tparam _PredicateT
/// @tparam _BaseT
/// @param base Base address of the module.
/// @param predicate Predicate to match the function entry.
/// @return The matched FunctionTableEntry or std::nullopt if not found.
template <typename _PredicateT, class _BaseT>
requires types::HandleLike<_BaseT> && std::is_invocable_r_v<bool, _PredicateT, const FunctionTableEntry&>
PLIB_FORCEINLINE std::optional<FunctionTableEntry> GetModuleExportEntry(_BaseT base, _PredicateT&& predicate) noexcept
Expand All @@ -200,34 +227,6 @@ namespace plib::pe::export_table
}
return std::nullopt;
}

template<typename T>
requires types::HandleLike<T>
PLIB_FORCEINLINE std::optional<FunctionTableEntry> GetModuleExportEntryByName(T base, const std::string_view& name) noexcept
{
return GetModuleExportEntry(base, ProcAddressNamePredicate<std::string_view> {name});
}

template<typename T>
requires types::HandleLike<T>
PLIB_FORCEINLINE std::optional<FunctionTableEntry> GetModuleExportEntryByName(T base, const char* name) noexcept
{
return GetModuleExportEntry(base, ProcAddressNamePredicate<std::string_view> {name});
}

template<typename T>
requires types::HandleLike<T>
PLIB_FORCEINLINE std::optional<FunctionTableEntry> GetModuleExportEntryByName(T base, const wchar_t* name) noexcept
{
// Convert wide string to narrow string
CHAR buffer[MAX_PATH] = {0};
const size_t length = std::wcstombs(buffer, name, sizeof(buffer) - 1);
if (length == static_cast<size_t>(-1)) {
return std::nullopt; // Conversion failed
}
buffer[length] = '\0'; // Ensure null termination
return GetModuleExportEntry(base, ProcAddressNamePredicate<std::string_view> {buffer});
}
}

namespace plib::pe::export_table
Expand Down Expand Up @@ -266,7 +265,6 @@ namespace plib::pe::export_table
return functionTable[ordinal];
}


PLIB_FORCEINLINE const WORD ExportDirectory::GetNameOrdinal(DWORD index) const noexcept
{
if (_ied == nullptr || index >= GetNumberOfNames()) {
Expand Down
63 changes: 62 additions & 1 deletion include/plib/pe/export_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ static inline const void *to_address(T p)

namespace plib::pe::export_utils
{
/// @brief Retrieves the module handle of a function.
/// @tparam T The type of the function pointer.
/// @param funcPtr The function pointer to retrieve the module handle for.
/// @return The module handle if found, or std::nullopt if not found.
/// @note This function uses GetModuleHandleExA with the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag.
template <pe::types::function_ptr T>
inline std::optional<HMODULE> GetModuleOfFunction(T funcPtr) noexcept
{
Expand All @@ -39,7 +44,11 @@ namespace plib::pe::export_utils
return mod;
}

// Obtém RVA a partir de um VA (endereço de função, thunk, etc.)
/// @brief Retrieves the RVA (Relative Virtual Address) of a function.
/// @tparam T The type of the function pointer.
/// @param funcPtr The function pointer to retrieve the RVA for.
/// @return The RVA if found, or std::nullopt if not found.
/// @note This function uses GetModuleHandleExA internally
template <plib::pe::types::function_ptr T>
inline std::optional<uint32_t> GetRvaOfFunction(T funcPtr) noexcept
{
Expand Down Expand Up @@ -70,6 +79,11 @@ namespace plib::pe::export_utils
return static_cast<std::uint32_t>(rva);
}

/// @brief Retrieves the ordinal of a function.
/// @tparam T The type of the function pointer.
/// @param funcPtr The function pointer to retrieve the ordinal for.
/// @return The ordinal if found, or std::nullopt if not found.
/// @note This function uses GetModuleHandleExA internally.
template<pe::types::function_ptr T>
std::optional<uint32_t> GetOrdinalOfFunction(T funcPtr) noexcept
{
Expand Down Expand Up @@ -109,4 +123,51 @@ namespace plib::pe::export_utils
}
return std::nullopt;
}

/// @brief Retrieves a module export entry by name.
/// @tparam T The type of the module base address.
/// @tparam Predicate The type of the predicate used for matching.
/// @param base The base address of the module.
/// @param name The name of the exported function.
/// @return The export entry if found, or std::nullopt if not found.
template<typename Predicate, typename T>
requires types::HandleLike<T>
PLIB_FORCEINLINE std::optional<pe::export_table::FunctionTableEntry> GetModuleExportEntryByName(T base, const std::string_view& name) noexcept
{
using namespace pe::export_table;
return GetModuleExportEntry(base, ProcAddressNamePredicate<std::string_view> {name});
}

/// @brief Retrieves a module export entry by name.
/// @tparam T The type of the module base address.
/// @param base The base address of the module.
/// @param name The name of the exported function.
/// @return The export entry if found, or std::nullopt if not found.
template<typename T>
requires types::HandleLike<T>
PLIB_FORCEINLINE std::optional<pe::export_table::FunctionTableEntry> GetModuleExportEntryByName(T base, const char* name) noexcept
{
using namespace pe::export_table;
return GetModuleExportEntry(base, ProcAddressNamePredicate<std::string_view> {name});
}

/// @brief Retrieves a module export entry by name.
/// @tparam T The type of the module base address.
/// @param base The base address of the module.
/// @param name The name of the exported function.
/// @return The export entry if found, or std::nullopt if not found.
template<typename T>
requires types::HandleLike<T>
PLIB_FORCEINLINE std::optional<pe::export_table::FunctionTableEntry> GetModuleExportEntryByName(T base, const wchar_t* name) noexcept
{
using namespace pe::export_table;
// Convert wide string to narrow string
CHAR buffer[MAX_PATH] = {0};
const size_t length = std::wcstombs(buffer, name, sizeof(buffer) - 1);
if (length == static_cast<size_t>(-1)) {
return std::nullopt; // Conversion failed
}
buffer[length] = '\0'; // Ensure null termination
return GetModuleExportEntry(base, ProcAddressNamePredicate<std::string_view> {buffer});
}
}
7 changes: 7 additions & 0 deletions include/plib/pe/import_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

namespace plib::pe::import_utils
{
/// @brief Hooks a function in the Import Address Table (IAT) of a PE module.
/// @tparam T The type of the module base address.
/// @param pModBase The base address of the module.
/// @param lpszImportProcName The name of the imported function to hook.
/// @param pfnNewProc The new function to replace the imported function.
/// @param ppfnOldProc A pointer to store the old function pointer.
/// @return True if the hook was successful, false otherwise.
template<plib::pe::types::HandleLike T>
bool PeHookIAT(
T pModBase,
Expand Down
14 changes: 13 additions & 1 deletion include/plib/pe/pe_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

namespace plib::pe::utils
{
/// @brief Retrieves the NT headers from a given module base address.
/// @tparam T The type of the module base address.
/// @param baseRef The base address of the module.
/// @return A pointer to the NT headers, or nullptr if *baseRef* points to an invalid image.
template <class T>
requires types::HandleLike<T>
inline const IMAGE_NT_HEADERS* GetNtHeaders(const T baseRef)
inline const IMAGE_NT_HEADERS* GetNtHeaders(const T baseRef) noexcept
{
auto base = reinterpret_cast<const uint8_t*>(baseRef);
auto dos = reinterpret_cast<const IMAGE_DOS_HEADER *>(base);
Expand All @@ -22,13 +26,21 @@ namespace plib::pe::utils
return nt;
}

/// @brief Retrieves the NT headers from an optional module base address.
/// @tparam T The type of the module base address.
/// @param mod The optional module base address.
/// @return A pointer to the NT headers, or nullptr if not found.
template <types::HandleLike T>
inline const IMAGE_NT_HEADERS *
GetNtHeaders(std::optional<T> const &mod) noexcept
{
return mod ? GetNtHeaders(mod.value()) : nullptr;
}

/// @brief Retrieves the NT headers from a module base address.
/// @tparam T The type of the module base address.
/// @param hModule The module base address.
/// @return A pointer to the NT headers, or nullptr if not found.
template <class T>
requires pe::types::HandleLike<T>
inline const IMAGE_DATA_DIRECTORY* GetExportDirectoryImage(const T hModule)
Expand Down
10 changes: 10 additions & 0 deletions include/plib/proxy_lib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ extern volatile LONG g_reflect_ready;
extern "C" {
#endif // __cplusplus

/// @brief Registers a callback function to be called when a new RL_IMAGE is available.
/// @param callback The callback function to register. If nullptr, unregisters any existing callback.
/// @note It is possible to register only one callback per process.
DLL_EXPORT void RegisterProxyCallback(void(*callback)(const RL_IMAGE&));

#ifdef __cplusplus
Expand All @@ -34,6 +37,8 @@ DLL_EXPORT void RegisterProxyCallback(void(*callback)(const RL_IMAGE&));
#include <atomic>
#include <memory>

/// @brief Registers a C++ callable (lambda, function object, etc.) as a proxy callback.
/// @note This is intended for internal use; Don't refer to this namespace directly.
namespace proxycb_detail
{
struct IHandler {
Expand Down Expand Up @@ -73,6 +78,9 @@ namespace proxycb_detail
}
}

/// @brief Registers a C++ callable (lambda, function object, etc.) as a proxy callback.
/// @tparam F The type of the callable to register.
/// @param f The callable to register.
template<class F>
inline void RegisterProxyCallbackCpp(F&& f) {
using namespace proxycb_detail;
Expand All @@ -81,6 +89,8 @@ inline void RegisterProxyCallbackCpp(F&& f) {
RegisterProxyCallback(&Trampoline);
}

/// @brief Unregisters the currently registered proxy callback.
/// @param uninstall_trampoline If true, uninstalls the trampoline function (defaults to true).
inline void UnregisterProxyCallbackCpp(bool uninstall_trampoline = true) {
using namespace proxycb_detail;
g_handler.store(nullptr, std::memory_order_release);
Expand Down
1 change: 0 additions & 1 deletion include/plib/rl/rl_tls.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// rl/include/rl/rl_tls.h
#pragma once
#include <windows.h>
#include "rl_loader.h"
Expand Down
Loading