shjit
This commit is contained in:
35
examples/CS2-Internal-silenty/SourceEngine/Utils/Defines.h
Normal file
35
examples/CS2-Internal-silenty/SourceEngine/Utils/Defines.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
|
||||
#define _CS_INTERNAL_CONCATENATE(LEFT, RIGHT) LEFT##RIGHT
|
||||
#define CS_CONCATENATE(LEFT, RIGHT) _CS_INTERNAL_CONCATENATE(LEFT, RIGHT)
|
||||
#define MEM_PAD(SIZE) \
|
||||
private: \
|
||||
char CS_CONCATENATE(pad_0, __COUNTER__)[SIZE]; \
|
||||
public:
|
||||
|
||||
#define MAX_PATH 260
|
||||
|
||||
|
||||
#define SCHEMASYSTEM_TYPE_SCOPES_OFFSET 0x188
|
||||
#define SCHEMASYSTEMTYPESCOPE_OFF1 0x3F8
|
||||
#define SCHEMASYSTEMTYPESCOPE_OFF2 0x8
|
||||
|
||||
|
||||
|
||||
#define _NUMBER_MAX_BASE 36;
|
||||
|
||||
#define CLIENT_DLL (L"client.dll")
|
||||
#define SCENESYSTEM_DLL (L"scenesystem.dll")
|
||||
#define ENGINE2_DLL (L"engine2.dll")
|
||||
#define GAME_RESOURCE_SERVICE_CLIENT ("GameResourceServiceClientV00")
|
||||
#define SOURCE2_ENGINE_TO_CLIENT ("Source2EngineToClient00")
|
||||
|
||||
#define SCHEMASYSTEM_DLL L"schemasystem.dll"
|
||||
#define SCHEMA_SYSTEM "SchemaSystem_00"
|
||||
#define TIER0_DLL (L"tier0.dll")
|
||||
#define DBGHELP_DLL (L"dbghelp.dll")
|
||||
|
||||
|
||||
26
examples/CS2-Internal-silenty/SourceEngine/Utils/FNV1A.h
Normal file
26
examples/CS2-Internal-silenty/SourceEngine/Utils/FNV1A.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
using FNV1A_t = std::uint64_t;
|
||||
|
||||
namespace FNV1A
|
||||
{
|
||||
using FNV1A_t = std::uint64_t;
|
||||
|
||||
constexpr FNV1A_t ullBasis = 0xCBF29CE484222325ULL;
|
||||
constexpr FNV1A_t ullPrime = 0x100000001B3ULL;
|
||||
|
||||
consteval FNV1A_t HashConst(const char* szString, const FNV1A_t uKey = ullBasis) noexcept
|
||||
{
|
||||
return (szString[0] == '\0') ? uKey : HashConst(&szString[1], (uKey ^ static_cast<FNV1A_t>(szString[0])) * ullPrime);
|
||||
}
|
||||
|
||||
inline FNV1A_t Hash(const char* szString, FNV1A_t uKey = ullBasis) noexcept
|
||||
{
|
||||
while (*szString)
|
||||
{
|
||||
uKey ^= static_cast<FNV1A_t>(*szString++);
|
||||
uKey *= ullPrime;
|
||||
}
|
||||
|
||||
return uKey;
|
||||
}
|
||||
}
|
||||
196
examples/CS2-Internal-silenty/SourceEngine/Utils/Hashes.h
Normal file
196
examples/CS2-Internal-silenty/SourceEngine/Utils/Hashes.h
Normal file
@@ -0,0 +1,196 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
#include "Defines.h"
|
||||
|
||||
class CUtlMemoryPool
|
||||
{
|
||||
public:
|
||||
int Count() const
|
||||
{
|
||||
return nBlocksAllocated;
|
||||
}
|
||||
|
||||
int PeakCount() const
|
||||
{
|
||||
return nPeakAlloc;
|
||||
}
|
||||
|
||||
int BlockSize() const
|
||||
{
|
||||
return nBlockSize;
|
||||
}
|
||||
|
||||
protected:
|
||||
class CBlob
|
||||
{
|
||||
public:
|
||||
CBlob* pPrev;
|
||||
CBlob* pNext;
|
||||
int nNumBytes;
|
||||
char Data[1];
|
||||
char Padding[3];
|
||||
};
|
||||
|
||||
int nBlockSize;
|
||||
int nBlocksPerBlob;
|
||||
int nGrowMode;
|
||||
int nBlocksAllocated;
|
||||
int nPeakAlloc;
|
||||
|
||||
unsigned short nAlignment;
|
||||
unsigned short nNumBlobs;
|
||||
|
||||
void* pHeadOfFreeList;
|
||||
void* pAllocOwner;
|
||||
CBlob BlobHead;
|
||||
};
|
||||
|
||||
using UtlTSHashHandle_t = std::uintptr_t;
|
||||
|
||||
inline unsigned HashIntConventional(const int n)
|
||||
{
|
||||
unsigned hash = 0xAAAAAAAA + (n & 0xFF);
|
||||
hash = (hash << 5) + hash + ((n >> 8) & 0xFF);
|
||||
hash = (hash << 5) + hash + ((n >> 16) & 0xFF);
|
||||
hash = (hash << 5) + hash + ((n >> 24) & 0xFF);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <int nBucketCount, class tKey = std::uintptr_t>
|
||||
class CUtlTSHashGenericHash
|
||||
{
|
||||
public:
|
||||
static int Hash(const tKey& Key, int nBucketMask)
|
||||
{
|
||||
int nHash = HashIntConventional(std::uintptr_t(Key));
|
||||
if (nBucketCount <= UINT16_MAX)
|
||||
{
|
||||
nHash ^= (nHash >> 16);
|
||||
}
|
||||
|
||||
if (nBucketCount <= UINT8_MAX)
|
||||
{
|
||||
nHash ^= (nHash >> 8);
|
||||
}
|
||||
|
||||
return (nHash & nBucketMask);
|
||||
}
|
||||
|
||||
static bool Compare(const tKey& lhs, const tKey& rhs)
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <class tElement, int nBucketCount, class tKey = std::uintptr_t, class tHashFuncs = CUtlTSHashGenericHash<nBucketCount, tKey>, int nAlignment = 0>
|
||||
class CUtlTSHash
|
||||
{
|
||||
static constexpr int nBucketMask = nBucketCount - 1;
|
||||
|
||||
public:
|
||||
static constexpr UtlTSHashHandle_t InvalidHandle()
|
||||
{
|
||||
return static_cast<UtlTSHashHandle_t>(0);
|
||||
}
|
||||
|
||||
UtlTSHashHandle_t Find(tKey uiKey)
|
||||
{
|
||||
int iBucket = tHashFuncs::Hash(uiKey, nBucketCount);
|
||||
const HashBucket_t& hashBucket = aBuckets[iBucket];
|
||||
const UtlTSHashHandle_t hHash = Find(uiKey, hashBucket.pFirst, nullptr);
|
||||
return hHash ? hHash : Find(uiKey, hashBucket.pFirstUncommited, hashBucket.pFirst);
|
||||
}
|
||||
|
||||
int Count() const
|
||||
{
|
||||
return EntryMemory.Count();
|
||||
}
|
||||
|
||||
int GetElements(int nFirstElement, int nCount, UtlTSHashHandle_t* pHandles) const
|
||||
{
|
||||
int nIndex = 0;
|
||||
for (int nBucketIndex = 0; nBucketIndex < nBucketCount; nBucketIndex++)
|
||||
{
|
||||
const HashBucket_t& hashBucket = aBuckets[nBucketIndex];
|
||||
|
||||
HashFixedData_t* pElement = hashBucket.pFirstUncommited;
|
||||
for (; pElement; pElement = pElement->pNext)
|
||||
{
|
||||
if (--nFirstElement >= 0)
|
||||
continue;
|
||||
|
||||
pHandles[nIndex++] = reinterpret_cast<UtlTSHashHandle_t>(pElement);
|
||||
|
||||
if (nIndex >= nCount)
|
||||
return nIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return nIndex;
|
||||
}
|
||||
|
||||
tElement Element(UtlTSHashHandle_t hHash)
|
||||
{
|
||||
return ((HashFixedData_t*)(hHash))->Data;
|
||||
}
|
||||
|
||||
const tElement& Element(UtlTSHashHandle_t hHash) const
|
||||
{
|
||||
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
|
||||
}
|
||||
|
||||
tElement& operator[](UtlTSHashHandle_t hHash)
|
||||
{
|
||||
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
|
||||
}
|
||||
|
||||
const tElement& operator[](UtlTSHashHandle_t hHash) const
|
||||
{
|
||||
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
|
||||
}
|
||||
|
||||
tKey GetID(UtlTSHashHandle_t hHash) const
|
||||
{
|
||||
return reinterpret_cast<HashFixedData_t*>(hHash)->uiKey;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename tData>
|
||||
struct HashFixedDataInternal_t
|
||||
{
|
||||
tKey uiKey;
|
||||
HashFixedDataInternal_t<tData>* pNext;
|
||||
tData Data;
|
||||
};
|
||||
|
||||
using HashFixedData_t = HashFixedDataInternal_t<tElement>;
|
||||
|
||||
struct HashBucket_t
|
||||
{
|
||||
private:
|
||||
[[maybe_unused]] std::byte pad0[0x18];
|
||||
|
||||
public:
|
||||
HashFixedData_t* pFirst;
|
||||
HashFixedData_t* pFirstUncommited;
|
||||
};
|
||||
|
||||
UtlTSHashHandle_t Find(tKey uiKey, HashFixedData_t* pFirstElement, HashFixedData_t* pLastElement)
|
||||
{
|
||||
for (HashFixedData_t* pElement = pFirstElement; pElement != pLastElement; pElement = pElement->pNext)
|
||||
{
|
||||
if (tHashFuncs::Compare(pElement->uiKey, uiKey))
|
||||
return reinterpret_cast<UtlTSHashHandle_t>(pElement);
|
||||
}
|
||||
|
||||
return InvalidHandle();
|
||||
}
|
||||
|
||||
CUtlMemoryPool EntryMemory;
|
||||
MEM_PAD(0x40);
|
||||
HashBucket_t aBuckets[nBucketCount];
|
||||
bool bNeedsCommit;
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include "Memory.h"
|
||||
|
||||
using InstantiateInterfaceFn_t = void* (*)();
|
||||
|
||||
class ISchemaSystem;
|
||||
class IGameResourceService;
|
||||
class IEngineClient;
|
||||
class IEngineCVar;
|
||||
class Tracing;
|
||||
class IMemAlloc;
|
||||
|
||||
|
||||
class CInterfaceRegister
|
||||
{
|
||||
public:
|
||||
InstantiateInterfaceFn_t fnCreate;
|
||||
const char* szName;
|
||||
CInterfaceRegister* pNext;
|
||||
};
|
||||
|
||||
namespace I
|
||||
{
|
||||
static const CInterfaceRegister* GetRegisterList(const wchar_t* wszModuleName)
|
||||
{
|
||||
void* hModule = M::GetModuleBaseHandle(wszModuleName);
|
||||
if (hModule == nullptr)
|
||||
return nullptr;
|
||||
|
||||
std::uint8_t* pCreateInterface = reinterpret_cast<std::uint8_t*>(M::GetExportAddress(hModule, "CreateInterface"));
|
||||
|
||||
if (pCreateInterface == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return *reinterpret_cast<CInterfaceRegister**>(M::ResolveRelativeAddress(pCreateInterface, 0x3, 0x7));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T = void*>
|
||||
T* Capture(const CInterfaceRegister* pModuleRegister, const char* szInterfaceName)
|
||||
{
|
||||
std::size_t nInterfaceNameLength = std::strlen(szInterfaceName);
|
||||
|
||||
for (const CInterfaceRegister* pRegister = pModuleRegister; pRegister != nullptr; pRegister = pRegister->pNext)
|
||||
{
|
||||
std::size_t nRegisterNameLength = std::strlen(pRegister->szName);
|
||||
|
||||
if (std::strncmp(szInterfaceName, pRegister->szName, nInterfaceNameLength) == 0 &&
|
||||
(nRegisterNameLength == nInterfaceNameLength ||
|
||||
std::strtol(pRegister->szName + nInterfaceNameLength, nullptr, 10) > 0))
|
||||
{
|
||||
void* pInterface = pRegister->fnCreate();
|
||||
return static_cast<T*>(pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline ISchemaSystem* SchemaSystem = nullptr;
|
||||
inline Tracing* Trace = nullptr;
|
||||
inline IGameResourceService* GameResourceService = nullptr;
|
||||
inline IEngineClient* Engine = nullptr;
|
||||
inline IEngineCVar* Cvar = nullptr;
|
||||
inline IMemAlloc* MemAlloc = nullptr;
|
||||
|
||||
}
|
||||
|
||||
200
examples/CS2-Internal-silenty/SourceEngine/Utils/Memory.h
Normal file
200
examples/CS2-Internal-silenty/SourceEngine/Utils/Memory.h
Normal file
@@ -0,0 +1,200 @@
|
||||
#pragma once
|
||||
#include "Windows.h"
|
||||
#include "string"
|
||||
#include "vector"
|
||||
#include "cVector.h"
|
||||
#include "../qAngles.h"
|
||||
#include "Defines.h"
|
||||
|
||||
#ifndef DEG2RAD
|
||||
#define DEG2RAD(x) ((x) * (M_PI / 180.0f))
|
||||
#endif
|
||||
|
||||
|
||||
class CUtlBuffer;
|
||||
|
||||
namespace M
|
||||
{
|
||||
inline void* GetModuleBaseHandle(const wchar_t* wszModuleName)
|
||||
{
|
||||
if (wszModuleName == nullptr)
|
||||
return GetModuleHandle(nullptr);
|
||||
|
||||
HMODULE hModule = GetModuleHandleW(wszModuleName);
|
||||
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
inline constexpr int StringCompare(const C* tszLeft, const C* tszRight)
|
||||
{
|
||||
if constexpr (std::is_same_v<C, char>)
|
||||
{
|
||||
return std::strcmp(tszLeft, tszRight);
|
||||
}
|
||||
else if constexpr (std::is_same_v<C, wchar_t>)
|
||||
{
|
||||
return std::wcscmp(tszLeft, tszRight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void* GetExportAddress(const void* hModuleBase, const char* szProcedureName)
|
||||
{
|
||||
const auto pBaseAddress = static_cast<const std::uint8_t*>(hModuleBase);
|
||||
|
||||
const auto pIDH = static_cast<const IMAGE_DOS_HEADER*>(hModuleBase);
|
||||
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
return nullptr;
|
||||
|
||||
const auto pINH = reinterpret_cast<const IMAGE_NT_HEADERS64*>(pBaseAddress + pIDH->e_lfanew);
|
||||
if (pINH->Signature != IMAGE_NT_SIGNATURE)
|
||||
return nullptr;
|
||||
|
||||
const IMAGE_OPTIONAL_HEADER64* pIOH = &pINH->OptionalHeader;
|
||||
const std::uintptr_t nExportDirectorySize = pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
||||
const std::uintptr_t uExportDirectoryAddress = pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
|
||||
if (nExportDirectorySize == 0U || uExportDirectoryAddress == 0U)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto pIED = reinterpret_cast<const IMAGE_EXPORT_DIRECTORY*>(pBaseAddress + uExportDirectoryAddress);
|
||||
const auto pNamesRVA = reinterpret_cast<const std::uint32_t*>(pBaseAddress + pIED->AddressOfNames);
|
||||
const auto pNameOrdinalsRVA = reinterpret_cast<const std::uint16_t*>(pBaseAddress + pIED->AddressOfNameOrdinals);
|
||||
const auto pFunctionsRVA = reinterpret_cast<const std::uint32_t*>(pBaseAddress + pIED->AddressOfFunctions);
|
||||
|
||||
// Perform binary search to find the export by name
|
||||
std::size_t nRight = pIED->NumberOfNames, nLeft = 0U;
|
||||
|
||||
while (nRight != nLeft)
|
||||
{
|
||||
// Avoid INT_MAX/2 overflow
|
||||
const std::size_t uMiddle = nLeft + ((nRight - nLeft) >> 1U);
|
||||
const int iResult = StringCompare(szProcedureName, reinterpret_cast<const char*>(pBaseAddress + pNamesRVA[uMiddle]));
|
||||
|
||||
if (iResult == 0)
|
||||
{
|
||||
const std::uint32_t uFunctionRVA = pFunctionsRVA[pNameOrdinalsRVA[uMiddle]];
|
||||
|
||||
|
||||
// Check if it's a forwarded export
|
||||
if (uFunctionRVA >= uExportDirectoryAddress && uFunctionRVA - uExportDirectoryAddress < nExportDirectorySize)
|
||||
{
|
||||
// Forwarded exports are not supported
|
||||
break;
|
||||
}
|
||||
|
||||
return const_cast<std::uint8_t*>(pBaseAddress) + uFunctionRVA;
|
||||
}
|
||||
|
||||
if (iResult > 0)
|
||||
nLeft = uMiddle + 1;
|
||||
else
|
||||
nRight = uMiddle;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t nIndex, class CBaseClass, typename... Args_t>
|
||||
static 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...);
|
||||
}
|
||||
|
||||
inline std::vector<int> PatternToBytes(const char* pattern) {
|
||||
std::vector<int> bytes;
|
||||
const char* current = pattern;
|
||||
while (*current) {
|
||||
if (*current == '?') {
|
||||
bytes.push_back(-1); // Wildcard
|
||||
current++;
|
||||
if (*current == '?') current++; // Skip second '?'
|
||||
}
|
||||
else {
|
||||
bytes.push_back(static_cast<int>(std::strtoul(current, nullptr, 16)));
|
||||
current += 2;
|
||||
}
|
||||
if (*current == ' ') current++; // Skip spaces
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
inline uintptr_t FindPattern(const wchar_t* moduleName, const char* pattern)
|
||||
{
|
||||
HMODULE hModule = GetModuleHandleW(moduleName);
|
||||
if (!hModule) return 0;
|
||||
|
||||
std::uint8_t* moduleBase = reinterpret_cast<std::uint8_t*>(hModule);
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(moduleBase + reinterpret_cast<PIMAGE_DOS_HEADER>(moduleBase)->e_lfanew);
|
||||
std::size_t moduleSize = ntHeaders->OptionalHeader.SizeOfImage;
|
||||
|
||||
std::vector<int> patternBytes = PatternToBytes(pattern);
|
||||
std::size_t patternLength = patternBytes.size();
|
||||
|
||||
for (std::size_t i = 0; i <= moduleSize - patternLength; i++) {
|
||||
bool found = true;
|
||||
for (std::size_t j = 0; j < patternLength; j++) {
|
||||
if (patternBytes[j] != -1 && patternBytes[j] != moduleBase[i + j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
return reinterpret_cast<uintptr_t>(moduleBase + i);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename T = uintptr_t>
|
||||
T GetAbsoluteAddress(T pRelativeAddress, int nPreOffset = 0x0, int nPostOffset = 0x0) {
|
||||
std::int32_t relativeOffset = *reinterpret_cast<std::int32_t*>(reinterpret_cast<std::uint8_t*>(pRelativeAddress) + nPreOffset);
|
||||
return pRelativeAddress + relativeOffset + sizeof(std::int32_t) + nPreOffset + nPostOffset;
|
||||
}
|
||||
|
||||
inline void** CopyVirtualTable(void** Original)
|
||||
{
|
||||
constexpr int Entries = 8192 / sizeof(void*);
|
||||
|
||||
void** NewVTable = new void* [Entries];
|
||||
|
||||
for (int i = 0; i < Entries; ++i)
|
||||
NewVTable[i] = Original[i];
|
||||
|
||||
|
||||
return NewVTable;
|
||||
}
|
||||
|
||||
inline Vector_t AngleToDirection(const QAngle_t& Angles)
|
||||
{
|
||||
Vector_t Direction;
|
||||
float Pitch = DEG2RAD(Angles.x);
|
||||
float Yaw = DEG2RAD(Angles.y);
|
||||
|
||||
Direction.x = cos(Pitch) * cos(Yaw);
|
||||
Direction.y = cos(Pitch) * sin(Yaw);
|
||||
Direction.z = -sin(Pitch);
|
||||
|
||||
return Direction;
|
||||
}
|
||||
|
||||
inline void(__fastcall* fnUtlBufferInit)(CUtlBuffer*, int, int, int);
|
||||
inline void(__fastcall* fnUtlBufferPutString)(CUtlBuffer*, const char*);
|
||||
inline void(__fastcall* fnUtlBufferEnsureCapacity)(CUtlBuffer*, int);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace detail {
|
||||
extern "C" void* _spoofer_stub();
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
static auto shellcode_stub_helper(
|
||||
const void* shell,
|
||||
Args... args
|
||||
) -> Ret {
|
||||
auto fn = (Ret(*)(Args...))(shell);
|
||||
return fn(args...);
|
||||
}
|
||||
|
||||
template <std::size_t Argc, typename>
|
||||
struct argument_remapper {
|
||||
// At least 5 params
|
||||
template<
|
||||
typename Ret,
|
||||
typename First,
|
||||
typename Second,
|
||||
typename Third,
|
||||
typename Fourth,
|
||||
typename... Pack
|
||||
>
|
||||
static auto do_call(
|
||||
const void* shell,
|
||||
void* shell_param,
|
||||
First first,
|
||||
Second second,
|
||||
Third third,
|
||||
Fourth fourth,
|
||||
Pack... pack
|
||||
) -> Ret {
|
||||
return shellcode_stub_helper<
|
||||
Ret,
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
Fourth,
|
||||
void*,
|
||||
void*,
|
||||
Pack...
|
||||
>(
|
||||
shell,
|
||||
first,
|
||||
second,
|
||||
third,
|
||||
fourth,
|
||||
shell_param,
|
||||
nullptr,
|
||||
pack...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t Argc>
|
||||
struct argument_remapper<Argc, std::enable_if_t<Argc <= 4>> {
|
||||
// 4 or less params
|
||||
template<
|
||||
typename Ret,
|
||||
typename First = void*,
|
||||
typename Second = void*,
|
||||
typename Third = void*,
|
||||
typename Fourth = void*
|
||||
>
|
||||
static auto do_call(
|
||||
const void* shell,
|
||||
void* shell_param,
|
||||
First first = First{},
|
||||
Second second = Second{},
|
||||
Third third = Third{},
|
||||
Fourth fourth = Fourth{}
|
||||
) -> Ret {
|
||||
return shellcode_stub_helper<
|
||||
Ret,
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
Fourth,
|
||||
void*,
|
||||
void*
|
||||
>(
|
||||
shell,
|
||||
first,
|
||||
second,
|
||||
third,
|
||||
fourth,
|
||||
shell_param,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename result, typename... arguments>
|
||||
static auto FakeReturnAddress(
|
||||
const void* trampoline,
|
||||
result(*fn)(arguments...),
|
||||
arguments... args
|
||||
) -> result {
|
||||
struct shell_params {
|
||||
const void* trampoline;
|
||||
void* function;
|
||||
void* register_; // originally rbx, currently rdx
|
||||
};
|
||||
|
||||
shell_params p = { trampoline, reinterpret_cast<void*>(fn) };
|
||||
using mapper = detail::argument_remapper<sizeof...(arguments), void>;
|
||||
return mapper::template do_call<result, arguments...>((const void*)&detail::_spoofer_stub, &p, args...);
|
||||
}
|
||||
400
examples/CS2-Internal-silenty/SourceEngine/Utils/cVector.h
Normal file
400
examples/CS2-Internal-silenty/SourceEngine/Utils/cVector.h
Normal file
@@ -0,0 +1,400 @@
|
||||
#pragma once
|
||||
// used: [stl] numeric_limits
|
||||
#include <limits>
|
||||
// used: [crt] isfinite, fmodf, sqrtf
|
||||
#include <cmath>
|
||||
|
||||
// forward declarations
|
||||
struct QAngle_t;
|
||||
struct Matrix3x4_t;
|
||||
|
||||
// @source: master/public/mathlib/vector.h
|
||||
|
||||
struct Vector2D_t
|
||||
{
|
||||
constexpr Vector2D_t(const float x = 0.0f, const float y = 0.0f) :
|
||||
x(x), y(y) { }
|
||||
|
||||
[[nodiscard]] bool IsZero() const
|
||||
{
|
||||
// @note: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
|
||||
return (this->x == 0.0f && this->y == 0.0f);
|
||||
}
|
||||
|
||||
float DistanceTo(const Vector2D_t& other) const
|
||||
{
|
||||
float dx = x - other.x;
|
||||
float dy = y - other.y;
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
float x = 0.0f, y = 0.0f;
|
||||
};
|
||||
|
||||
struct Vector_t
|
||||
{
|
||||
constexpr Vector_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f) :
|
||||
x(x), y(y), z(z) { }
|
||||
|
||||
constexpr Vector_t(const float* arrVector) :
|
||||
x(arrVector[0]), y(arrVector[1]), z(arrVector[2]) { }
|
||||
|
||||
constexpr Vector_t(const Vector2D_t& vecBase2D) :
|
||||
x(vecBase2D.x), y(vecBase2D.y) { }
|
||||
|
||||
#pragma region vector_array_operators
|
||||
|
||||
[[nodiscard]] float& operator[](const int nIndex)
|
||||
{
|
||||
return reinterpret_cast<float*>(this)[nIndex];
|
||||
}
|
||||
|
||||
[[nodiscard]] const float& operator[](const int nIndex) const
|
||||
{
|
||||
return reinterpret_cast<const float*>(this)[nIndex];
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region vector_relational_operators
|
||||
|
||||
bool operator==(const Vector_t& vecBase) const
|
||||
{
|
||||
return this->IsEqual(vecBase);
|
||||
}
|
||||
|
||||
bool operator!=(const Vector_t& vecBase) const
|
||||
{
|
||||
return !this->IsEqual(vecBase);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region vector_assignment_operators
|
||||
|
||||
constexpr Vector_t& operator=(const Vector_t& vecBase)
|
||||
{
|
||||
this->x = vecBase.x;
|
||||
this->y = vecBase.y;
|
||||
this->z = vecBase.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator=(const Vector2D_t& vecBase2D)
|
||||
{
|
||||
this->x = vecBase2D.x;
|
||||
this->y = vecBase2D.y;
|
||||
this->z = 0.0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region vector_arithmetic_assignment_operators
|
||||
|
||||
constexpr Vector_t& operator+=(const Vector_t& vecBase)
|
||||
{
|
||||
this->x += vecBase.x;
|
||||
this->y += vecBase.y;
|
||||
this->z += vecBase.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator-=(const Vector_t& vecBase)
|
||||
{
|
||||
this->x -= vecBase.x;
|
||||
this->y -= vecBase.y;
|
||||
this->z -= vecBase.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator*=(const Vector_t& vecBase)
|
||||
{
|
||||
this->x *= vecBase.x;
|
||||
this->y *= vecBase.y;
|
||||
this->z *= vecBase.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator/=(const Vector_t& vecBase)
|
||||
{
|
||||
this->x /= vecBase.x;
|
||||
this->y /= vecBase.y;
|
||||
this->z /= vecBase.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator+=(const float flAdd)
|
||||
{
|
||||
this->x += flAdd;
|
||||
this->y += flAdd;
|
||||
this->z += flAdd;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator-=(const float flSubtract)
|
||||
{
|
||||
this->x -= flSubtract;
|
||||
this->y -= flSubtract;
|
||||
this->z -= flSubtract;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator*=(const float flMultiply)
|
||||
{
|
||||
this->x *= flMultiply;
|
||||
this->y *= flMultiply;
|
||||
this->z *= flMultiply;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t& operator/=(const float flDivide)
|
||||
{
|
||||
this->x /= flDivide;
|
||||
this->y /= flDivide;
|
||||
this->z /= flDivide;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region vector_arithmetic_unary_operators
|
||||
|
||||
constexpr Vector_t& operator-()
|
||||
{
|
||||
this->x = -this->x;
|
||||
this->y = -this->y;
|
||||
this->z = -this->z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Vector_t operator-() const
|
||||
{
|
||||
return { -this->x, -this->y, -this->z };
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region vector_arithmetic_ternary_operators
|
||||
|
||||
Vector_t operator+(const Vector_t& vecAdd) const
|
||||
{
|
||||
return { this->x + vecAdd.x, this->y + vecAdd.y, this->z + vecAdd.z };
|
||||
}
|
||||
|
||||
Vector_t operator-(const Vector_t& vecSubtract) const
|
||||
{
|
||||
return { this->x - vecSubtract.x, this->y - vecSubtract.y, this->z - vecSubtract.z };
|
||||
}
|
||||
|
||||
Vector_t operator*(const Vector_t& vecMultiply) const
|
||||
{
|
||||
return { this->x * vecMultiply.x, this->y * vecMultiply.y, this->z * vecMultiply.z };
|
||||
}
|
||||
|
||||
Vector_t operator/(const Vector_t& vecDivide) const
|
||||
{
|
||||
return { this->x / vecDivide.x, this->y / vecDivide.y, this->z / vecDivide.z };
|
||||
}
|
||||
|
||||
Vector_t operator+(const float flAdd) const
|
||||
{
|
||||
return { this->x + flAdd, this->y + flAdd, this->z + flAdd };
|
||||
}
|
||||
|
||||
Vector_t operator-(const float flSubtract) const
|
||||
{
|
||||
return { this->x - flSubtract, this->y - flSubtract, this->z - flSubtract };
|
||||
}
|
||||
|
||||
Vector_t operator*(const float flMultiply) const
|
||||
{
|
||||
return { this->x * flMultiply, this->y * flMultiply, this->z * flMultiply };
|
||||
}
|
||||
|
||||
Vector_t operator/(const float flDivide) const
|
||||
{
|
||||
return { this->x / flDivide, this->y / flDivide, this->z / flDivide };
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
/// @returns: true if each component of the vector is finite, false otherwise
|
||||
[[nodiscard]] bool IsValid() const
|
||||
{
|
||||
return std::isfinite(this->x) && std::isfinite(this->y) && std::isfinite(this->z);
|
||||
}
|
||||
|
||||
constexpr void Invalidate()
|
||||
{
|
||||
this->x = this->y = this->z = std::numeric_limits<float>::infinity();
|
||||
}
|
||||
|
||||
/// @returns: true if each component of the vector equals to another, false otherwise
|
||||
[[nodiscard]] bool IsEqual(const Vector_t& vecEqual, const float flErrorMargin = std::numeric_limits<float>::epsilon()) const
|
||||
{
|
||||
return (std::fabsf(this->x - vecEqual.x) < flErrorMargin && std::fabsf(this->y - vecEqual.y) < flErrorMargin && std::fabsf(this->z - vecEqual.z) < flErrorMargin);
|
||||
}
|
||||
|
||||
/// @returns: true if each component of the vector equals to zero, false otherwise
|
||||
[[nodiscard]] bool IsZero() const
|
||||
{
|
||||
// @note: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
|
||||
return (this->x == 0.0f && this->y == 0.0f && this->z == 0.0f);
|
||||
}
|
||||
|
||||
[[nodiscard]] float Length() const
|
||||
{
|
||||
return std::sqrtf(this->LengthSqr());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr float LengthSqr() const
|
||||
{
|
||||
return DotProduct(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] float Length2D() const
|
||||
{
|
||||
return std::sqrtf(this->Length2DSqr());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr float Length2DSqr() const
|
||||
{
|
||||
return (this->x * this->x + this->y * this->y);
|
||||
}
|
||||
|
||||
[[nodiscard]] float DistTo(const Vector_t& vecEnd) const
|
||||
{
|
||||
return (*this - vecEnd).Length();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr float DistToSqr(const Vector_t& vecEnd) const
|
||||
{
|
||||
return (*this - vecEnd).LengthSqr();
|
||||
}
|
||||
|
||||
/// normalize magnitude of each component of the vector
|
||||
/// @returns: length of the vector
|
||||
float NormalizeInPlace()
|
||||
{
|
||||
const float flLength = this->Length();
|
||||
const float flRadius = 1.0f / (flLength + std::numeric_limits<float>::epsilon());
|
||||
|
||||
this->x *= flRadius;
|
||||
this->y *= flRadius;
|
||||
this->z *= flRadius;
|
||||
|
||||
return flLength;
|
||||
}
|
||||
|
||||
/// normalize magnitude of each component of the vector
|
||||
/// @returns: copy of the vector with normalized components
|
||||
[[nodiscard]] Vector_t Normalized() const
|
||||
{
|
||||
Vector_t vecOut = *this;
|
||||
vecOut.NormalizeInPlace();
|
||||
return vecOut;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr float DotProduct(const Vector_t& vecDot) const
|
||||
{
|
||||
return (this->x * vecDot.x + this->y * vecDot.y + this->z * vecDot.z);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector_t CrossProduct(const Vector_t& vecCross) const
|
||||
{
|
||||
return { this->y * vecCross.z - this->z * vecCross.y, this->z * vecCross.x - this->x * vecCross.z, this->x * vecCross.y - this->y * vecCross.x };
|
||||
}
|
||||
|
||||
/// @returns: transformed vector by given transformation matrix
|
||||
[[nodiscard]] Vector_t Transform(const Matrix3x4_t& matTransform) const;
|
||||
|
||||
[[nodiscard]] Vector2D_t ToVector2D() const
|
||||
{
|
||||
return { this->x, this->y };
|
||||
}
|
||||
|
||||
/// convert forward direction vector to other direction vectors
|
||||
/// @param[out] pvecRight [optional] output for converted right vector
|
||||
/// @param[out] pvecUp [optional] output for converted up vector
|
||||
void ToDirections(Vector_t* pvecRight, Vector_t* pvecUp) const
|
||||
{
|
||||
if (std::fabsf(this->x) < 1e-6f && std::fabsf(this->y) < 1e-6f)
|
||||
{
|
||||
// pitch 90 degrees up/down from identity
|
||||
if (pvecRight != nullptr)
|
||||
{
|
||||
pvecRight->x = 0.0f;
|
||||
pvecRight->y = -1.0f;
|
||||
pvecRight->z = 0.0f;
|
||||
}
|
||||
|
||||
if (pvecUp != nullptr)
|
||||
{
|
||||
pvecUp->x = -this->z;
|
||||
pvecUp->y = 0.0f;
|
||||
pvecUp->z = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pvecRight != nullptr)
|
||||
{
|
||||
pvecRight->x = this->y;
|
||||
pvecRight->y = -this->x;
|
||||
pvecRight->z = 0.0f;
|
||||
pvecRight->NormalizeInPlace();
|
||||
}
|
||||
|
||||
if (pvecUp != nullptr)
|
||||
{
|
||||
pvecUp->x = (-this->x) * this->z;
|
||||
pvecUp->y = -(this->y * this->z);
|
||||
pvecUp->z = this->y * this->y - (-this->x) * this->x;
|
||||
pvecUp->NormalizeInPlace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @returns: 2D angles converted from direction vector
|
||||
[[nodiscard]] QAngle_t ToAngles() const;
|
||||
|
||||
/// @returns: matrix converted from forward direction vector
|
||||
[[nodiscard]] Matrix3x4_t ToMatrix() const;
|
||||
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
};
|
||||
|
||||
struct Vector4D_t
|
||||
{
|
||||
constexpr Vector4D_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f, const float w = 0.0f) :
|
||||
x(x), y(y), z(z), w(w) { }
|
||||
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f, w = 0.0f;
|
||||
};
|
||||
|
||||
struct alignas(16) VectorAligned_t : Vector_t
|
||||
{
|
||||
VectorAligned_t() = default;
|
||||
|
||||
explicit VectorAligned_t(const Vector_t& vecBase)
|
||||
{
|
||||
this->x = vecBase.x;
|
||||
this->y = vecBase.y;
|
||||
this->z = vecBase.z;
|
||||
this->w = 0.0f;
|
||||
}
|
||||
|
||||
constexpr VectorAligned_t& operator=(const Vector_t& vecBase)
|
||||
{
|
||||
this->x = vecBase.x;
|
||||
this->y = vecBase.y;
|
||||
this->z = vecBase.z;
|
||||
this->w = 0.0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float w = 0.0f;
|
||||
};
|
||||
|
||||
static_assert(alignof(VectorAligned_t) == 16);
|
||||
@@ -0,0 +1,32 @@
|
||||
PUBLIC _spoofer_stub
|
||||
option casemap :none
|
||||
|
||||
; if the line is labelled as MODIFY you need to modify the register it reads or writes to
|
||||
; valid registers include: rbx, rbp+0x0, rdi, rsi, r12, r13+0x0, r14, r15
|
||||
|
||||
_TEXT SEGMENT
|
||||
_spoofer_stub PROC
|
||||
pop r11 ; poping without setting up stack frame, r11 is the return address (the one in our code)
|
||||
add rsp, 8 ; skipping callee reserved space
|
||||
mov rax, [rsp + 24] ; dereference shell_param
|
||||
|
||||
mov r10, [rax] ; load shell_param.trampoline
|
||||
mov [rsp], r10 ; store address of trampoline as return address
|
||||
|
||||
mov r10, [rax + 8] ; load shell_param.function
|
||||
mov [rax + 8], r11 ; store the original return address in shell_param.function
|
||||
|
||||
mov [rax + 16], rdi ; preserve register in shell_param.register_ | MODIFY
|
||||
lea rdi, fixup ; load fixup address in register | MODIFY
|
||||
mov [rax], rdi ; store address of fixup label in shell_param.trampoline | MODIFY
|
||||
mov rdi, rax ; preserve address of shell_param in register | MODIFY
|
||||
|
||||
jmp r10 ; call shell_param.function
|
||||
fixup:
|
||||
sub rsp, 16
|
||||
mov rcx, rdi ; restore address of shell_param | MODIFY
|
||||
mov rdi, [rcx + 16] ; restore register from shell_param.register_ | MODIFY
|
||||
jmp QWORD PTR [rcx + 8] ; jmp to the original return address
|
||||
_spoofer_stub ENDP
|
||||
_TEXT ENDS
|
||||
END
|
||||
Reference in New Issue
Block a user