#pragma once // used: memory api #include // used: std::vector #include #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(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 [[nodiscard]] T* GetAbsoluteAddress(T* pRelativeAddress, int nPreOffset = 0x0, int nPostOffset = 0x0) { pRelativeAddress += nPreOffset; pRelativeAddress += sizeof(std::int32_t) + *reinterpret_cast(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(nAddressBytes + nRVAOffset); std::uint64_t nRIP = reinterpret_cast(nAddressBytes) + nRIPOffset; return reinterpret_cast(nRVA + nRIP); } /// get pointer to function of virtual-function table /// @returns: pointer to virtual function template [[nodiscard]] CS_INLINE T GetVFunc(const void* thisptr, std::size_t nIndex) { return (*static_cast(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 static CS_INLINE T CallVFunc(CBaseClass* thisptr, Args_t... argList) { using VirtualFn_t = T(__thiscall*)(const void*, decltype(argList)...); return (*reinterpret_cast(reinterpret_cast(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 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); }