2025-07-22 22:06:34 +03:00

151 lines
8.5 KiB
C++

#pragma once
// used: memory api
#include <memory>
// used: std::vector
#include <vector>
#include "../common.h"
#pragma region memory_definitions
#pragma warning(push)
#pragma warning(disable: 6255) // '_alloca' indicates failure by raising a stack overflow exception. consider using '_malloca' instead
#define MEM_STACKALLOC(SIZE) _malloca(SIZE)
#pragma warning(pop)
#define MEM_STACKFREE(MEMORY) static_cast<void>(0)
#define MEM_PAD(SIZE) \
private: \
char CS_CONCATENATE(pad_0, __COUNTER__)[SIZE]; \
public:
#pragma endregion
class CUtlBuffer;
class CKeyValues3;
struct KV3ID_t;
namespace MEM
{
bool Setup();
/* @section: allocation */
// allocate a block of memory from a heap
[[nodiscard]] void* HeapAlloc(const std::size_t nSize);
// free a memory block allocated from a heap
void HeapFree(void* pMemory);
// reallocate a block of memory from a heap
// @note: we're expect this to allocate instead when passed null, and free if size is null
void* HeapRealloc(void* pMemory, const std::size_t nNewSize);
/* @section: get */
/// alternative of 'GetModuleHandle()'
/// @param[in] wszModuleName module name to search base handle for, null means current process
/// @returns: base handle of module with given name if it exist, null otherwise
[[nodiscard]] void* GetModuleBaseHandle(const wchar_t* wszModuleName);
/// alternative of 'GetModuleFileName()'
/// @param[in] hModuleBase module base to search filename for, null means current process
/// @returns: name of given module if it's valid, null otherwise
[[nodiscard]] const wchar_t* GetModuleBaseFileName(const void* hModuleBase, const bool bGetFullPath = false);
/// alternative of 'GetProcAddress()'
/// @remarks: doesn't support forwarded exports, this means you may need to manual call 'LoadLibrary'/'FreeLibrary' for export library
/// @returns: pointer to exported procedure
[[nodiscard]] void* GetExportAddress(const void* hModuleBase, const char* szProcedureName);
/// @param[in] szSectionName section to get info of (e.g. ".rdata", ".text", etc)
/// @param[out] ppSectionStart output for section start address
/// @param[out] pnSectionSize output for section size
/// @returns: true if code section has been found, false otherwise
[[nodiscard]] bool GetSectionInfo(const void* hModuleBase, const char* szSectionName, std::uint8_t** ppSectionStart, std::size_t* pnSectionSize);
/// get absolute address from relative address
/// @param[in] pRelativeAddress pointer to relative address, e.g. destination address from JMP, JE, JNE and others instructions
/// @param[in] nPreOffset offset before relative address
/// @param[in] nPostOffset offset after relative address
/// @returns: pointer to absolute address
template <typename T = std::uint8_t>
[[nodiscard]] T* GetAbsoluteAddress(T* pRelativeAddress, int nPreOffset = 0x0, int nPostOffset = 0x0)
{
pRelativeAddress += nPreOffset;
pRelativeAddress += sizeof(std::int32_t) + *reinterpret_cast<std::int32_t*>(pRelativeAddress);
pRelativeAddress += nPostOffset;
return pRelativeAddress;
}
/// resolve rip relative address
/// @param[in] nAddressBytes as byte for the address we want to resolve
/// @param[in] nRVAOffset offset of the relative address
/// @param[in] nRIPOffset offset of the instruction pointer
/// @returns: pointer to resolved address
[[nodiscard]] CS_INLINE std::uint8_t* ResolveRelativeAddress(std::uint8_t* nAddressBytes, std::uint32_t nRVAOffset, std::uint32_t nRIPOffset)
{
std::uint32_t nRVA = *reinterpret_cast<std::uint32_t*>(nAddressBytes + nRVAOffset);
std::uint64_t nRIP = reinterpret_cast<std::uint64_t>(nAddressBytes) + nRIPOffset;
return reinterpret_cast<std::uint8_t*>(nRVA + nRIP);
}
/// get pointer to function of virtual-function table
/// @returns: pointer to virtual function
template <typename T = void*>
[[nodiscard]] CS_INLINE T GetVFunc(const void* thisptr, std::size_t nIndex)
{
return (*static_cast<T* const*>(thisptr))[nIndex];
}
/// call virtual function of specified class at given index
/// @note: reference and const reference arguments must be forwarded as pointers or wrapped with 'std::ref'/'std::cref' calls!
/// @returns: result of virtual function call
template <typename T, std::size_t nIndex, class CBaseClass, typename... Args_t>
static CS_INLINE T CallVFunc(CBaseClass* thisptr, Args_t... argList)
{
using VirtualFn_t = T(__thiscall*)(const void*, decltype(argList)...);
return (*reinterpret_cast<VirtualFn_t* const*>(reinterpret_cast<std::uintptr_t>(thisptr)))[nIndex](thisptr, argList...);
}
/* @section: search */
/// ida style pattern byte comparison in a specific mo dule
/// @param[in] wszModuleName module name where to search for pattern
/// @param[in] szPattern ida style pattern, e.g. "55 8B 40 ? 30", wildcard can be either '?' or "??", bytes always presented by two numbers in a row [00 .. FF], whitespaces can be omitted (wildcards in this case should be two-character)
/// @returns: pointer to address of the first found occurrence with equal byte sequence on success, null otherwise
[[nodiscard]] std::uint8_t* FindPattern(const wchar_t* wszModuleName, const char* szPattern);
/// naive style pattern byte comparison in a specific module
/// @param[in] wszModuleName module name where to search for pattern
/// @param[in] szBytePattern naive style pattern, e.g. "\x55\x8B\x40\x00\x30", wildcard bytes value ignored
/// @param[in] szByteMask wildcard mask for byte array, e.g. "xxx?x", should always correspond to bytes count
/// @returns: pointer to address of the first found occurrence with equal byte sequence on success, null otherwise
[[nodiscard]] std::uint8_t* FindPattern(const wchar_t* wszModuleName, const char* szBytePattern, const char* szByteMask);
/// pattern byte comparison in the specific region
/// @param[in] arrByteBuffer byte sequence to search
/// @param[in] nByteCount count of search bytes
/// @param[in] szByteMask [optional] wildcard mask for byte array
/// @returns: pointer to address of the first found occurrence with equal byte sequence on success, null otherwise
[[nodiscard]] std::uint8_t* FindPatternEx(const std::uint8_t* pRegionStart, const std::size_t nRegionSize, const std::uint8_t* arrByteBuffer, const std::size_t nByteCount, const char* szByteMask = nullptr);
/// pattern byte comparison in the specific region
/// @param[in] arrByteBuffer byte sequence to search
/// @param[in] nByteCount count of search bytes
/// @param[in] szByteMask [optional] wildcard mask for byte array
/// @returns: pointers to addresses of the all found occurrences with equal byte sequence on success, empty otherwise
[[nodiscard]] std::vector<std::uint8_t*> FindPatternAllOccurrencesEx(const std::uint8_t* pRegionStart, const std::size_t nRegionSize, const std::uint8_t* arrByteBuffer, const std::size_t nByteCount, const char* szByteMask = nullptr);
/// class RTTI virtual table search in a specific module
/// @returns: pointer to the found virtual table on success, null otherwise
/* @section: extra */
/// convert ida-style pattern to byte array
/// @param[in] szPattern ida-style pattern, e.g. "55 8B 40 ? 30", wildcard can be either '?' or "??", bytes are always presented by two numbers in a row [00 .. FF], blank delimiters are ignored and not necessary (wildcard in this case should be two-character)
/// @param[out] pOutByteBuffer output for converted, zero-terminated byte array
/// @param[out] szOutMaskBuffer output for wildcard, zero-terminated byte mask
/// @returns: count of the converted bytes from the pattern
std::size_t PatternToBytes(const char* szPattern, std::uint8_t* pOutByteBuffer, char* szOutMaskBuffer);
/// convert byte array to ida-style pattern
/// @param[in] pByteBuffer buffer of bytes to convert
/// @param[in] nByteCount count of bytes to convert
/// @param[out] szOutBuffer output for converted pattern
/// @returns: length of the converted ida-style pattern, not including the terminating null
std::size_t BytesToPattern(const std::uint8_t* pByteBuffer, const std::size_t nByteCount, char* szOutBuffer);
/* @section: game exports */
inline unsigned long(CS_STDCALL* fnUnDecorateSymbolName)(const char* szName, char* pszOutput, unsigned long nMaxStringLength, unsigned long dwFlags) = nullptr;
inline bool(CS_FASTCALL* fnLoadKV3)(CKeyValues3*, void*, const char*, const KV3ID_t*, const char*);
inline std::int64_t(CS_FASTCALL* fnCreateMaterial)(void*, void*, const char*, void*, unsigned int, unsigned int);
inline void(CS_FASTCALL* fnUtlBufferInit)(CUtlBuffer*, int, int, int);
inline void(CS_FASTCALL* fnUtlBufferPutString)(CUtlBuffer*, const char*);
inline void(CS_FASTCALL* fnUtlBufferEnsureCapacity)(CUtlBuffer*, int);
}