diff --git a/csgo2.sln b/csgo2.sln new file mode 100644 index 0000000..e34f30d --- /dev/null +++ b/csgo2.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.33130.400 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csgo2", "csgo2\csgo2.vcxproj", "{0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Debug|x64.ActiveCfg = Debug|x64 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Debug|x64.Build.0 = Debug|x64 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Debug|x86.ActiveCfg = Debug|Win32 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Debug|x86.Build.0 = Debug|Win32 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Release|x64.ActiveCfg = Release|x64 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Release|x64.Build.0 = Release|x64 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Release|x86.ActiveCfg = Release|Win32 + {0AF170B6-CC8D-4A56-9879-5064F3D3EBDB}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {14904916-41DB-45E6-A72D-6AE7FD145050} + EndGlobalSection +EndGlobal diff --git a/csgo2/MinHook/.gitkeep b/csgo2/MinHook/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/csgo2/MinHook/.gitkeep @@ -0,0 +1 @@ + diff --git a/csgo2/MinHook/include/MinHook.h b/csgo2/MinHook/include/MinHook.h new file mode 100644 index 0000000..15c0a87 --- /dev/null +++ b/csgo2/MinHook/include/MinHook.h @@ -0,0 +1,186 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) + #error MinHook supports only x86 and x64 systems. +#endif + +#include + +// MinHook Error Codes. +typedef enum MH_STATUS +{ + // Unknown error. Should not be returned. + MH_UNKNOWN = -1, + + // Successful. + MH_OK = 0, + + // MinHook is already initialized. + MH_ERROR_ALREADY_INITIALIZED, + + // MinHook is not initialized yet, or already uninitialized. + MH_ERROR_NOT_INITIALIZED, + + // The hook for the specified target function is already created. + MH_ERROR_ALREADY_CREATED, + + // The hook for the specified target function is not created yet. + MH_ERROR_NOT_CREATED, + + // The hook for the specified target function is already enabled. + MH_ERROR_ENABLED, + + // The hook for the specified target function is not enabled yet, or already + // disabled. + MH_ERROR_DISABLED, + + // The specified pointer is invalid. It points the address of non-allocated + // and/or non-executable region. + MH_ERROR_NOT_EXECUTABLE, + + // The specified target function cannot be hooked. + MH_ERROR_UNSUPPORTED_FUNCTION, + + // Failed to allocate memory. + MH_ERROR_MEMORY_ALLOC, + + // Failed to change the memory protection. + MH_ERROR_MEMORY_PROTECT, + + // The specified module is not loaded. + MH_ERROR_MODULE_NOT_FOUND, + + // The specified function is not found. + MH_ERROR_FUNCTION_NOT_FOUND +} +MH_STATUS; + +// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, +// MH_QueueEnableHook or MH_QueueDisableHook. +#define MH_ALL_HOOKS NULL + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the MinHook library. You must call this function EXACTLY ONCE + // at the beginning of your program. + MH_STATUS WINAPI MH_Initialize(VOID); + + // Uninitialize the MinHook library. You must call this function EXACTLY + // ONCE at the end of your program. + MH_STATUS WINAPI MH_Uninitialize(VOID); + + // Creates a Hook for the specified target function, in disabled state. + // Parameters: + // pTarget [in] A pointer to the target function, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a Hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszTarget [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a Hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszTarget [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + // ppTarget [out] A pointer to the target function, which will be used + // with other functions. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); + + // Removes an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); + + // Enables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // enabled in one go. + MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); + + // Disables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // disabled in one go. + MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); + + // Queues to enable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be enabled. + MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); + + // Queues to disable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be disabled. + MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); + + // Applies all queued changes in one go. + MH_STATUS WINAPI MH_ApplyQueued(VOID); + + // Translates the MH_STATUS to its name as a string. + const char * WINAPI MH_StatusToString(MH_STATUS status); + +#ifdef __cplusplus +} +#endif + diff --git a/csgo2/MinHook/src/HDE/hde32.c b/csgo2/MinHook/src/HDE/hde32.c new file mode 100644 index 0000000..08fa25b --- /dev/null +++ b/csgo2/MinHook/src/HDE/hde32.c @@ -0,0 +1,326 @@ +/* + * Hacker Disassembler Engine 32 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#if defined(_M_IX86) || defined(__i386__) + +#include "hde32.h" +#include "table32.h" + +unsigned int hde32_disasm(const void *code, hde32s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; + + // Avoid using memset to reduce the footprint. +#ifndef _MSC_VER + memset((LPBYTE)hs, 0, sizeof(hde32s)); +#else + __stosb((LPBYTE)hs, 0, sizeof(hde32s)); +#endif + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde32_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde32_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde32_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde32_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde32_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (pref & PRE_66) { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } else { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } + } + + if (cflags & C_IMM16) { + if (hs->flags & F_IMM32) { + hs->flags |= F_IMM16; + hs->disp.disp16 = *(uint16_t *)p; + } else if (hs->flags & F_IMM16) { + hs->flags |= F_2IMM16; + hs->disp.disp16 = *(uint16_t *)p; + } else { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + } + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} + +#endif // defined(_M_IX86) || defined(__i386__) diff --git a/csgo2/MinHook/src/HDE/hde32.h b/csgo2/MinHook/src/HDE/hde32.h new file mode 100644 index 0000000..1112450 --- /dev/null +++ b/csgo2/MinHook/src/HDE/hde32.h @@ -0,0 +1,105 @@ +/* + * Hacker Disassembler Engine 32 + * Copyright (c) 2006-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde32.h: C/C++ header file + * + */ + +#ifndef _HDE32_H_ +#define _HDE32_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include "pstdint.h" + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_DISP8 0x00000020 +#define F_DISP16 0x00000040 +#define F_DISP32 0x00000080 +#define F_RELATIVE 0x00000100 +#define F_2IMM16 0x00000800 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_ANY 0x3f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde32s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde32_disasm(const void *code, hde32s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE32_H_ */ diff --git a/csgo2/MinHook/src/HDE/hde64.c b/csgo2/MinHook/src/HDE/hde64.c new file mode 100644 index 0000000..c23e2fc --- /dev/null +++ b/csgo2/MinHook/src/HDE/hde64.c @@ -0,0 +1,337 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#if defined(_M_X64) || defined(__x86_64__) + +#include "hde64.h" +#include "table64.h" + +unsigned int hde64_disasm(const void *code, hde64s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; + uint8_t op64 = 0; + + // Avoid using memset to reduce the footprint. +#ifndef _MSC_VER + memset((LPBYTE)hs, 0, sizeof(hde64s)); +#else + __stosb((LPBYTE)hs, 0, sizeof(hde64s)); +#endif + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((c & 0xf0) == 0x40) { + hs->flags |= F_PREFIX_REX; + if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) + op64++; + hs->rex_r = (c & 7) >> 2; + hs->rex_x = (c & 3) >> 1; + hs->rex_b = c & 1; + if (((c = *p++) & 0xf0) == 0x40) { + opcode = c; + goto error_opcode; + } + } + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + op64++; + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + error_opcode: + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde64_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde64_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde64_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde64_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde64_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (op64) { + hs->flags |= F_IMM64; + hs->imm.imm64 = *(uint64_t *)p; + p += 8; + } else if (!(pref & PRE_66)) { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else + goto imm16_ok; + } + + + if (cflags & C_IMM16) { + imm16_ok: + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} + +#endif // defined(_M_X64) || defined(__x86_64__) diff --git a/csgo2/MinHook/src/HDE/hde64.h b/csgo2/MinHook/src/HDE/hde64.h new file mode 100644 index 0000000..ecbf4df --- /dev/null +++ b/csgo2/MinHook/src/HDE/hde64.h @@ -0,0 +1,112 @@ +/* + * Hacker Disassembler Engine 64 + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde64.h: C/C++ header file + * + */ + +#ifndef _HDE64_H_ +#define _HDE64_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include "pstdint.h" + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_IMM64 0x00000020 +#define F_DISP8 0x00000040 +#define F_DISP16 0x00000080 +#define F_DISP32 0x00000100 +#define F_RELATIVE 0x00000200 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_REX 0x40000000 +#define F_PREFIX_ANY 0x7f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t rex; + uint8_t rex_w; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + uint64_t imm64; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde64s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde64_disasm(const void *code, hde64s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE64_H_ */ diff --git a/csgo2/MinHook/src/HDE/pstdint.h b/csgo2/MinHook/src/HDE/pstdint.h new file mode 100644 index 0000000..84d82a0 --- /dev/null +++ b/csgo2/MinHook/src/HDE/pstdint.h @@ -0,0 +1,39 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +// Integer types for HDE. +typedef INT8 int8_t; +typedef INT16 int16_t; +typedef INT32 int32_t; +typedef INT64 int64_t; +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; diff --git a/csgo2/MinHook/src/HDE/table32.h b/csgo2/MinHook/src/HDE/table32.h new file mode 100644 index 0000000..7b3e12e --- /dev/null +++ b/csgo2/MinHook/src/HDE/table32.h @@ -0,0 +1,73 @@ +/* + * Hacker Disassembler Engine 32 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xf1 +#define DELTA_FPU_MODRM 0xf8 +#define DELTA_PREFIXES 0x130 +#define DELTA_OP_LOCK_OK 0x1a1 +#define DELTA_OP2_LOCK_OK 0x1b9 +#define DELTA_OP_ONLY_MEM 0x1cb +#define DELTA_OP2_ONLY_MEM 0x1da + +unsigned char hde32_table[] = { + 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, + 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, + 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, + 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, + 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, + 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, + 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, + 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, + 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, + 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, + 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, + 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, + 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, + 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, + 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, + 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, + 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, + 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, + 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, + 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, + 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, + 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, + 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, + 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, + 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, + 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, + 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, + 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, + 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, + 0xe7,0x08,0x00,0xf0,0x02,0x00 +}; diff --git a/csgo2/MinHook/src/HDE/table64.h b/csgo2/MinHook/src/HDE/table64.h new file mode 100644 index 0000000..01d4541 --- /dev/null +++ b/csgo2/MinHook/src/HDE/table64.h @@ -0,0 +1,74 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xfd +#define DELTA_FPU_MODRM 0x104 +#define DELTA_PREFIXES 0x13c +#define DELTA_OP_LOCK_OK 0x1ae +#define DELTA_OP2_LOCK_OK 0x1c6 +#define DELTA_OP_ONLY_MEM 0x1d8 +#define DELTA_OP2_ONLY_MEM 0x1e7 + +unsigned char hde64_table[] = { + 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, + 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, + 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, + 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, + 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, + 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, + 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, + 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, + 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, + 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, + 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, + 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, + 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, + 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, + 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, + 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, + 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, + 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, + 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, + 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, + 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, + 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, + 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, + 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, + 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, + 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, + 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, + 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, + 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, + 0x00,0xf0,0x02,0x00 +}; diff --git a/csgo2/MinHook/src/buffer.c b/csgo2/MinHook/src/buffer.c new file mode 100644 index 0000000..8f9fbce --- /dev/null +++ b/csgo2/MinHook/src/buffer.c @@ -0,0 +1,312 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "buffer.h" + +// Size of each memory block. (= page size of VirtualAlloc) +#define MEMORY_BLOCK_SIZE 0x1000 + +// Max range for seeking a memory block. (= 1024MB) +#define MAX_MEMORY_RANGE 0x40000000 + +// Memory protection flags to check the executable address. +#define PAGE_EXECUTE_FLAGS \ + (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) + +// Memory slot. +typedef struct _MEMORY_SLOT +{ + union + { + struct _MEMORY_SLOT *pNext; + UINT8 buffer[MEMORY_SLOT_SIZE]; + }; +} MEMORY_SLOT, *PMEMORY_SLOT; + +// Memory block info. Placed at the head of each block. +typedef struct _MEMORY_BLOCK +{ + struct _MEMORY_BLOCK *pNext; + PMEMORY_SLOT pFree; // First element of the free slot list. + UINT usedCount; +} MEMORY_BLOCK, *PMEMORY_BLOCK; + +//------------------------------------------------------------------------- +// Global Variables: +//------------------------------------------------------------------------- + +// First element of the memory block list. +PMEMORY_BLOCK g_pMemoryBlocks; + +//------------------------------------------------------------------------- +VOID InitializeBuffer(VOID) +{ + // Nothing to do for now. +} + +//------------------------------------------------------------------------- +VOID UninitializeBuffer(VOID) +{ + PMEMORY_BLOCK pBlock = g_pMemoryBlocks; + g_pMemoryBlocks = NULL; + + while (pBlock) + { + PMEMORY_BLOCK pNext = pBlock->pNext; + VirtualFree(pBlock, 0, MEM_RELEASE); + pBlock = pNext; + } +} + +//------------------------------------------------------------------------- +#if defined(_M_X64) || defined(__x86_64__) +static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) +{ + ULONG_PTR tryAddr = (ULONG_PTR)pAddress; + + // Round down to the allocation granularity. + tryAddr -= tryAddr % dwAllocationGranularity; + + // Start from the previous allocation granularity multiply. + tryAddr -= dwAllocationGranularity; + + while (tryAddr >= (ULONG_PTR)pMinAddr) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) + break; + + if (mbi.State == MEM_FREE) + return (LPVOID)tryAddr; + + if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) + break; + + tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; + } + + return NULL; +} +#endif + +//------------------------------------------------------------------------- +#if defined(_M_X64) || defined(__x86_64__) +static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) +{ + ULONG_PTR tryAddr = (ULONG_PTR)pAddress; + + // Round down to the allocation granularity. + tryAddr -= tryAddr % dwAllocationGranularity; + + // Start from the next allocation granularity multiply. + tryAddr += dwAllocationGranularity; + + while (tryAddr <= (ULONG_PTR)pMaxAddr) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) + break; + + if (mbi.State == MEM_FREE) + return (LPVOID)tryAddr; + + tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; + + // Round up to the next allocation granularity. + tryAddr += dwAllocationGranularity - 1; + tryAddr -= tryAddr % dwAllocationGranularity; + } + + return NULL; +} +#endif + +//------------------------------------------------------------------------- +static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) +{ + PMEMORY_BLOCK pBlock; +#if defined(_M_X64) || defined(__x86_64__) + ULONG_PTR minAddr; + ULONG_PTR maxAddr; + + SYSTEM_INFO si; + GetSystemInfo(&si); + minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; + maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; + + // pOrigin ± 512MB + if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) + minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; + + if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) + maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; + + // Make room for MEMORY_BLOCK_SIZE bytes. + maxAddr -= MEMORY_BLOCK_SIZE - 1; +#endif + + // Look the registered blocks for a reachable one. + for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) + { +#if defined(_M_X64) || defined(__x86_64__) + // Ignore the blocks too far. + if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) + continue; +#endif + // The block has at least one unused slot. + if (pBlock->pFree != NULL) + return pBlock; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Alloc a new block above if not found. + { + LPVOID pAlloc = pOrigin; + while ((ULONG_PTR)pAlloc >= minAddr) + { + pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); + if (pAlloc == NULL) + break; + + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (pBlock != NULL) + break; + } + } + + // Alloc a new block below if not found. + if (pBlock == NULL) + { + LPVOID pAlloc = pOrigin; + while ((ULONG_PTR)pAlloc <= maxAddr) + { + pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); + if (pAlloc == NULL) + break; + + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (pBlock != NULL) + break; + } + } +#else + // In x86 mode, a memory block can be placed anywhere. + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +#endif + + if (pBlock != NULL) + { + // Build a linked list of all the slots. + PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; + pBlock->pFree = NULL; + pBlock->usedCount = 0; + do + { + pSlot->pNext = pBlock->pFree; + pBlock->pFree = pSlot; + pSlot++; + } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); + + pBlock->pNext = g_pMemoryBlocks; + g_pMemoryBlocks = pBlock; + } + + return pBlock; +} + +//------------------------------------------------------------------------- +LPVOID AllocateBuffer(LPVOID pOrigin) +{ + PMEMORY_SLOT pSlot; + PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); + if (pBlock == NULL) + return NULL; + + // Remove an unused slot from the list. + pSlot = pBlock->pFree; + pBlock->pFree = pSlot->pNext; + pBlock->usedCount++; +#ifdef _DEBUG + // Fill the slot with INT3 for debugging. + memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); +#endif + return pSlot; +} + +//------------------------------------------------------------------------- +VOID FreeBuffer(LPVOID pBuffer) +{ + PMEMORY_BLOCK pBlock = g_pMemoryBlocks; + PMEMORY_BLOCK pPrev = NULL; + ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; + + while (pBlock != NULL) + { + if ((ULONG_PTR)pBlock == pTargetBlock) + { + PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; +#ifdef _DEBUG + // Clear the released slot for debugging. + memset(pSlot, 0x00, sizeof(*pSlot)); +#endif + // Restore the released slot to the list. + pSlot->pNext = pBlock->pFree; + pBlock->pFree = pSlot; + pBlock->usedCount--; + + // Free if unused. + if (pBlock->usedCount == 0) + { + if (pPrev) + pPrev->pNext = pBlock->pNext; + else + g_pMemoryBlocks = pBlock->pNext; + + VirtualFree(pBlock, 0, MEM_RELEASE); + } + + break; + } + + pPrev = pBlock; + pBlock = pBlock->pNext; + } +} + +//------------------------------------------------------------------------- +BOOL IsExecutableAddress(LPVOID pAddress) +{ + MEMORY_BASIC_INFORMATION mi; + VirtualQuery(pAddress, &mi, sizeof(mi)); + + return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); +} diff --git a/csgo2/MinHook/src/buffer.h b/csgo2/MinHook/src/buffer.h new file mode 100644 index 0000000..204d551 --- /dev/null +++ b/csgo2/MinHook/src/buffer.h @@ -0,0 +1,42 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +// Size of each memory slot. +#if defined(_M_X64) || defined(__x86_64__) + #define MEMORY_SLOT_SIZE 64 +#else + #define MEMORY_SLOT_SIZE 32 +#endif + +VOID InitializeBuffer(VOID); +VOID UninitializeBuffer(VOID); +LPVOID AllocateBuffer(LPVOID pOrigin); +VOID FreeBuffer(LPVOID pBuffer); +BOOL IsExecutableAddress(LPVOID pAddress); diff --git a/csgo2/MinHook/src/hook.c b/csgo2/MinHook/src/hook.c new file mode 100644 index 0000000..b9bc9bd --- /dev/null +++ b/csgo2/MinHook/src/hook.c @@ -0,0 +1,888 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "../include/MinHook.h" +#include "buffer.h" +#include "trampoline.h" +#ifndef ARRAYSIZE + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +// Initial capacity of the HOOK_ENTRY buffer. +#define INITIAL_HOOK_CAPACITY 32 + +// Initial capacity of the thread IDs buffer. +#define INITIAL_THREAD_CAPACITY 128 + +// Special hook position values. +#define INVALID_HOOK_POS UINT_MAX +#define ALL_HOOKS_POS UINT_MAX + +// Freeze() action argument defines. +#define ACTION_DISABLE 0 +#define ACTION_ENABLE 1 +#define ACTION_APPLY_QUEUED 2 + +// Thread access rights for suspending/resuming threads. +#define THREAD_ACCESS \ + (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) + +// Hook information. +typedef struct _HOOK_ENTRY +{ + LPVOID pTarget; // Address of the target function. + LPVOID pDetour; // Address of the detour or relay function. + LPVOID pTrampoline; // Address of the trampoline function. + UINT8 backup[8]; // Original prologue of the target function. + + UINT8 patchAbove : 1; // Uses the hot patch area. + UINT8 isEnabled : 1; // Enabled. + UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. + + UINT nIP : 4; // Count of the instruction boundaries. + UINT8 oldIPs[8]; // Instruction boundaries of the target function. + UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. +} HOOK_ENTRY, *PHOOK_ENTRY; + +// Suspended threads for Freeze()/Unfreeze(). +typedef struct _FROZEN_THREADS +{ + LPDWORD pItems; // Data heap + UINT capacity; // Size of allocated data heap, items + UINT size; // Actual number of data items +} FROZEN_THREADS, *PFROZEN_THREADS; + +//------------------------------------------------------------------------- +// Global Variables: +//------------------------------------------------------------------------- + +// Spin lock flag for EnterSpinLock()/LeaveSpinLock(). +volatile LONG g_isLocked = FALSE; + +// Private heap handle. If not NULL, this library is initialized. +HANDLE g_hHeap = NULL; + +// Hook entries. +struct +{ + PHOOK_ENTRY pItems; // Data heap + UINT capacity; // Size of allocated data heap, items + UINT size; // Actual number of data items +} g_hooks; + +//------------------------------------------------------------------------- +// Returns INVALID_HOOK_POS if not found. +static UINT FindHookEntry(LPVOID pTarget) +{ + UINT i; + for (i = 0; i < g_hooks.size; ++i) + { + if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) + return i; + } + + return INVALID_HOOK_POS; +} + +//------------------------------------------------------------------------- +static PHOOK_ENTRY AddHookEntry() +{ + if (g_hooks.pItems == NULL) + { + g_hooks.capacity = INITIAL_HOOK_CAPACITY; + g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( + g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); + if (g_hooks.pItems == NULL) + return NULL; + } + else if (g_hooks.size >= g_hooks.capacity) + { + PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( + g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); + if (p == NULL) + return NULL; + + g_hooks.capacity *= 2; + g_hooks.pItems = p; + } + + return &g_hooks.pItems[g_hooks.size++]; +} + +//------------------------------------------------------------------------- +static void DeleteHookEntry(UINT pos) +{ + if (pos < g_hooks.size - 1) + g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; + + g_hooks.size--; + + if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) + { + PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( + g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); + if (p == NULL) + return; + + g_hooks.capacity /= 2; + g_hooks.pItems = p; + } +} + +//------------------------------------------------------------------------- +static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) +{ + UINT i; + + if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) + return (DWORD_PTR)pHook->pTarget; + + for (i = 0; i < pHook->nIP; ++i) + { + if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) + return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Check relay function. + if (ip == (DWORD_PTR)pHook->pDetour) + return (DWORD_PTR)pHook->pTarget; +#endif + + return 0; +} + +//------------------------------------------------------------------------- +static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) +{ + UINT i; + for (i = 0; i < pHook->nIP; ++i) + { + if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) + return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; + } + + return 0; +} + +//------------------------------------------------------------------------- +static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) +{ + // If the thread suspended in the overwritten area, + // move IP to the proper address. + + CONTEXT c; +#if defined(_M_X64) || defined(__x86_64__) + DWORD64 *pIP = &c.Rip; +#else + DWORD *pIP = &c.Eip; +#endif + UINT count; + + c.ContextFlags = CONTEXT_CONTROL; + if (!GetThreadContext(hThread, &c)) + return; + + if (pos == ALL_HOOKS_POS) + { + pos = 0; + count = g_hooks.size; + } + else + { + count = pos + 1; + } + + for (; pos < count; ++pos) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + BOOL enable; + DWORD_PTR ip; + + switch (action) + { + case ACTION_DISABLE: + enable = FALSE; + break; + + case ACTION_ENABLE: + enable = TRUE; + break; + + default: // ACTION_APPLY_QUEUED + enable = pHook->queueEnable; + break; + } + if (pHook->isEnabled == enable) + continue; + + if (enable) + ip = FindNewIP(pHook, *pIP); + else + ip = FindOldIP(pHook, *pIP); + + if (ip != 0) + { + *pIP = ip; + SetThreadContext(hThread, &c); + } + } +} + +//------------------------------------------------------------------------- +static VOID EnumerateThreads(PFROZEN_THREADS pThreads) +{ + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hSnapshot != INVALID_HANDLE_VALUE) + { + THREADENTRY32 te; + te.dwSize = sizeof(THREADENTRY32); + if (Thread32First(hSnapshot, &te)) + { + do + { + if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) + && te.th32OwnerProcessID == GetCurrentProcessId() + && te.th32ThreadID != GetCurrentThreadId()) + { + if (pThreads->pItems == NULL) + { + pThreads->capacity = INITIAL_THREAD_CAPACITY; + pThreads->pItems + = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); + if (pThreads->pItems == NULL) + break; + } + else if (pThreads->size >= pThreads->capacity) + { + LPDWORD p = (LPDWORD)HeapReAlloc( + g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD)); + if (p == NULL) + break; + + pThreads->capacity *= 2; + pThreads->pItems = p; + } + pThreads->pItems[pThreads->size++] = te.th32ThreadID; + } + + te.dwSize = sizeof(THREADENTRY32); + } while (Thread32Next(hSnapshot, &te)); + } + CloseHandle(hSnapshot); + } +} + +//------------------------------------------------------------------------- +static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) +{ + pThreads->pItems = NULL; + pThreads->capacity = 0; + pThreads->size = 0; + EnumerateThreads(pThreads); + + if (pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); + if (hThread != NULL) + { + SuspendThread(hThread); + ProcessThreadIPs(hThread, pos, action); + CloseHandle(hThread); + } + } + } +} + +//------------------------------------------------------------------------- +static VOID Unfreeze(PFROZEN_THREADS pThreads) +{ + if (pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); + if (hThread != NULL) + { + ResumeThread(hThread); + CloseHandle(hThread); + } + } + + HeapFree(g_hHeap, 0, pThreads->pItems); + } +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableHookLL(UINT pos, BOOL enable) +{ + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + DWORD oldProtect; + SIZE_T patchSize = sizeof(JMP_REL); + LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; + + if (pHook->patchAbove) + { + pPatchTarget -= sizeof(JMP_REL); + patchSize += sizeof(JMP_REL_SHORT); + } + + if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) + return MH_ERROR_MEMORY_PROTECT; + + if (enable) + { + PJMP_REL pJmp = (PJMP_REL)pPatchTarget; + pJmp->opcode = 0xE9; + pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); + + if (pHook->patchAbove) + { + PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; + pShortJmp->opcode = 0xEB; + pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); + } + } + else + { + if (pHook->patchAbove) + memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); + else + memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); + } + + VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); + + // Just-in-case measure. + FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); + + pHook->isEnabled = enable; + pHook->queueEnable = enable; + + return MH_OK; +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableAllHooksLL(BOOL enable) +{ + MH_STATUS status = MH_OK; + UINT i, first = INVALID_HOOK_POS; + + for (i = 0; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != enable) + { + first = i; + break; + } + } + + if (first != INVALID_HOOK_POS) + { + FROZEN_THREADS threads; + Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); + + for (i = first; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != enable) + { + status = EnableHookLL(i, enable); + if (status != MH_OK) + break; + } + } + + Unfreeze(&threads); + } + + return status; +} + +//------------------------------------------------------------------------- +static VOID EnterSpinLock(VOID) +{ + SIZE_T spinCount = 0; + + // Wait until the flag is FALSE. + while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) + { + // No need to generate a memory barrier here, since InterlockedCompareExchange() + // generates a full memory barrier itself. + + // Prevent the loop from being too busy. + if (spinCount < 32) + Sleep(0); + else + Sleep(1); + + spinCount++; + } +} + +//------------------------------------------------------------------------- +static VOID LeaveSpinLock(VOID) +{ + // No need to generate a memory barrier here, since InterlockedExchange() + // generates a full memory barrier itself. + + InterlockedExchange(&g_isLocked, FALSE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_Initialize(VOID) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap == NULL) + { + g_hHeap = HeapCreate(0, 0, 0); + if (g_hHeap != NULL) + { + // Initialize the internal function buffer. + InitializeBuffer(); + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_ALREADY_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_Uninitialize(VOID) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + status = EnableAllHooksLL(FALSE); + if (status == MH_OK) + { + // Free the internal function buffer. + + // HeapFree is actually not required, but some tools detect a false + // memory leak without HeapFree. + + UninitializeBuffer(); + + HeapFree(g_hHeap, 0, g_hooks.pItems); + HeapDestroy(g_hHeap); + + g_hHeap = NULL; + + g_hooks.pItems = NULL; + g_hooks.capacity = 0; + g_hooks.size = 0; + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + if (IsExecutableAddress(pTarget)/* && IsExecutableAddress(pDetour)*/) + { + UINT pos = FindHookEntry(pTarget); + if (pos == INVALID_HOOK_POS) + { + LPVOID pBuffer = AllocateBuffer(pTarget); + if (pBuffer != NULL) + { + TRAMPOLINE ct; + + ct.pTarget = pTarget; + ct.pDetour = pDetour; + ct.pTrampoline = pBuffer; + if (CreateTrampolineFunction(&ct)) + { + PHOOK_ENTRY pHook = AddHookEntry(); + if (pHook != NULL) + { + pHook->pTarget = ct.pTarget; +#if defined(_M_X64) || defined(__x86_64__) + pHook->pDetour = ct.pRelay; +#else + pHook->pDetour = ct.pDetour; +#endif + pHook->pTrampoline = ct.pTrampoline; + pHook->patchAbove = ct.patchAbove; + pHook->isEnabled = FALSE; + pHook->queueEnable = FALSE; + pHook->nIP = ct.nIP; + memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); + memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); + + // Back up the target function. + + if (ct.patchAbove) + { + memcpy( + pHook->backup, + (LPBYTE)pTarget - sizeof(JMP_REL), + sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); + } + else + { + memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); + } + + if (ppOriginal != NULL) + *ppOriginal = pHook->pTrampoline; + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_UNSUPPORTED_FUNCTION; + } + + if (status != MH_OK) + { + FreeBuffer(pBuffer); + } + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_ALREADY_CREATED; + } + } + else + { + status = MH_ERROR_NOT_EXECUTABLE; + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + UINT pos = FindHookEntry(pTarget); + if (pos != INVALID_HOOK_POS) + { + if (g_hooks.pItems[pos].isEnabled) + { + FROZEN_THREADS threads; + Freeze(&threads, pos, ACTION_DISABLE); + + status = EnableHookLL(pos, FALSE); + + Unfreeze(&threads); + } + + if (status == MH_OK) + { + FreeBuffer(g_hooks.pItems[pos].pTrampoline); + DeleteHookEntry(pos); + } + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + if (pTarget == MH_ALL_HOOKS) + { + status = EnableAllHooksLL(enable); + } + else + { + FROZEN_THREADS threads; + UINT pos = FindHookEntry(pTarget); + if (pos != INVALID_HOOK_POS) + { + if (g_hooks.pItems[pos].isEnabled != enable) + { + Freeze(&threads, pos, ACTION_ENABLE); + + status = EnableHookLL(pos, enable); + + Unfreeze(&threads); + } + else + { + status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; + } + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) +{ + return EnableHook(pTarget, TRUE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) +{ + return EnableHook(pTarget, FALSE); +} + +//------------------------------------------------------------------------- +static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + if (pTarget == MH_ALL_HOOKS) + { + UINT i; + for (i = 0; i < g_hooks.size; ++i) + g_hooks.pItems[i].queueEnable = queueEnable; + } + else + { + UINT pos = FindHookEntry(pTarget); + if (pos != INVALID_HOOK_POS) + { + g_hooks.pItems[pos].queueEnable = queueEnable; + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) +{ + return QueueHook(pTarget, TRUE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) +{ + return QueueHook(pTarget, FALSE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_ApplyQueued(VOID) +{ + MH_STATUS status = MH_OK; + UINT i, first = INVALID_HOOK_POS; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + for (i = 0; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) + { + first = i; + break; + } + } + + if (first != INVALID_HOOK_POS) + { + FROZEN_THREADS threads; + Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); + + for (i = first; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->isEnabled != pHook->queueEnable) + { + status = EnableHookLL(i, pHook->queueEnable); + if (status != MH_OK) + break; + } + } + + Unfreeze(&threads); + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, + LPVOID *ppOriginal, LPVOID *ppTarget) +{ + HMODULE hModule; + LPVOID pTarget; + + hModule = GetModuleHandleW(pszModule); + if (hModule == NULL) + return MH_ERROR_MODULE_NOT_FOUND; + + pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); + if (pTarget == NULL) + return MH_ERROR_FUNCTION_NOT_FOUND; + + if(ppTarget != NULL) + *ppTarget = pTarget; + + return MH_CreateHook(pTarget, pDetour, ppOriginal); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) +{ + return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); +} + +//------------------------------------------------------------------------- +const char * WINAPI MH_StatusToString(MH_STATUS status) +{ +#define MH_ST2STR(x) \ + case x: \ + return #x; + + switch (status) { + MH_ST2STR(MH_UNKNOWN) + MH_ST2STR(MH_OK) + MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) + MH_ST2STR(MH_ERROR_NOT_INITIALIZED) + MH_ST2STR(MH_ERROR_ALREADY_CREATED) + MH_ST2STR(MH_ERROR_NOT_CREATED) + MH_ST2STR(MH_ERROR_ENABLED) + MH_ST2STR(MH_ERROR_DISABLED) + MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) + MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) + MH_ST2STR(MH_ERROR_MEMORY_ALLOC) + MH_ST2STR(MH_ERROR_MEMORY_PROTECT) + MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) + MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) + } + +#undef MH_ST2STR + + return "(unknown)"; +} diff --git a/csgo2/MinHook/src/trampoline.c b/csgo2/MinHook/src/trampoline.c new file mode 100644 index 0000000..ac37f0f --- /dev/null +++ b/csgo2/MinHook/src/trampoline.c @@ -0,0 +1,316 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifndef ARRAYSIZE + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#if defined(_M_X64) || defined(__x86_64__) + #include "./hde/hde64.h" + typedef hde64s HDE; + #define HDE_DISASM(code, hs) hde64_disasm(code, hs) +#else + #include "./hde/hde32.h" + typedef hde32s HDE; + #define HDE_DISASM(code, hs) hde32_disasm(code, hs) +#endif + +#include "trampoline.h" +#include "buffer.h" + +// Maximum size of a trampoline function. +#if defined(_M_X64) || defined(__x86_64__) + #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) +#else + #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE +#endif + +//------------------------------------------------------------------------- +static BOOL IsCodePadding(LPBYTE pInst, UINT size) +{ + UINT i; + + if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) + return FALSE; + + for (i = 1; i < size; ++i) + { + if (pInst[i] != pInst[0]) + return FALSE; + } + return TRUE; +} + +//------------------------------------------------------------------------- +BOOL CreateTrampolineFunction(PTRAMPOLINE ct) +{ +#if defined(_M_X64) || defined(__x86_64__) + CALL_ABS call = { + 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] + 0xEB, 0x08, // EB 08: JMP +10 + 0x0000000000000000ULL // Absolute destination address + }; + JMP_ABS jmp = { + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; + JCC_ABS jcc = { + 0x70, 0x0E, // 7* 0E: J** +16 + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; +#else + CALL_REL call = { + 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + JMP_REL jmp = { + 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + JCC_REL jcc = { + 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx + 0x00000000 // Relative destination address + }; +#endif + + UINT8 oldPos = 0; + UINT8 newPos = 0; + ULONG_PTR jmpDest = 0; // Destination address of an internal jump. + BOOL finished = FALSE; // Is the function completed? +#if defined(_M_X64) || defined(__x86_64__) + UINT8 instBuf[16]; +#endif + + ct->patchAbove = FALSE; + ct->nIP = 0; + + do + { + HDE hs; + UINT copySize; + LPVOID pCopySrc; + ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; + ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; + + copySize = HDE_DISASM((LPVOID)pOldInst, &hs); + if (hs.flags & F_ERROR) + return FALSE; + + pCopySrc = (LPVOID)pOldInst; + if (oldPos >= sizeof(JMP_REL)) + { + // The trampoline function is long enough. + // Complete the function with the jump to the target function. +#if defined(_M_X64) || defined(__x86_64__) + jmp.address = pOldInst; +#else + jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); +#endif + pCopySrc = &jmp; + copySize = sizeof(jmp); + + finished = TRUE; + } +#if defined(_M_X64) || defined(__x86_64__) + else if ((hs.modrm & 0xC7) == 0x05) + { + // Instructions using RIP relative addressing. (ModR/M = 00???101B) + + // Modify the RIP relative address. + PUINT32 pRelAddr; + + // Avoid using memcpy to reduce the footprint. +#ifndef _MSC_VER + memcpy(instBuf, (LPBYTE)pOldInst, copySize); +#else + __movsb(instBuf, (LPBYTE)pOldInst, copySize); +#endif + pCopySrc = instBuf; + + // Relative address is stored at (instruction length - immediate value length - 4). + pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); + *pRelAddr + = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); + + // Complete the function if JMP (FF /4). + if (hs.opcode == 0xFF && hs.modrm_reg == 4) + finished = TRUE; + } +#endif + else if (hs.opcode == 0xE8) + { + // Direct relative CALL + ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; +#if defined(_M_X64) || defined(__x86_64__) + call.address = dest; +#else + call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); +#endif + pCopySrc = &call; + copySize = sizeof(call); + } + else if ((hs.opcode & 0xFD) == 0xE9) + { + // Direct relative JMP (EB or E9) + ULONG_PTR dest = pOldInst + hs.len; + + if (hs.opcode == 0xEB) // isShort jmp + dest += (INT8)hs.imm.imm8; + else + dest += (INT32)hs.imm.imm32; + + // Simply copy an internal jump. + if ((ULONG_PTR)ct->pTarget <= dest + && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) + { + if (jmpDest < dest) + jmpDest = dest; + } + else + { +#if defined(_M_X64) || defined(__x86_64__) + jmp.address = dest; +#else + jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); +#endif + pCopySrc = &jmp; + copySize = sizeof(jmp); + + // Exit the function If it is not in the branch + finished = (pOldInst >= jmpDest); + } + } + else if ((hs.opcode & 0xF0) == 0x70 + || (hs.opcode & 0xFC) == 0xE0 + || (hs.opcode2 & 0xF0) == 0x80) + { + // Direct relative Jcc + ULONG_PTR dest = pOldInst + hs.len; + + if ((hs.opcode & 0xF0) == 0x70 // Jcc + || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ + dest += (INT8)hs.imm.imm8; + else + dest += (INT32)hs.imm.imm32; + + // Simply copy an internal jump. + if ((ULONG_PTR)ct->pTarget <= dest + && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) + { + if (jmpDest < dest) + jmpDest = dest; + } + else if ((hs.opcode & 0xFC) == 0xE0) + { + // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. + return FALSE; + } + else + { + UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); +#if defined(_M_X64) || defined(__x86_64__) + // Invert the condition in x64 mode to simplify the conditional jump logic. + jcc.opcode = 0x71 ^ cond; + jcc.address = dest; +#else + jcc.opcode1 = 0x80 | cond; + jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); +#endif + pCopySrc = &jcc; + copySize = sizeof(jcc); + } + } + else if ((hs.opcode & 0xFE) == 0xC2) + { + // RET (C2 or C3) + + // Complete the function if not in a branch. + finished = (pOldInst >= jmpDest); + } + + // Can't alter the instruction length in a branch. + if (pOldInst < jmpDest && copySize != hs.len) + return FALSE; + + // Trampoline function is too large. + if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) + return FALSE; + + // Trampoline function has too many instructions. + if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) + return FALSE; + + ct->oldIPs[ct->nIP] = oldPos; + ct->newIPs[ct->nIP] = newPos; + ct->nIP++; + + // Avoid using memcpy to reduce the footprint. +#ifndef _MSC_VER + memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); +#else + __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); +#endif + newPos += copySize; + oldPos += hs.len; + } + while (!finished); + + // Is there enough place for a long jump? + if (oldPos < sizeof(JMP_REL) + && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) + { + // Is there enough place for a short jump? + if (oldPos < sizeof(JMP_REL_SHORT) + && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) + { + return FALSE; + } + + // Can we place the long jump above the function? + if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) + return FALSE; + + if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) + return FALSE; + + ct->patchAbove = TRUE; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Create a relay function. + jmp.address = (ULONG_PTR)ct->pDetour; + + ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; + memcpy(ct->pRelay, &jmp, sizeof(jmp)); +#endif + + return TRUE; +} diff --git a/csgo2/MinHook/src/trampoline.h b/csgo2/MinHook/src/trampoline.h new file mode 100644 index 0000000..bdffdac --- /dev/null +++ b/csgo2/MinHook/src/trampoline.h @@ -0,0 +1,105 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#pragma pack(push, 1) + +// Structs for writing x86/x64 instructions. + +// 8-bit relative jump. +typedef struct _JMP_REL_SHORT +{ + UINT8 opcode; // EB xx: JMP +2+xx + UINT8 operand; +} JMP_REL_SHORT, *PJMP_REL_SHORT; + +// 32-bit direct relative jump/call. +typedef struct _JMP_REL +{ + UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx + UINT32 operand; // Relative destination address +} JMP_REL, *PJMP_REL, CALL_REL; + +// 64-bit indirect absolute jump. +typedef struct _JMP_ABS +{ + UINT8 opcode0; // FF25 00000000: JMP [+6] + UINT8 opcode1; + UINT32 dummy; + UINT64 address; // Absolute destination address +} JMP_ABS, *PJMP_ABS; + +// 64-bit indirect absolute call. +typedef struct _CALL_ABS +{ + UINT8 opcode0; // FF15 00000002: CALL [+6] + UINT8 opcode1; + UINT32 dummy0; + UINT8 dummy1; // EB 08: JMP +10 + UINT8 dummy2; + UINT64 address; // Absolute destination address +} CALL_ABS; + +// 32-bit direct relative conditional jumps. +typedef struct _JCC_REL +{ + UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx + UINT8 opcode1; + UINT32 operand; // Relative destination address +} JCC_REL; + +// 64bit indirect absolute conditional jumps that x64 lacks. +typedef struct _JCC_ABS +{ + UINT8 opcode; // 7* 0E: J** +16 + UINT8 dummy0; + UINT8 dummy1; // FF25 00000000: JMP [+6] + UINT8 dummy2; + UINT32 dummy3; + UINT64 address; // Absolute destination address +} JCC_ABS; + +#pragma pack(pop) + +typedef struct _TRAMPOLINE +{ + LPVOID pTarget; // [In] Address of the target function. + LPVOID pDetour; // [In] Address of the detour function. + LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. + +#if defined(_M_X64) || defined(__x86_64__) + LPVOID pRelay; // [Out] Address of the relay function. +#endif + BOOL patchAbove; // [Out] Should use the hot patch area? + UINT nIP; // [Out] Number of the instruction boundaries. + UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. + UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. +} TRAMPOLINE, *PTRAMPOLINE; + +BOOL CreateTrampolineFunction(PTRAMPOLINE ct); diff --git a/csgo2/VTHook.h b/csgo2/VTHook.h new file mode 100644 index 0000000..1d730d6 --- /dev/null +++ b/csgo2/VTHook.h @@ -0,0 +1,100 @@ +#pragma once +#include "pch.h" +class VTHook +{ +public: + VTHook() + { + memset( this, 0, sizeof( VTHook) ); + } + + VTHook( PDWORD64* ppdwClassBase ) + { + bInitialize( ppdwClassBase ); + } + + ~VTHook() + { + UnHook(); + } + void ClearClassBase() + { + m_ClassBase = NULL; + } + bool bInitialize( PDWORD64* ppdwClassBase ) + { + m_ClassBase = ppdwClassBase; + m_OldVT = *ppdwClassBase; + m_VTSize = GetVTCount( *ppdwClassBase ); + m_NewVT = new DWORD64[ m_VTSize ]; + memcpy( m_NewVT, m_OldVT, sizeof( DWORD64) * m_VTSize ); + *ppdwClassBase = m_NewVT; + return true; + } + + bool bInitialize( PDWORD64** pppdwClassBase ) // fix for pp + { + return bInitialize( *pppdwClassBase ); + } + + void UnHook() + { + if( m_ClassBase ) + { + *m_ClassBase = m_OldVT; + } + } + + void ReHook() + { + if( m_ClassBase ) + { + *m_ClassBase = m_NewVT; + } + } + + int iGetFuncCount() + { + return ( int )m_VTSize; + } + + DWORD64 GetFuncAddress( int Index ) + { + if( Index >= 0 && Index <= ( int )m_VTSize && m_OldVT != NULL ) + { + return m_OldVT[ Index ]; + } + return NULL; + } + + PDWORD64 GetOldVT() + { + return m_OldVT; + } + + DWORD64 HookFunction( DWORD64 dwNewFunc, unsigned int iIndex ) + { + if( m_NewVT && m_OldVT && iIndex <= m_VTSize && iIndex >= 0 ) + { + m_NewVT[ iIndex ] = dwNewFunc; + return m_OldVT[ iIndex ]; + } + + return NULL; + } + +private: + DWORD64 GetVTCount( PDWORD64 pdwVMT ) + { + DWORD64 dwIndex = 0; + + while (IsBadCodePtr((FARPROC)pdwVMT[dwIndex]) == false) { + dwIndex++; + } + return dwIndex; + } + + PDWORD64* m_ClassBase; + PDWORD64 m_NewVT, m_OldVT; + DWORD64 m_VTSize; +}; diff --git a/csgo2/cpp.hint b/csgo2/cpp.hint new file mode 100644 index 0000000..b6d326a --- /dev/null +++ b/csgo2/cpp.hint @@ -0,0 +1,4 @@ +// 提示文件帮助 Visual Studio IDE 解释 Visual C++ 标识符, +// 如函数和宏的名称。 +// 有关详细信息,请参见 https://go.microsoft.com/fwlink/?linkid=865984 +#define SCHEMA_FIELD(type, varName) SCHEMA_FIELD_OFFSET(type, varName, 0) diff --git a/csgo2/csgo2.vcxproj b/csgo2/csgo2.vcxproj new file mode 100644 index 0000000..b4e82e3 --- /dev/null +++ b/csgo2/csgo2.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {0af170b6-cc8d-4a56-9879-5064f3d3ebdb} + csgo2 + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + stdcpplatest + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + stdcpplatest + + + Windows + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + \ No newline at end of file diff --git a/csgo2/csgo2.vcxproj.filters b/csgo2/csgo2.vcxproj.filters new file mode 100644 index 0000000..8589b31 --- /dev/null +++ b/csgo2/csgo2.vcxproj.filters @@ -0,0 +1,282 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {89393917-f155-4ae6-9e03-2529967f88c3} + + + {88318acc-d490-446b-8333-f20a22d748a6} + + + {aed2a097-5c17-4c61-a5de-65cde80a84a4} + + + {c3ddaa59-6f23-48e1-b43c-03e626960a5e} + + + {d8b32656-ba7f-49d3-be6d-c97f9bc02ba0} + + + {87180362-2725-4f7b-a702-17cb8cff94d3} + + + {8ce5a064-6e56-4bfb-9c12-b6da38016dbc} + + + {b8db59a4-0a74-4cd8-9f3d-5e30e04a52f3} + + + {a4fd0778-933c-4ac7-a724-70b62977c3f9} + + + {341ff6a7-81b6-4c44-9d66-ac9c4fbe8684} + + + {76acdb22-3f64-4cf6-8447-986ab46533ae} + + + {c28f9f29-7571-4821-9cbd-11f27692566a} + + + {e26bdf5e-ad8d-4ed2-965c-1fdb958a6098} + + + {c5938a38-9035-4f7a-952c-156a8549bb54} + + + {ec02337e-1abc-42a9-b29c-355278bf4bf2} + + + {6c9da4be-92c5-4504-8c46-ab0cc612bfe5} + + + {f1101bd0-b17e-4c9e-87f1-e34d97979e77} + + + {63beb427-0b96-4062-83e0-752efb2ed5f0} + + + {68556c7c-97c0-4e1e-82f0-e4b45b9ad40d} + + + {befb97b4-a3ba-48a8-84a8-c36a74d2d48c} + + + {a403d20d-862c-4c26-965b-9cc23e67745f} + + + {c359acb2-cc33-4be0-b5dd-3dfef50ba594} + + + + + 头文件 + + + 头文件 + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件 + + + 头文件 + + + 头文件\math + + + 头文件\math + + + 头文件 + + + 头文件\memory + + + 头文件\memory + + + 头文件\memory + + + 头文件\memory + + + 头文件\memory + + + 头文件\sdk + + + 头文件\sdk\gameevent + + + 头文件\sdk\handle + + + 头文件\sdk\player + + + 头文件\sdk\player + + + 头文件\events + + + 头文件\sdk\interfaces + + + 头文件\native_sdk\interfaces + + + 头文件\native_sdk\interfaces + + + 头文件\native_sdk\interfaces + + + 头文件\native_sdk\entity + + + 头文件\memory + + + 头文件\native_sdk\entity + + + 头文件\native_sdk\handle + + + 头文件\native_sdk\entity + + + 头文件\native_sdk\interfaces + + + 头文件\sdk\convar + + + 头文件\sdk\tier1 + + + 头文件\sdk\tier1 + + + 头文件\sdk\tier1 + + + 头文件\sdk\public + + + 头文件\sdk\public + + + 头文件\sdk\tier1 + + + + + 源文件 + + + 源文件 + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 头文件\minhook + + + 源文件 + + + 源文件 + + + 源文件\memory + + + 源文件\memory + + + 源文件\memory + + + 源文件\events + + + 源文件\native_sdk\interfaces + + + 源文件\memory + + + 源文件\native_sdk\interfaces + + + 源文件\native_sdk\interfaces + + + 源文件\native_sdk\entity + + + 源文件\native_sdk\handle + + + 头文件\sdk\convar + + + 头文件\sdk\tier1 + + + + + + \ No newline at end of file diff --git a/csgo2/dllmain.cpp b/csgo2/dllmain.cpp new file mode 100644 index 0000000..6751781 --- /dev/null +++ b/csgo2/dllmain.cpp @@ -0,0 +1,62 @@ +// dllmain.cpp : 定义 DLL 应用程序的入口点。 +#include "pch.h" + +auto unload() -> void { + hooks::unload(); + LOG("unload \n"); +} +auto WatchExitThread(void *ctx) -> void { + while (true) { + if (GetAsyncKeyState(VK_END) & 1) { + break; + } + Sleep(100); + } + global::Exit = true; + unload(); +} +auto init(void* ctx) -> bool { + AllocConsole(); + SetConsoleTitleA("huoji debug console"); + freopen_s(reinterpret_cast stdout, "CONOUT$", "w", stdout); + CreateThread(NULL, 0, + reinterpret_cast(WatchExitThread), + NULL, 0, NULL); + + while (Offset::Module_tier0 == 0) + { + if (global::Exit) { + return false; + } + Offset::Module_tier0 = reinterpret_cast(GetModuleHandleA("tier0")); + Sleep(200); + } + if (Offset::Init() == false) { + LOG("Offset::Init() == false !\n"); + return false; + } + LOG("hacked by huoji 2023.9.14 \n"); + bool isSuccess = false; + isSuccess = hooks::init(); + if (isSuccess) { + LOG("plugin install success !\n"); + } + return isSuccess; +} + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, + LPVOID lpReserved) { + bool result = true; + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + CreateThread(NULL, 0, + reinterpret_cast(init), + NULL, 0, NULL); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return result; +} diff --git a/csgo2/events.cpp b/csgo2/events.cpp new file mode 100644 index 0000000..1feab7b --- /dev/null +++ b/csgo2/events.cpp @@ -0,0 +1,28 @@ +#include "events.h" +#include "native_sdk/entity/cbaseplayercontroller.h" +#include "player.h" +namespace events { + auto OnPlayerDeathEvent(IGameEvent* event) -> void { + UnkGameEventStruct_t userIdNameParams{ "userid" }; + UnkGameEventStruct_t attackerNameParams{ "attacker" }; + + const auto victim = reinterpret_cast(event->GetPlayerPawn(&userIdNameParams)); + const auto attacker = reinterpret_cast(event->GetPlayerPawn(&attackerNameParams)); + auto victimName = &victim->m_iszPlayerName(); + //victimBasePlayer->ForceRespawn(); + printf("victim %s\n", victimName); + printf("attacker %s\n", attacker->m_iszPlayerName()); + + } + auto OnPlayerChat(IGameEvent* event) -> void + { + UnkGameEventStruct_t userIdNameParams{ "userid" }; + const auto chater = reinterpret_cast(event->GetPlayer(&userIdNameParams)); + const auto text = event->GetString("text"); + const auto chaterName = chater->m_iszPlayerName(); + + LOG("player: %s say: %s \n", chaterName, text); + + + } +} \ No newline at end of file diff --git a/csgo2/events.h b/csgo2/events.h new file mode 100644 index 0000000..50c2e13 --- /dev/null +++ b/csgo2/events.h @@ -0,0 +1,8 @@ +#pragma once +#include "pch.h" +#include "sdk/gameevent/IGameEvent.h" + +namespace events { + auto OnPlayerDeathEvent(IGameEvent* event) -> void; + auto OnPlayerChat(IGameEvent* event) -> void; +} diff --git a/csgo2/framework.h b/csgo2/framework.h new file mode 100644 index 0000000..80cbbc9 --- /dev/null +++ b/csgo2/framework.h @@ -0,0 +1,5 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 +// Windows 头文件 +#include diff --git a/csgo2/global.cpp b/csgo2/global.cpp new file mode 100644 index 0000000..61d0b21 --- /dev/null +++ b/csgo2/global.cpp @@ -0,0 +1,4 @@ +#include "global.h" +namespace global { + bool Exit; +} \ No newline at end of file diff --git a/csgo2/global.h b/csgo2/global.h new file mode 100644 index 0000000..d592b77 --- /dev/null +++ b/csgo2/global.h @@ -0,0 +1,5 @@ +#pragma once +#include "pch.h" +namespace global { + extern bool Exit; +} \ No newline at end of file diff --git a/csgo2/hash_fnv1a_constexpr.h b/csgo2/hash_fnv1a_constexpr.h new file mode 100644 index 0000000..b5f0f13 --- /dev/null +++ b/csgo2/hash_fnv1a_constexpr.h @@ -0,0 +1,15 @@ +#pragma once +#include + +// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit +// str should be a null terminated string literal, value should be left out +// e.g hash_32_fnv1a_const("example") +// code license: public domain or equivalent +// post: https://notes.underscorediscovery.com/constexpr-fnv1a/ + +constexpr uint32_t val_32_const = 0x811c9dc5; +constexpr uint32_t prime_32_const = 0x1000193; + +inline constexpr uint32_t hash_32_fnv1a_const(const char* const str, const uint32_t value = val_32_const) noexcept { + return (str[0] == '\0') ? value : hash_32_fnv1a_const(&str[1], (value ^ uint32_t(str[0])) * prime_32_const); +} \ No newline at end of file diff --git a/csgo2/hooks.cpp b/csgo2/hooks.cpp new file mode 100644 index 0000000..84ea8f5 --- /dev/null +++ b/csgo2/hooks.cpp @@ -0,0 +1,120 @@ +#include "hooks.h" +#include "native_sdk/entity/cbaseentity.h" +#include "sdk/convar/convar.hpp" +FireEventServerSide_t original_FireEventServerSide = NULL; +OnClientConnect_t original_OnClientConnected = NULL; +Host_Say_t original_Host_Say = NULL; + +namespace hooks { + VTHook* HIServerGameClient; + bool __fastcall hook_OnClientConnected(CPlayerSlot slot, const char* pszName, uint64_t xuid, const char* pszNetworkID, bool unk1, CBufferString* pRejectReason) + { + LOG("Hook_OnClientConnected(%d, \"%s\", %d, \"%s\")\n", slot, pszName, xuid, pszNetworkID); + return original_OnClientConnected(slot, pszName, xuid, pszNetworkID, unk1, pRejectReason); + } + void __fastcall hook_Host_Say(void* pEntity, void* args, bool teamonly, int unk1, const char* unk2) + { + const auto theArgs = reinterpret_cast(args); + const auto theEntity = reinterpret_cast(pEntity); + char* pos = nullptr; + do + { + if (theArgs == nullptr || theEntity == nullptr) { + break; + } + auto message = std::string(theArgs->GetCommandString()); + printf("messageNoZero: %s \n", message.c_str()); + } while (false); + /* + if (*pMessage == '!' || *pMessage == '/') + ParseChatCommand(pMessage, pEntity); + + if (*pMessage == '/') + return; + */ + return original_Host_Say(pEntity, args, teamonly, unk1, unk2); + } + + bool __fastcall hook_FireEventServerSide(CGameEventManager* rcx, IGameEvent* event, + bool serverSide) { + do { + if (!event) { + break; + } + + const char* eventName = event->GetName(); + if (!eventName) { + break; + } + static constexpr auto player_death = + hash_32_fnv1a_const("player_death"); + static constexpr auto player_chat = + hash_32_fnv1a_const("player_chat"); + switch (hash_32_fnv1a_const(eventName)) + { + case player_death: + events::OnPlayerDeathEvent(event); + break; + //Vbug,ⲻ + /* + case player_chat: + events::OnPlayerChat(event); + break; + } + */ + } + + } while (false); + return original_FireEventServerSide(rcx, event, serverSide); + } + auto initMinHook() -> bool { + bool isSuccess = false; + // ʼMiniHook + do { + if (MH_Initialize() != MH_OK) { + LOG("MH_Initialize() != MH_OK\n"); + break; + } + // + if (MH_CreateHook((LPVOID)Offset::FireEventServerSidePtr, + &hook_FireEventServerSide, + reinterpret_cast( + &original_FireEventServerSide)) != MH_OK) { + LOG("MH_CreateHook original_FireEventServerSide\n"); + break; + } + if (MH_CreateHook((LPVOID)Offset::Host_SayPtr, + &hook_Host_Say, + reinterpret_cast( + &original_Host_Say)) != MH_OK) { + LOG("MH_CreateHook original_Host_Say\n"); + break; + } + // ù + if (MH_EnableHook(MH_ALL_HOOKS) != MH_OK) { + LOG("MH_EnableHook \n"); + break; + } + isSuccess = true; + } while (false); + return isSuccess; + + } + auto initVmtHook() -> bool { + + HIServerGameClient = new VTHook((DWORD64**)Offset::InterFaces::IServerGameClient); + original_OnClientConnected = (OnClientConnect_t)HIServerGameClient->HookFunction((DWORD64)hook_OnClientConnected, 1); + return original_OnClientConnected != nullptr; + } + auto init() -> bool { + bool isSuccess = initMinHook() && initVmtHook(); + //bool isSuccess = initVmtHook(); + return isSuccess; + } + auto unload() -> void + { + MH_DisableHook(MH_ALL_HOOKS); + MH_RemoveHook(MH_ALL_HOOKS); + MH_Uninitialize(); + } +} \ No newline at end of file diff --git a/csgo2/hooks.h b/csgo2/hooks.h new file mode 100644 index 0000000..6658ef3 --- /dev/null +++ b/csgo2/hooks.h @@ -0,0 +1,15 @@ +#pragma once +#include "pch.h" +#include "sdk/gameevent/IGameEvent.h" + + +typedef bool(__fastcall* FireEventServerSide_t)(CGameEventManager*, IGameEvent*, bool); +typedef void(__fastcall* Host_Say_t)(void*, void*, bool, int, const char*); +typedef bool(__fastcall* OnClientConnect_t)(CPlayerSlot, const char*, uint64_t, const char*, bool unk1, CBufferString*); + +extern FireEventServerSide_t original_FireEventServerSide; +extern Host_Say_t original_Host_Say; +namespace hooks { + auto init() -> bool; + auto unload() -> void; +} \ No newline at end of file diff --git a/csgo2/interface.cpp b/csgo2/interface.cpp new file mode 100644 index 0000000..077f315 --- /dev/null +++ b/csgo2/interface.cpp @@ -0,0 +1,4 @@ +#include "pch.h" +namespace interfaces { + +} // namespace interfaces diff --git a/csgo2/interface.h b/csgo2/interface.h new file mode 100644 index 0000000..b1fe292 --- /dev/null +++ b/csgo2/interface.h @@ -0,0 +1,5 @@ +#pragma once +#include "pch.h" +namespace interfaces { + +} // namespace interfaces diff --git a/csgo2/memory.cpp b/csgo2/memory.cpp new file mode 100644 index 0000000..e69de29 diff --git a/csgo2/memory.h b/csgo2/memory.h new file mode 100644 index 0000000..4dbc559 --- /dev/null +++ b/csgo2/memory.h @@ -0,0 +1,18 @@ +#pragma once +#include "pch.h" +namespace Memory { + template + void write(uintptr_t address, T value) + { + WriteProcessMemory(GetCurrentProcess(), (void*)address, &value, sizeof(T), 0); + } + + template + T read(uintptr_t address) + { + T buffer{}; + ReadProcessMemory(GetCurrentProcess(), (void*)address, &buffer, sizeof(T), 0); + return buffer; + } + +}; \ No newline at end of file diff --git a/csgo2/module.h b/csgo2/module.h new file mode 100644 index 0000000..e55f923 --- /dev/null +++ b/csgo2/module.h @@ -0,0 +1,146 @@ +#pragma once +#include "pch.h" +#define IS_WINDOWS 1 +class InterfaceReg; +// Pointer arithmetic utility class. +struct UTILPtr { + public: + template + UTILPtr(T val) { + m_val = (uintptr_t)(val); + } + + template + T Get(const char* variableName = nullptr) { +#ifdef CS2_SDK_ENABLE_LOGGING + if (variableName) LOG("%s found at -> %llX\n", variableName, m_val); +#endif + + return (T)(m_val); + } + + template + void Get(T& dst, const char* variableName = nullptr) { + dst = Get(variableName); + } + + UTILPtr& AddOffset(int offset) { + if (m_val) m_val += offset; + return *this; + } + UTILPtr& ToAbsolute(int preOffset, int postOffset) { + if (m_val) { + AddOffset(preOffset); + m_val = m_val + sizeof(int) + *(int*)(m_val); + AddOffset(postOffset); + } + return *this; + } + UTILPtr& Dereference(int dereferences) { + if (m_val) + while (dereferences-- != 0) m_val = *(uintptr_t*)(m_val); + return *this; + } + + bool IsValid() { return m_val != 0; } + + private: + uintptr_t m_val; +}; + +class CModule { + public: + // CS2TODO: Maybe write a simple caching system + + CModule(CModule&&) = delete; + CModule(const CModule&) = delete; + + explicit CModule(const char* name) : m_name(name) { this->Load(); } + + void Load() { + this->InitializeHandle(); + this->InitializeBounds(); + } + + UTILPtr GetProcAddress(const char* procName) const { + UTILPtr rv = 0; + if (this->IsLoaded()) { +#ifdef IS_WINDOWS + rv = ::GetProcAddress(static_cast(this->m_handle), + procName); +#endif + } + return rv; + } + UTILPtr FindInterface(const char* version) const { + UTILPtr rv = 0; + if (this->IsLoaded()) { + UTILPtr pCreateInterface = this->GetProcAddress("CreateInterface"); + if (!pCreateInterface.IsValid()) return rv; + + InterfaceReg* s_pInterfaceRegs = pCreateInterface.ToAbsolute(3, 0) + .Dereference(1) + .Get(); + + for (; s_pInterfaceRegs; + s_pInterfaceRegs = s_pInterfaceRegs->m_pNext) { + if (strcmp(version, s_pInterfaceRegs->m_pName) == 0) { + rv = s_pInterfaceRegs->m_CreateFn(); + break; + } + } + } + return rv; + } + template + UTILPtr FindPattern(const std::array& signature) const { + UTILPtr rv = 0; + if (this->IsLoaded()) { + const int* pSigData = signature.data(); + uint8_t* pBytes = reinterpret_cast(this->m_start); + for (size_t i = 0; i < this->m_end - N; ++i) { + bool found = true; + for (size_t j = 0; j < N; ++j) { + if (pBytes[i + j] != pSigData[j] && pSigData[j] != -1) { + found = false; + break; + } + } + + if (found) { + rv = reinterpret_cast(&pBytes[i]); + break; + } + } + } + return rv; + } + const char* GetName() const { return this->m_name; } + bool IsLoaded() const { return this->m_handle != 0; } + void* GetBase() const { return this->m_handle; } + + private: + void InitializeHandle() { +#ifdef IS_WINDOWS + this->m_handle = static_cast(GetModuleHandleA(this->GetName())); +#endif + } + void InitializeBounds() { + if (!this->IsLoaded()) return; + +#ifdef IS_WINDOWS + MODULEINFO mi; + BOOL status = GetModuleInformation(GetCurrentProcess(), + static_cast(this->m_handle), + &mi, sizeof(mi)); + if (status != 0) { + this->m_start = reinterpret_cast(this->m_handle); + this->m_end = static_cast(mi.SizeOfImage); + } +#endif + } + + void* m_handle = nullptr; + uintptr_t m_start = 0, m_end = 0; + const char* m_name = ""; +}; diff --git a/csgo2/native_sdk/cgameentitysystem.cpp b/csgo2/native_sdk/cgameentitysystem.cpp new file mode 100644 index 0000000..3d029c0 --- /dev/null +++ b/csgo2/native_sdk/cgameentitysystem.cpp @@ -0,0 +1,6 @@ +#include "cgameentitysystem.h" +#include "../pch.h" + +CGameEntitySystem* CGameEntitySystem::GetInstance(){ + return Offset::InterFaces::GameResourceServiceServer->GetGameEntitySystem(); +} diff --git a/csgo2/native_sdk/cgameentitysystem.h b/csgo2/native_sdk/cgameentitysystem.h new file mode 100644 index 0000000..412ed4f --- /dev/null +++ b/csgo2/native_sdk/cgameentitysystem.h @@ -0,0 +1,63 @@ +#pragma once +#include "entity/cbaseentity.h" + +#define MAX_ENTITIES_IN_LIST 512 +#define MAX_ENTITY_LISTS 64 +#define MAX_TOTAL_ENTITIES MAX_ENTITIES_IN_LIST *MAX_ENTITY_LISTS + +class CEntityIdentity +{ +public: + CBaseEntity *entity; + void *dunno; + int64_t unk0; + int64_t unk1; + const char *internalName; + const char *entityName; + void *unk2; + void *unk3; + void *unk4; + void *unk5; + CEntityIdentity *prevValid; + CEntityIdentity *nextValid; + void *unkptr; + void *unkptr2; + void *unkptr3; +}; + +class CEntityIdentities +{ +public: + CEntityIdentity m_pIdentities[MAX_ENTITIES_IN_LIST]; +}; + +class EntityIdentityList +{ +public: + CEntityIdentities *m_pIdentityList; +}; + +class CGameEntitySystem +{ +public: + virtual void n_0(); + void *unk; + CEntityIdentities *m_pEntityList[MAX_ENTITY_LISTS]; + + CBaseEntity *GetBaseEntity(int index) + { + if (index <= -1 || index >= MAX_TOTAL_ENTITIES) + return nullptr; + + int listToUse = (index / MAX_ENTITIES_IN_LIST); + if (!m_pEntityList[listToUse]) + return nullptr; + + if (m_pEntityList[listToUse]->m_pIdentities[index % MAX_ENTITIES_IN_LIST].entity) + return m_pEntityList[listToUse]->m_pIdentities[index % MAX_ENTITIES_IN_LIST].entity; + else + return nullptr; + } + + static CGameEntitySystem *GetInstance(); +}; \ No newline at end of file diff --git a/csgo2/native_sdk/cgameresourceserviceserver.h b/csgo2/native_sdk/cgameresourceserviceserver.h new file mode 100644 index 0000000..035ed80 --- /dev/null +++ b/csgo2/native_sdk/cgameresourceserviceserver.h @@ -0,0 +1,12 @@ +#pragma once +#include "../pch.h" +class CGameEntitySystem; + +class CGameResourceService +{ +public: + CGameEntitySystem *GetGameEntitySystem() + { + return *reinterpret_cast((uintptr_t)(this) + 0x58); + } +}; \ No newline at end of file diff --git a/csgo2/native_sdk/cschemasystem.cpp b/csgo2/native_sdk/cschemasystem.cpp new file mode 100644 index 0000000..8faed05 --- /dev/null +++ b/csgo2/native_sdk/cschemasystem.cpp @@ -0,0 +1,13 @@ +#include "cschemasystem.h" + +auto CSchemaSystemTypeScope::FindDeclaredClass(const char* pClass) -> SchemaClassInfoData_t* +{ + SchemaClassInfoData_t* rv = nullptr; + CALL_VIRTUAL(void, 2, this, &rv, pClass); + return rv; +} + +auto CSchemaSystem::FindTypeScopeForModule(const char* module) -> CSchemaSystemTypeScope* +{ + return CALL_VIRTUAL(CSchemaSystemTypeScope*, 13, this, module, nullptr); +} \ No newline at end of file diff --git a/csgo2/native_sdk/cschemasystem.h b/csgo2/native_sdk/cschemasystem.h new file mode 100644 index 0000000..2ae0fad --- /dev/null +++ b/csgo2/native_sdk/cschemasystem.h @@ -0,0 +1,77 @@ +#pragma once +#include "../pch.h" +#include "../vmt.h" + +struct SchemaClassFieldData_t +{ + const char *m_name; + char pad0[0x8]; + short m_offset; + char pad1[0xE]; +}; + +class SchemaClassInfoData_t; + +struct SchemaBaseClassInfoData_t +{ + unsigned int m_offset; + SchemaClassInfoData_t *m_class; +}; + +class SchemaClassInfoData_t +{ +public: + auto GetName() + { + return m_name; + } + + auto GetFieldsSize() + { + return m_align; + } + + auto GetFields() + { + return m_fields; + } + + auto GetParent() + { + return m_schema_parent->m_class; + } + +private: + char pad_0x0000[0x8]; // 0x0000 + + const char *m_name; // 0x0008 + char *m_module; // 0x0010 + + int m_size; // 0x0018 + std::int16_t m_align; // 0x001C + + std::int16_t m_static_size; // 0x001E + std::int16_t m_metadata_size; // 0x0020 + std::int16_t m_i_unk1; // 0x0022 + std::int16_t m_i_unk2; // 0x0024 + std::int16_t m_i_unk3; // 0x0026 + + SchemaClassFieldData_t *m_fields; // 0x0028 + + char pad_0x0030[0x8]; // 0x0030 + SchemaBaseClassInfoData_t *m_schema_parent; // 0x0038 + + char pad_0x0038[0x10]; // 0x0038 +}; + +class CSchemaSystemTypeScope +{ +public: + auto FindDeclaredClass(const char* pClass) -> SchemaClassInfoData_t*; +}; + +class CSchemaSystem +{ +public: + auto FindTypeScopeForModule(const char* module) ->CSchemaSystemTypeScope*; +}; \ No newline at end of file diff --git a/csgo2/native_sdk/entity/cbaseentity.h b/csgo2/native_sdk/entity/cbaseentity.h new file mode 100644 index 0000000..e9f39b4 --- /dev/null +++ b/csgo2/native_sdk/entity/cbaseentity.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../../schema.h" +#include "ccollisionproperty.h" +#include "../handle/handle.h" +#include "../cgameentitysystem.h" +class CEntityIdentity; +class CEntityInstance { +public: + DECLARE_CLASS(CEntityInstance); + + auto Schema_DynamicBinding() { + SchemaClassInfoData_t* rv = nullptr; + CALL_VIRTUAL(void, 0, this, &rv); + return rv; + } + + auto GetRefEHandle() { + CHandle handle; + CALL_VIRTUAL(void*, 2, this, &handle); + return handle; + } + + SCHEMA_FIELD(CEntityIdentity*, m_pEntity); + SCHEMA_FIELD(const char*, m_designerName); + +}; + +class CBaseEntity : CEntityInstance +{ +public: + DECLARE_CLASS(CBaseEntity); + + SCHEMA_FIELD(int, m_iHealth) + //SCHEMA_FIELD(Vector, m_vecBaseVelocity) + SCHEMA_FIELD(CCollisionProperty*, m_pCollision) +}; \ No newline at end of file diff --git a/csgo2/native_sdk/entity/cbaseplayercontroller.h b/csgo2/native_sdk/entity/cbaseplayercontroller.h new file mode 100644 index 0000000..abd869e --- /dev/null +++ b/csgo2/native_sdk/entity/cbaseplayercontroller.h @@ -0,0 +1,24 @@ +#pragma once +#include "../../pch.h" +#include "../handle/handle.h" +#include "cbaseentity.h" +class CBasePlayerController : public CBaseEntity +{ +public: + DECLARE_CLASS(CBasePlayerController); + + SCHEMA_FIELD(uint64_t, m_steamID) + SCHEMA_FIELD(CHandle, m_hPawn) + SCHEMA_FIELD(char, m_iszPlayerName) + +}; + +class CCSPlayerController : public CBasePlayerController { +public: + DECLARE_CLASS(CCSPlayerController) + + SCHEMA_FIELD(uint32_t, m_iPawnHealth) + SCHEMA_FIELD(bool, m_bPawnIsAlive) + SCHEMA_FIELD(const char*, m_szClanName) + +}; diff --git a/csgo2/native_sdk/entity/cbaseplayerpawn.h b/csgo2/native_sdk/entity/cbaseplayerpawn.h new file mode 100644 index 0000000..9cc9f23 --- /dev/null +++ b/csgo2/native_sdk/entity/cbaseplayerpawn.h @@ -0,0 +1,14 @@ +#pragma once + +#include "cbaseentity.h" +#include "services.h" + +class CBasePlayerPawn : public CBaseEntity +{ +public: + DECLARE_CLASS(CBasePlayerPawn); + + SCHEMA_FIELD(CPlayer_MovementServices*, m_pMovementServices) + SCHEMA_FIELD(uint8*, m_pWeaponServices) + SCHEMA_FIELD(uint8**, m_pItemServices) +}; \ No newline at end of file diff --git a/csgo2/native_sdk/entity/ccollisionproperty.h b/csgo2/native_sdk/entity/ccollisionproperty.h new file mode 100644 index 0000000..fae053e --- /dev/null +++ b/csgo2/native_sdk/entity/ccollisionproperty.h @@ -0,0 +1,21 @@ +#pragma once +#include "../../pch.h" +#include "../../schema.h" + +struct VPhysicsCollisionAttribute_t +{ + DECLARE_CLASS(VPhysicsCollisionAttribute_t) + + SCHEMA_FIELD(uint8_t, m_nCollisionGroup) +}; + +class CCollisionProperty +{ +public: + DECLARE_CLASS(CCollisionProperty) + + SCHEMA_FIELD(VPhysicsCollisionAttribute_t, m_collisionAttribute) + //SCHEMA_FIELD(SolidType_t, m_nSolidType) + SCHEMA_FIELD(uint8_t, m_usSolidFlags) + SCHEMA_FIELD(uint8_t, m_CollisionGroup) +}; \ No newline at end of file diff --git a/csgo2/native_sdk/entity/ccsplayercontroller.h b/csgo2/native_sdk/entity/ccsplayercontroller.h new file mode 100644 index 0000000..8b08ccc --- /dev/null +++ b/csgo2/native_sdk/entity/ccsplayercontroller.h @@ -0,0 +1,12 @@ +#pragma once + +#include "cbaseplayercontroller.h" +#include "services.h" + +class CCSPlayerController : public CBasePlayerController +{ +public: + DECLARE_CLASS(CCSPlayerController); + + SCHEMA_FIELD(CCSPlayerController_InGameMoneyServices*, m_pInGameMoneyServices) +}; \ No newline at end of file diff --git a/csgo2/native_sdk/entity/ccsplayerpawn.h b/csgo2/native_sdk/entity/ccsplayerpawn.h new file mode 100644 index 0000000..6c1f72e --- /dev/null +++ b/csgo2/native_sdk/entity/ccsplayerpawn.h @@ -0,0 +1,9 @@ +#pragma once + +#include "cbaseplayerpawn.h" + +class CCSPlayerPawn : public CBasePlayerPawn +{ +public: + DECLARE_CLASS(CCSPlayerPawn); +}; \ No newline at end of file diff --git a/csgo2/native_sdk/entity/services.h b/csgo2/native_sdk/entity/services.h new file mode 100644 index 0000000..eba7b37 --- /dev/null +++ b/csgo2/native_sdk/entity/services.h @@ -0,0 +1,18 @@ +#pragma once +#include + +#include "../schema.h" + +class CPlayer_MovementServices +{ +public: + DECLARE_CLASS(CPlayer_MovementServices); +}; + +class CCSPlayerController_InGameMoneyServices +{ +public: + DECLARE_CLASS(CCSPlayerController_InGameMoneyServices); + + SCHEMA_FIELD(int, m_iAccount) +}; \ No newline at end of file diff --git a/csgo2/native_sdk/handle/handle.cpp b/csgo2/native_sdk/handle/handle.cpp new file mode 100644 index 0000000..00da4bb --- /dev/null +++ b/csgo2/native_sdk/handle/handle.cpp @@ -0,0 +1,11 @@ +#include "handle.h" +#include "../cgameentitysystem.h" + +CBaseEntity* CHandle::GetBaseEntity() const +{ + CGameEntitySystem* pEntitySystem = CGameEntitySystem::GetInstance(); + if (!pEntitySystem) + return nullptr; + + return pEntitySystem->GetBaseEntity(GetEntryIndex()); +} \ No newline at end of file diff --git a/csgo2/native_sdk/handle/handle.h b/csgo2/native_sdk/handle/handle.h new file mode 100644 index 0000000..bafa6bc --- /dev/null +++ b/csgo2/native_sdk/handle/handle.h @@ -0,0 +1,26 @@ +#pragma once +#include +#define INVALID_EHANDLE_INDEX 0xFFFFFFFF +#define ENT_ENTRY_MASK 0x7FFF + +class CBaseEntity; + +class CHandle +{ + CBaseEntity* GetBaseEntity() const; + +public: + bool operator==(CHandle rhs) const { return m_Index == rhs.m_Index; } + + bool IsValid() const { return m_Index != INVALID_EHANDLE_INDEX; } + + int GetEntryIndex() const { return m_Index & ENT_ENTRY_MASK; } + + template + T* Get() const + { + return reinterpret_cast(GetBaseEntity()); + } + + uint32_t m_Index; +}; \ No newline at end of file diff --git a/csgo2/offset.cpp b/csgo2/offset.cpp new file mode 100644 index 0000000..9c371f9 --- /dev/null +++ b/csgo2/offset.cpp @@ -0,0 +1,56 @@ +#include "offset.h" + +namespace Offset { +uint64_t GameResourceServicePtr; +uint64_t FireEventServerSidePtr; +uint64_t NetworkStateChangedPtr; +uint64_t CGameEventManagerPtr; +uint64_t Host_SayPtr; +uint64_t Module_tier0; +namespace InterFaces { + CSchemaSystem* SchemaSystem; + IGameEventManager2* GameEventManager; + CGameEventManager* CGameEventManger; + CGameResourceService* GameResourceServiceServer; + IServerGameClients* IServerGameClient; +}; +auto Init() -> bool { + CModule server("server.dll"); + CModule schemasystem("schemasystem.dll"); + CModule engine("engine2.dll"); + + // server.dll + server.FindPattern(pattern_FireEventServerSide).Get(FireEventServerSidePtr); + server.FindPattern(pattern_NetworkStateChanged).Get(NetworkStateChangedPtr); + //48 8D 05 4A 30 82 00 lea rax, ??_7CGameEventManager@@6B@ + server.FindPattern(pattern_CGameEventManager).ToAbsolute(3, 0).Get(CGameEventManagerPtr); + server.FindPattern(pattern_fnHost_SayPtr).Get(Host_SayPtr); + + //schemasystem + InterFaces::SchemaSystem = reinterpret_cast(schemasystem.FindInterface("SchemaSystem_001").Get()); + // engine.dll + InterFaces::GameEventManager = reinterpret_cast(engine.FindInterface("GameEventSystemServerV001").Get()); + InterFaces::GameResourceServiceServer = reinterpret_cast(engine.FindInterface("Source2GameClients001").Get()); + + // server.dll + InterFaces::IServerGameClient = reinterpret_cast(server.FindInterface("GameResourceServiceServerV001").Get()); + // only init in console server + InterFaces::CGameEventManger = reinterpret_cast(CGameEventManagerPtr); + + + //client.FindPattern(pattern_FireEventServerSide).Get(FireEventServerSidePtr); + LOG("[huoji]FireEventServerSidePtr : %llx \n", FireEventServerSidePtr); + LOG("[huoji]NetworkStateChangedPtr : %llx \n", NetworkStateChangedPtr); + LOG("[huoji]Host_SayPtr : %llx \n", Host_SayPtr); + + LOG("[huoji]InterFaces::SchemaSystem : %llx \n", InterFaces::SchemaSystem); + LOG("[huoji]InterFaces::GameEventManager : %llx \n", InterFaces::GameEventManager); + LOG("[huoji]InterFaces::CGameEventManger : %llx \n", InterFaces::CGameEventManger); + LOG("[huoji]InterFaces::GameResourceServiceServer : %llx \n", InterFaces::GameResourceServiceServer); + LOG("[huoji]InterFaces::IServerGameClient : %llx \n", InterFaces::IServerGameClient); + + //GetOffsets(); + LOG("init offset success !\n"); + return Host_SayPtr && InterFaces::GameResourceServiceServer && InterFaces::IServerGameClient && InterFaces::GameEventManager && InterFaces::SchemaSystem && FireEventServerSidePtr && NetworkStateChangedPtr; +} +} // namespace Offset diff --git a/csgo2/offset.h b/csgo2/offset.h new file mode 100644 index 0000000..f314daa --- /dev/null +++ b/csgo2/offset.h @@ -0,0 +1,38 @@ +#pragma once +#include "pch.h" +#include "native_sdk/cschemasystem.h" +#include "native_sdk/cgameresourceserviceserver.h" +#include "sdk/public/eiface.h" +class CSchemaSystem; + +namespace Offset { +namespace InterFaces { + extern CSchemaSystem* SchemaSystem; + extern IGameEventManager2* GameEventManager; + extern CGameEventManager* CGameEventManger; + extern CGameResourceService* GameResourceServiceServer; + extern IServerGameClients* IServerGameClient; +}; +static const auto pattern_CGameEventManager = THE_GAME_SIG("48 ?? ?? ?? ?? ?? ?? 48 89 ?? ?? ?? 48 89 01 48 8B D9 48 ?? ?? ?? ?? ?? ?? 48 89 ?? ?? E8 ?? ?? ?? ?? 48 ?? ?? ?? ?? ?? ??"); +static const auto pattern_NetworkStateChanged = THE_GAME_SIG("4C 8B C9 48 8B 09 48 85 C9 74 ? 48 8B 41 10"); +static const auto pattern_FireEventServerSide = THE_GAME_SIG( + "40 53 57 41 54 41 55 41 56 48 ?? ?? ?? 4C 8B F2 4C 8B E1 BA ?? ?? ?? " + "?? 48 ?? ?? ?? ?? ?? ?? 45 0F B6 E8 E8 ?? ?? ?? ?? 48 85 C0 75 ?? 48 " + "?? ?? ?? ?? ?? ?? 48 8B ?? ?? 80 ?? ?? 74 ?? 49 8B 06 49 8B CE FF ?? " + "?? 48 8B D0 48 ?? ?? ?? ?? ?? ?? FF ?? ?? ?? ?? ??"); +static const auto pattern_fnGetBaseEntity = + THE_GAME_SIG("8B D3 E8 ? ? ? ? 48 8B F8 48 85 C0 74 76"); +static const auto pattern_fnGetHighestEntityIndex = + THE_GAME_SIG("33 DB E8 ? ? ? ? 8B 08"); +static const auto pattern_fnGetLocalPlayerController = + THE_GAME_SIG("E8 ? ? ? ? 49 89 47 08"); +//"\"Console<0>\" say \"%s\"\n" +static const auto pattern_fnHost_SayPtr = + THE_GAME_SIG("44 89 4C 24 ?? 44 88 44 24 ?? 55 53 56 57 41 54 41 55"); +extern uint64_t GameResourceServicePtr; +extern uint64_t FireEventServerSidePtr; +extern uint64_t Module_tier0; +extern uint64_t NetworkStateChangedPtr; +extern uint64_t Host_SayPtr; +auto Init() -> bool; +}; // namespace Offset diff --git a/csgo2/pch.cpp b/csgo2/pch.cpp new file mode 100644 index 0000000..70af52d --- /dev/null +++ b/csgo2/pch.cpp @@ -0,0 +1,17 @@ +// pch.cpp: 与预编译标头对应的源文件 + +#include "pch.h" +void DebugPrintA(const char* format, ...) { + std::string temp; + va_list marker = { 0 }; + va_start(marker, format); + size_t num_of_chars = _vscprintf(format, marker); + if (num_of_chars > temp.capacity()) { + temp.reserve(num_of_chars + 1); + } + vsprintf_s(const_cast(temp.c_str()), num_of_chars + 1, format, + marker); + OutputDebugStringA(temp.c_str()); +} + +// 当使用预编译的头时,需要使用此源文件,编译才能成功。 diff --git a/csgo2/pch.h b/csgo2/pch.h new file mode 100644 index 0000000..a39204a --- /dev/null +++ b/csgo2/pch.h @@ -0,0 +1,34 @@ +// pch.h: 这是预编译标头文件。 +// 下方列出的文件仅编译一次,提高了将来生成的生成性能。 +// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 +// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 +// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 +#include +#include +#include +#include +#include +#include + +#include "framework.h" +#include "stb.hh" + +#include "memory.h" +extern void DebugPrintA(const char* format, ...); +//#define LOG DebugPrintA +#define LOG(...) printf(__VA_ARGS__) +#define THE_GAME_SIG(sig) \ + stb::simple_conversion::build::value +#include "vmt.h" + +#include "./MinHook/include/MinHook.h" +#include "sdk/sdk.h" +#include "interface.h" +#include "module.h" +#include "hash_fnv1a_constexpr.h" +#include "global.h" + +#include "offset.h" +#include "events.h" +#include "hooks.h" +#include "VTHook.h" \ No newline at end of file diff --git a/csgo2/player.cpp b/csgo2/player.cpp new file mode 100644 index 0000000..23fb848 --- /dev/null +++ b/csgo2/player.cpp @@ -0,0 +1,6 @@ +#include "player.h" + +auto CBasePlayer::ForceRespawn() -> void +{ + return CALL_VIRTUAL(void, 26, this); +} \ No newline at end of file diff --git a/csgo2/player.h b/csgo2/player.h new file mode 100644 index 0000000..2cc1ba5 --- /dev/null +++ b/csgo2/player.h @@ -0,0 +1,38 @@ +#pragma once +#include "pch.h" +#include "schema.h" +#include "native_sdk/entity/cbaseentity.h" +class CBasePlayer { +public: + auto ForceRespawn() -> void; +}; + +class CPlayer_MovementServices +{ +public: + DECLARE_CLASS(CPlayer_MovementServices); +}; + +class CCSPlayerController_InGameMoneyServices +{ +public: + DECLARE_CLASS(CCSPlayerController_InGameMoneyServices); + + SCHEMA_FIELD(int, m_iAccount) +}; +class CBasePlayerPawn : public CBaseEntity +{ +public: + DECLARE_CLASS(CBasePlayerPawn); + + SCHEMA_FIELD(CPlayer_MovementServices*, m_pMovementServices) + SCHEMA_FIELD(uint8_t*, m_pWeaponServices) + SCHEMA_FIELD(uint8_t**, m_pItemServices) +}; +class CCSPlayerPawn : public CBasePlayerPawn +{ +public: + DECLARE_CLASS(CCSPlayerPawn); + SCHEMA_FIELD(const char*, m_szLastPlaceName) + +}; \ No newline at end of file diff --git a/csgo2/schema.cpp b/csgo2/schema.cpp new file mode 100644 index 0000000..7dbffa7 --- /dev/null +++ b/csgo2/schema.cpp @@ -0,0 +1,81 @@ +#include "schema.h" +#include "native_sdk/cgameentitysystem.h" +#include "native_sdk/cschemasystem.h" +using SchemaKeyValueMap_t = std::unordered_map; +using SchemaTableMap_t = std::unordered_map; + +static bool InitSchemaFieldsForClass(SchemaTableMap_t& tableMap, + const char* className, uint32_t classKey) { + CSchemaSystemTypeScope* pType = + Offset::InterFaces::SchemaSystem->FindTypeScopeForModule("server.dll"); + if (!pType) return false; + + SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className); + if (!pClassInfo) { + tableMap.emplace(classKey, SchemaKeyValueMap_t{}); + + LOG("InitSchemaFieldsForClass(): '%s' was not found!\n", className); + return false; + } + + short fieldsSize = pClassInfo->GetFieldsSize(); + SchemaClassFieldData_t* pFields = pClassInfo->GetFields(); + + auto& keyValueMap = tableMap[classKey]; + keyValueMap.reserve(fieldsSize); + + for (int i = 0; i < fieldsSize; ++i) { + SchemaClassFieldData_t& field = pFields[i]; + LOG("%s::%s found at -> 0x%X\n", className, field.m_name, + field.m_offset); + keyValueMap.emplace(hash_32_fnv1a_const(field.m_name), field.m_offset); + } + + return true; +} + +int16_t schema::FindChainOffset(const char* className) +{ + CSchemaSystemTypeScope* pType = + Offset::InterFaces::SchemaSystem->FindTypeScopeForModule("server.dll"); + if (!pType) return false; + + SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className); + + do + { + SchemaClassFieldData_t* pFields = pClassInfo->GetFields(); + short fieldsSize = pClassInfo->GetFieldsSize(); + for (int i = 0; i < fieldsSize; ++i) { + SchemaClassFieldData_t& field = pFields[i]; + + if (strcmp(field.m_name, "__m_pChainEntity") == 0) + { + return field.m_offset; + } + + } + } while ((pClassInfo = pClassInfo->GetParent()) != nullptr); + + return 0; +} + +int16_t schema::GetOffset(const char* className, uint32_t classKey, + const char* memberName, uint32_t memberKey) { + static SchemaTableMap_t schemaTableMap; + const auto& tableMapIt = schemaTableMap.find(classKey); + if (tableMapIt == schemaTableMap.cend()) { + if (InitSchemaFieldsForClass(schemaTableMap, className, classKey)) + return GetOffset(className, classKey, memberName, memberKey); + return 0; + } + + const SchemaKeyValueMap_t& tableMap = tableMapIt->second; + if (tableMap.find(memberKey) == tableMap.cend()) { + LOG("schema::GetOffset(): '%s' was not found in '%s'!\n", memberName, className); + + return 0; + } + + return tableMap.at(memberKey); +} \ No newline at end of file diff --git a/csgo2/schema.h b/csgo2/schema.h new file mode 100644 index 0000000..8b0bd3e --- /dev/null +++ b/csgo2/schema.h @@ -0,0 +1,60 @@ +#pragma once +#include "pch.h" +typedef void(__fastcall* FnNetworkStateChanged)(uintptr_t chainEntity, uintptr_t offset, uintptr_t a3); + +#define SCHEMA_FIELD_OFFSET(type, varName, extra_offset) \ + std::add_lvalue_reference_t varName() \ + { \ + static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ + static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ + \ + static const auto m_offset = \ + schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ + \ + return *reinterpret_cast>( \ + (uintptr_t)(this) + m_offset + extra_offset); \ + } \ + void varName(type val) \ + { \ + static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ + static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ + \ + static const auto m_offset = \ + schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ + \ + static const auto m_chain = \ + schema::FindChainOffset(ThisClass); \ + \ + if (m_chain != 0) \ + { \ + reinterpret_cast(Offset::NetworkStateChangedPtr)((uintptr_t)(this) + m_chain, m_offset + extra_offset, 0xFFFFFFFF); \ + } \ + *reinterpret_cast>((uintptr_t)(this) + m_offset + extra_offset) = val; \ + } + +#define SCHEMA_FIELD(type, varName) \ + SCHEMA_FIELD_OFFSET(type, varName, 0) + +#define PSCHEMA_FIELD_OFFSET(type, varName, extra_offset) \ + auto varName() \ + { \ + static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ + static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ + \ + static const auto m_offset = \ + schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ + \ + return reinterpret_cast>( \ + (uintptr_t)(this) + m_offset + extra_offset); \ + } + +#define PSCHEMA_FIELD(type, varName) \ + PSCHEMA_FIELD_OFFSET(type, varName, 0) + +namespace schema +{ + int16_t FindChainOffset(const char* className); + int16_t GetOffset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey); +} + +#define DECLARE_CLASS(className) static constexpr auto ThisClass = #className; diff --git a/csgo2/sdk/convar/convar.cpp b/csgo2/sdk/convar/convar.cpp new file mode 100644 index 0000000..2bc9cca --- /dev/null +++ b/csgo2/sdk/convar/convar.cpp @@ -0,0 +1,18 @@ +#include "convar.hpp" + +inline const char** CCommand::ArgV() const +{ + return ArgC() ? (const char**)m_Args.Base() : NULL; +} + +inline const char* CCommand::ArgS() const +{ + return m_nArgv0Size ? (m_ArgSBuffer.Base() + m_nArgv0Size) : ""; +} + + + +inline const char* CCommand::operator[](int nIndex) const +{ + return Arg(nIndex); +} diff --git a/csgo2/sdk/convar/convar.hpp b/csgo2/sdk/convar/convar.hpp new file mode 100644 index 0000000..4ee0400 --- /dev/null +++ b/csgo2/sdk/convar/convar.hpp @@ -0,0 +1,128 @@ +#include "../sdk.h" +#include "../tier1/UtlVector.hpp" +struct characterset_t +{ + char set[256]; +}; +class ConCommandBase +{ + friend class CCvar; + friend class ConCommand; + +protected: + ConCommandBase(void); +public: + + ~ConCommandBase(void); + // Check flag + bool IsFlagSet(int64_t flag) const; + // Set flag + void AddFlags(int64_t flags); + // Clear flag + void RemoveFlags(int64_t flags); + + int64_t GetFlags() const; + + // Return name of cvar + const char* GetName(void) const; + + // Return help text for cvar + const char* GetHelpText(void) const; + +private: + // Static data + const char* m_pszName; + const char* m_pszHelpString; + + // ConVar flags + int64_t m_nFlags; +}; + +template< class T, size_t SIZE, class I = int > +class CUtlMemoryFixedGrowable : public CUtlMemory< T, I > +{ + typedef CUtlMemory< T, I > BaseClass; + +public: + CUtlMemoryFixedGrowable(int nGrowSize = 0, int nInitSize = SIZE) : BaseClass(m_pFixedMemory, SIZE) + { + Assert(nInitSize == 0 || nInitSize == SIZE); + } + + void EnsureCapacity(int num) + { + if (CUtlMemory::m_nAllocationCount >= num) + return; + + BaseClass::EnsureCapacity(num); + } + +private: + T m_pFixedMemory[SIZE]; +}; + +template< class T, size_t MAX_SIZE > +class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable > +{ + typedef CUtlVector< T, CUtlMemoryFixedGrowable > BaseClass; + +public: + // constructor, destructor + CUtlVectorFixedGrowable(int growSize = 0) : BaseClass(growSize, MAX_SIZE) {} +}; + + +class CCommand +{ +public: + CCommand(); + CCommand(int nArgC, const char** ppArgV); + virtual bool Tokenize(const char* pCommand, characterset_t* pBreakSet = NULL); + virtual void Reset(); + + int ArgC() const { + return m_Args.Count(); + } + const char** ArgV() const; + const char* ArgS() const; // All args that occur after the 0th arg, in string form + const char* GetCommandString() const + { + return ArgC() ? m_ArgSBuffer.Base() : ""; + } + const char* operator[](int nIndex) const; // Gets at arguments + const char* Arg(int nIndex) const { + // FIXME: Many command handlers appear to not be particularly careful + // about checking for valid argc range. For now, we're going to + // do the extra check and return an empty string if it's out of range + if (nIndex < 0 || nIndex >= ArgC()) + return ""; + return m_Args[nIndex]; + + } + + // Helper functions to parse arguments to commands. + // + // Returns index of argument, or -1 if no such argument. + int FindArg(const char* pName) const; + + int FindArgInt(const char* pName, int nDefaultVal) const; + + static int MaxCommandLength() + { + return COMMAND_MAX_LENGTH - 1; + } + static characterset_t* DefaultBreakSet(); + +private: + enum + { + COMMAND_MAX_ARGC = 64, + COMMAND_MAX_LENGTH = 512, + }; + + int m_nArgv0Size; + CUtlVectorFixedGrowable m_ArgSBuffer; + CUtlVectorFixedGrowable m_ArgvBuffer; + CUtlVectorFixedGrowable m_Args; +}; + diff --git a/csgo2/sdk/gameevent/IGameEvent.h b/csgo2/sdk/gameevent/IGameEvent.h new file mode 100644 index 0000000..5df198c --- /dev/null +++ b/csgo2/sdk/gameevent/IGameEvent.h @@ -0,0 +1,151 @@ +#pragma once +#include "../sdk.h" +#include "../player/playerslot.h" +#include "../player/player.h" +#include "../handle/basehandle.h" +#include "../interfaces/interfaces.h" +class CMsgSource1LegacyGameEvent; +class CUtlString; +class IToolGameEventAPI +{ + virtual void unk001(void*) = 0; +}; + +struct UnkGameEventStruct_t { + UnkGameEventStruct_t(const char* keyName) { + m_Unk = 0; + m_Key = keyName; + } + + uint64_t m_Unk; + const char* m_Key; +}; + +class IGameEvent +{ +public: + virtual ~IGameEvent() {}; + virtual const char* GetName() const = 0; // get event name + virtual int GetID() const = 0; + + virtual bool IsReliable() const = 0; // if event handled reliable + virtual bool IsLocal() const = 0; // if event is never networked + virtual bool IsEmpty(const char* keyName = NULL) = 0; // check if data field exists + + // Data access + virtual bool GetBool(const char* keyName = NULL, bool defaultValue = false) = 0; + virtual int GetInt(const char* keyName = NULL, int defaultValue = 0) = 0; + virtual uint64_t GetUint64(const char* keyName = NULL, uint64_t defaultValue = 0) = 0; + virtual float GetFloat(const char* keyName = NULL, float defaultValue = 0.0f) = 0; + virtual const char* GetString(const char* keyName = NULL, const char* defaultValue = "") = 0; + virtual void* GetPtr(const char* keyName = NULL, void* defaultValue = NULL) = 0; + + /* These function prototypes and names are very speculative and might be incorrect */ + virtual CEntityHandle GetEHandle(UnkGameEventStruct_t* keyName, CEntityHandle defaultValue) = 0; + virtual CEntityHandle GetStrictEHandle(UnkGameEventStruct_t* keyName, CEntityHandle defaultValue) = 0; + virtual CEntityHandle GetEHandle2(UnkGameEventStruct_t* keyName, CEntityHandle defaultValue) = 0; + + virtual CPlayerSlot* GetPlayerSlot(UnkGameEventStruct_t* keyName = NULL) = 0; + virtual CBasePlayer* GetPlayer(UnkGameEventStruct_t* keyName = NULL) = 0; + + virtual void* GetPlayerPawn(UnkGameEventStruct_t* keyName = NULL) = 0; + virtual CEntityHandle GetPlayerControllerEHandle(UnkGameEventStruct_t* keyName = NULL) = 0; + virtual CEntityHandle GetPlayerControllerEHandle2(UnkGameEventStruct_t* keyName = NULL) = 0; + /* ============================================================ */ + + virtual void SetBool(const char* keyName, bool value) = 0; + virtual void SetInt(const char* keyName, int value) = 0; + virtual void SetUint64(const char* keyName, uint64_t value) = 0; + virtual void SetFloat(const char* keyName, float value) = 0; + virtual void SetString(const char* keyName, const char* value) = 0; + virtual void SetPtr(const char* keyName, void* value) = 0; + + /* These function prototypes and names are very speculative and might be incorrect */ + virtual void SetEHandleStrict(const char* keyName, CEntityHandle handle) = 0; + virtual void SetEHandle(const char* keyName, CEntityHandle handle) = 0; + + // Also sets the _pawn key + virtual void SetPlayerSlot(const char* keyName, CPlayerSlot value) = 0; + virtual void SetPlayer(const char* keyName, CBasePlayer* value) = 0; + /* ============================================================ */ + + virtual bool HasKey(const char* keyName) = 0; + + // Something script vm related + virtual void unk001() = 0; + + //virtual KeyValues* GetDataKeys() const = 0; +}; +class IGameEventListener2 +{ +public: + virtual ~IGameEventListener2(void) {}; + + // FireEvent is called by EventManager if event just occured + // KeyValue memory will be freed by manager if not needed anymore + virtual void FireGameEvent(IGameEvent* event) = 0; +}; +class IGameEventManager2 : public IBaseInterface, public IToolGameEventAPI +{ +public: + virtual ~IGameEventManager2(void) {}; + + // load game event descriptions from a file eg "resource\gameevents.res" + virtual int LoadEventsFromFile(const char* filename, bool bSearchAll) = 0; + + // removes all and anything + virtual void Reset() = 0; + + // adds a listener for a particular event + virtual bool AddListener(IGameEventListener2* listener, const char* name, bool bServerSide) = 0; + + // returns true if this listener is listens to given event + virtual bool FindListener(IGameEventListener2* listener, const char* name) = 0; + + // removes a listener + virtual void RemoveListener(IGameEventListener2* listener) = 0; + + // create an event by name, but doesn't fire it. returns NULL is event is not + // known or no listener is registered for it. bForce forces the creation even if no listener is active + virtual IGameEvent* CreateEvent(const char* name, bool bForce = false, int* pCookie = NULL) = 0; + + // fires a server event created earlier, if bDontBroadcast is set, event is not send to clients + virtual bool FireEvent(IGameEvent* event, bool bDontBroadcast = false) = 0; + + // fires an event for the local client only, should be used only by client code + virtual bool FireEventClientSide(IGameEvent* event) = 0; + + // create a new copy of this event, must be free later + virtual IGameEvent* DuplicateEvent(IGameEvent* event) = 0; + + // if an event was created but not fired for some reason, it has to bee freed, same UnserializeEvent + virtual void FreeEvent(IGameEvent* event) = 0; + + // write/read event to/from bitbuffer + virtual bool SerializeEvent(IGameEvent* event, CMsgSource1LegacyGameEvent* ev) = 0; + virtual IGameEvent* UnserializeEvent(const CMsgSource1LegacyGameEvent& ev) = 0; // create new KeyValues, must be deleted + + virtual int LookupEventId(const char* name) = 0; + + virtual void PrintEventToString(IGameEvent* event, CUtlString& out) = 0; + + virtual bool HasEventDescriptor(const char* name) = 0; +}; + +class CGameEventManager : public IGameEventManager2 +{ +public: // IGameEventManager functions + virtual ~CGameEventManager() = 0; + + virtual int LoadEventsFromFile(const char* filename) = 0; + virtual void Reset() = 0; + + virtual bool AddListener(IGameEventListener2* listener, const char* name, bool bServerSide) = 0; + virtual bool FindListener(IGameEventListener2* listener, const char* name) = 0; + virtual void RemoveListener(IGameEventListener2* listener) = 0; + + virtual IGameEvent* CreateEvent(const char* name, bool bForce = false) = 0; + virtual IGameEvent* DuplicateEvent(IGameEvent* event) = 0; + virtual bool FireEvent(IGameEvent* event, bool bDontBroadcast = false) = 0; + virtual bool FireEventClientSide(IGameEvent* event) = 0; +}; diff --git a/csgo2/sdk/handle/basehandle.h b/csgo2/sdk/handle/basehandle.h new file mode 100644 index 0000000..35b9725 --- /dev/null +++ b/csgo2/sdk/handle/basehandle.h @@ -0,0 +1,16 @@ +#pragma once +#include "../sdk.h" + +class CEntityHandle +{ +public: + union + { + uint32_t m_Index; + struct + { + uint32_t m_EntityIndex : 15; + uint32_t m_Serial : 17; + } m_Parts; + }; +}; diff --git a/csgo2/sdk/interfaces/interfaces.h b/csgo2/sdk/interfaces/interfaces.h new file mode 100644 index 0000000..e3f3437 --- /dev/null +++ b/csgo2/sdk/interfaces/interfaces.h @@ -0,0 +1,21 @@ +#include "../sdk.h" +class IBaseInterface +{ +public: + virtual ~IBaseInterface() {} +}; + +typedef void* (*InstantiateInterfaceFn)(); + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char* pName); + +public: + InstantiateInterfaceFn m_CreateFn; + const char* m_pName; + + InterfaceReg* m_pNext; // For the global list. +}; diff --git a/csgo2/sdk/player/player.h b/csgo2/sdk/player/player.h new file mode 100644 index 0000000..dc36072 --- /dev/null +++ b/csgo2/sdk/player/player.h @@ -0,0 +1,3 @@ +#pragma once +#include "../sdk.h" +class CBasePlayer; diff --git a/csgo2/sdk/player/playerslot.h b/csgo2/sdk/player/playerslot.h new file mode 100644 index 0000000..6a2b9dc --- /dev/null +++ b/csgo2/sdk/player/playerslot.h @@ -0,0 +1,24 @@ +#pragma once +#include "../sdk.h" +class CPlayerSlot +{ +public: + CPlayerSlot(int slot) : m_Data(slot) + { + } + + int Get() const + { + return m_Data; + } + + bool operator==(const CPlayerSlot& other) const { + return other.m_Data == m_Data; + } + bool operator!=(const CPlayerSlot& other) const { + return other.m_Data != m_Data; + } + +private: + int m_Data; +}; \ No newline at end of file diff --git a/csgo2/sdk/public/IAppSystem.h b/csgo2/sdk/public/IAppSystem.h new file mode 100644 index 0000000..facb9aa --- /dev/null +++ b/csgo2/sdk/public/IAppSystem.h @@ -0,0 +1,63 @@ +#pragma once +#include "../sdk.h" +struct AppSystemInfo_t +{ + const char* m_pModuleName; + const char* m_pInterfaceName; +}; + +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + + INIT_LAST_VAL, +}; + +enum AppSystemTier_t +{ + APP_SYSTEM_TIER0 = 0, + APP_SYSTEM_TIER1, + APP_SYSTEM_TIER2, + APP_SYSTEM_TIER3, + APP_SYSTEM_TIER4, + + APP_SYSTEM_TIER_OTHER, +}; + +enum BuildType_t +{ + kBuildTypeRelease = 2 +}; + + +class IAppSystem +{ +public: + // Here's where the app systems get to learn about each other + virtual bool Connect(void* factory) = 0; + virtual void Disconnect() = 0; + + // Here's where systems can access other interfaces implemented by this object + // Returns NULL if it doesn't implement the requested interface + virtual void* QueryInterface(const char* pInterfaceName) = 0; + + // Init, shutdown + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + virtual void PreShutdown() = 0; + + // Returns all dependent libraries + virtual const AppSystemInfo_t* GetDependencies() = 0; + + // Returns the tier + virtual AppSystemTier_t GetTier() = 0; + + // Reconnect to a particular interface + virtual void Reconnect(void* factory, const char* pInterfaceName) = 0; + + // Returns whether or not the app system is a singleton + virtual bool IsSingleton() = 0; + + virtual BuildType_t GetBuildType() = 0; +}; \ No newline at end of file diff --git a/csgo2/sdk/public/eiface.h b/csgo2/sdk/public/eiface.h new file mode 100644 index 0000000..c41f18e --- /dev/null +++ b/csgo2/sdk/public/eiface.h @@ -0,0 +1,119 @@ +#pragma once +#include "../sdk.h" +#include "IAppSystem.h" +#include "../tier1/bufferstring.h" +#include "../convar/convar.hpp" +struct vis_info_t; +class IHLTVServer; +class IHLTVDirector; +class CSteamID; + +struct CEntityIndex +{ + CEntityIndex(int index) + { + _index = index; + } + + int Get() const + { + return _index; + } + + int _index; + + bool operator==(const CEntityIndex& other) const { return other._index == _index; } + bool operator!=(const CEntityIndex& other) const { return other._index != _index; } +}; +//----------------------------------------------------------------------------- +// Purpose: Player / Client related functions +//----------------------------------------------------------------------------- +class ISource2GameClients : public IAppSystem +{ +public: + virtual void OnClientConnected(CPlayerSlot slot, const char* pszName, uint64_t xuid, const char* pszNetworkID, const char* pszAddress, bool bFakePlayer) = 0; + + // Called when the client attempts to connect (doesn't get called for bots) + // returning false would reject the connection with the pRejectReason message + virtual bool ClientConnect(CPlayerSlot slot, const char* pszName, uint64_t xuid, const char* pszNetworkID, bool unk1, CBufferString* pRejectReason); + + // Client is connected and should be put in the game + // type values could be: + // 0 - player + // 1 - fake player (bot) + // 2 - unknown + virtual void ClientPutInServer(CPlayerSlot slot, char const* pszName, int type, uint64_t xuid) = 0; + + // Client is going active + // If bLoadGame is true, don't spawn the player because its state is already setup. + virtual void ClientActive(CPlayerSlot slot, bool bLoadGame, const char* pszName, uint64_t xuid) = 0; + + virtual void ClientFullyConnect(CPlayerSlot slot) = 0; + + // Client is disconnecting from server + virtual void ClientDisconnect(CPlayerSlot slot, /* ENetworkDisconnectionReason */ int reason, + const char* pszName, uint64_t xuid, const char* pszNetworkID) = 0; + + // Sets the client index for the client who typed the command into his/her console + // virtual void SetCommandClient( CPlayerSlot slot) = 0; + + // The client has typed a command at the console + virtual void ClientCommand(CPlayerSlot slot, const CCommand& args) = 0; + + // A player changed one/several replicated cvars (name etc) + virtual void ClientSettingsChanged(CPlayerSlot slot) = 0; + + // Determine PVS origin and set PVS for the player/viewentity + virtual void ClientSetupVisibility(CPlayerSlot slot, vis_info_t* visinfo) = 0; + + // A block of CUserCmds has arrived from the user, decode them and buffer for execution during player simulation + virtual float ProcessUsercmds(CPlayerSlot slot, void* buf, int numcmds, bool ignore, bool paused) = 0; + + virtual bool IsPlayerSlotOccupied(CPlayerSlot slot) = 0; + + virtual bool IsPlayerAlive(CPlayerSlot slot) = 0; + + virtual int GetPlayerScore(CPlayerSlot slot) = 0; + + // Get the ear position for a specified client + virtual void ClientEarPosition(CPlayerSlot slot, void* pEarOrigin) = 0; + + // Anything this game .dll wants to add to the bug reporter text (e.g., the entity/model under the picker crosshair) + // can be added here + virtual void GetBugReportInfo(CBufferString& buf) = 0; + + // TERROR: A player sent a voice packet + virtual void ClientVoice(CPlayerSlot slot) = 0; + + // A user has had their network id setup and validated + virtual void NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) = 0; + + // The client has submitted a keyvalues command + virtual void ClientCommandKeyValues(CPlayerSlot slot, void* pKeyValues) = 0; + + virtual bool ClientCanPause(CPlayerSlot slot) = 0; + + virtual void HLTVClientFullyConnect(int index, const CSteamID& steamID) = 0; + + virtual bool CanHLTVClientConnect(int index, const CSteamID& steamID, int* pRejectReason) = 0; + + virtual void StartHLTVServer(CEntityIndex index) = 0; + + virtual void SendHLTVStatusMessage(IHLTVServer*, bool, bool, const char*, int, int, int) = 0; + + virtual IHLTVDirector* GetHLTVDirector(void) = 0; + + virtual void unk002(CPlayerSlot slot) = 0; + virtual void unk003(CPlayerSlot slot) = 0; + + // Something NetMessage related + virtual void unk004() = 0; + + // Something pawn related + virtual void unk005() = 0; + virtual void unk006() = 0; + + virtual void unk007() = 0; + virtual void unk008() = 0; +}; +typedef ISource2GameClients IServerGameClients; diff --git a/csgo2/sdk/sdk.h b/csgo2/sdk/sdk.h new file mode 100644 index 0000000..759ce50 --- /dev/null +++ b/csgo2/sdk/sdk.h @@ -0,0 +1,21 @@ +#pragma once +#define CORRECT_PATH_SEPARATOR '\\' +#define CORRECT_PATH_SEPARATOR_S "\\" +#define INCORRECT_PATH_SEPARATOR '/' +#define INCORRECT_PATH_SEPARATOR_S "/" +#define FMTFUNCTION( a, b ) +enum EStringConvertErrorPolicy +{ + _STRINGCONVERTFLAG_SKIP = 1, + _STRINGCONVERTFLAG_FAIL = 2, + _STRINGCONVERTFLAG_ASSERT = 4, + + STRINGCONVERT_REPLACE = 0, + STRINGCONVERT_SKIP = _STRINGCONVERTFLAG_SKIP, + STRINGCONVERT_FAIL = _STRINGCONVERTFLAG_FAIL, + + STRINGCONVERT_ASSERT_REPLACE = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_REPLACE, + STRINGCONVERT_ASSERT_SKIP = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_SKIP, + STRINGCONVERT_ASSERT_FAIL = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_FAIL, +}; +#include "../pch.h" \ No newline at end of file diff --git a/csgo2/sdk/tier1/UtlMemory.hpp b/csgo2/sdk/tier1/UtlMemory.hpp new file mode 100644 index 0000000..ccfcd97 --- /dev/null +++ b/csgo2/sdk/tier1/UtlMemory.hpp @@ -0,0 +1,699 @@ +#pragma once + +#include +#define UTLMEMORY_TRACK_ALLOC() +#define MEM_ALLOC_CREDIT_CLASS() +#define UTLMEMORY_TRACK_FREE() +#define assert +template< class T, class I = int > +class CUtlMemory +{ +public: + // constructor, destructor + CUtlMemory(int nGrowSize = 0, int nInitSize = 0); + CUtlMemory(T* pMemory, int numElements); + CUtlMemory(const T* pMemory, int numElements); + ~CUtlMemory(); + + // Set the size by which the memory grows + void Init(int nGrowSize = 0, int nInitSize = 0); + + class Iterator_t + { + public: + Iterator_t(I i) : index(i) {} + I index; + + bool operator==(const Iterator_t it) const { return index == it.index; } + bool operator!=(const Iterator_t it) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); } + Iterator_t Next(const Iterator_t &it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); } + I GetIndex(const Iterator_t &it) const { return it.index; } + bool IsIdxAfter(I i, const Iterator_t &it) const { return i > it.index; } + bool IsValidIterator(const Iterator_t &it) const { return IsIdxValid(it.index); } + Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); } + + // element access + T& operator[](I i); + const T& operator[](I i) const; + T& Element(I i); + const T& Element(I i) const; + + bool IsIdxValid(I i) const; + + static const I INVALID_INDEX = (I)-1; // For use with COMPILE_TIME_ASSERT + static I InvalidIndex() { return INVALID_INDEX; } + + T* Base(); + const T* Base() const; + + void SetExternalBuffer(T* pMemory, int numElements); + void SetExternalBuffer(const T* pMemory, int numElements); + void AssumeMemory(T *pMemory, int nSize); + T* Detach(); + void *DetachMemory(); + + void Swap(CUtlMemory< T, I > &mem); + void ConvertToGrowableMemory(int nGrowSize); + int NumAllocated() const; + int Count() const; + void Grow(int num = 1); + void EnsureCapacity(int num); + void Purge(); + void Purge(int numElements); + bool IsExternallyAllocated() const; + bool IsReadOnly() const; + void SetGrowSize(int size); + +protected: + void ValidateGrowSize() + { + + } + + enum + { + EXTERNAL_BUFFER_MARKER = -1, + EXTERNAL_CONST_BUFFER_MARKER = -2, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class I > +CUtlMemory::CUtlMemory(int nGrowSize, int nInitAllocationCount) : m_pMemory(0), +m_nAllocationCount(nInitAllocationCount), m_nGrowSize(nGrowSize) +{ + ValidateGrowSize(); + assert(nGrowSize >= 0); + if(m_nAllocationCount) { + m_pMemory = (T*)new unsigned char[m_nAllocationCount * sizeof(T)]; + //m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +template< class T, class I > +CUtlMemory::CUtlMemory(T* pMemory, int numElements) : m_pMemory(pMemory), +m_nAllocationCount(numElements) +{ + // Special marker indicating externally supplied modifyable memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory::CUtlMemory(const T* pMemory, int numElements) : m_pMemory((T*)pMemory), +m_nAllocationCount(numElements) +{ + // Special marker indicating externally supplied modifyable memory + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory::~CUtlMemory() +{ + Purge(); +} + +template< class T, class I > +void CUtlMemory::Init(int nGrowSize /*= 0*/, int nInitSize /*= 0*/) +{ + Purge(); + + m_nGrowSize = nGrowSize; + m_nAllocationCount = nInitSize; + ValidateGrowSize(); + assert(nGrowSize >= 0); + if(m_nAllocationCount) { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::Swap(CUtlMemory &mem) +{ + V_swap(m_nGrowSize, mem.m_nGrowSize); + V_swap(m_pMemory, mem.m_pMemory); + V_swap(m_nAllocationCount, mem.m_nAllocationCount); +} + + +//----------------------------------------------------------------------------- +// Switches the buffer from an external memory buffer to a reallocatable buffer +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::ConvertToGrowableMemory(int nGrowSize) +{ + if(!IsExternallyAllocated()) + return; + + m_nGrowSize = nGrowSize; + if(m_nAllocationCount) { + int nNumBytes = m_nAllocationCount * sizeof(T); + T *pMemory = (T*)malloc(nNumBytes); + memcpy(pMemory, m_pMemory, nNumBytes); + m_pMemory = pMemory; + } else { + m_pMemory = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::SetExternalBuffer(T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory::SetExternalBuffer(const T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = const_cast(pMemory); + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory::AssumeMemory(T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + // Simply take the pointer but don't mark us as external + m_pMemory = pMemory; + m_nAllocationCount = numElements; +} + +template< class T, class I > +void *CUtlMemory::DetachMemory() +{ + if(IsExternallyAllocated()) + return NULL; + + void *pMemory = m_pMemory; + m_pMemory = 0; + m_nAllocationCount = 0; + return pMemory; +} + +template< class T, class I > +inline T* CUtlMemory::Detach() +{ + return (T*)DetachMemory(); +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T, class I > +inline T& CUtlMemory::operator[](I i) +{ + assert(!IsReadOnly()); + assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T, class I > +inline const T& CUtlMemory::operator[](I i) const +{ + assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T, class I > +inline T& CUtlMemory::Element(I i) +{ + assert(!IsReadOnly()); + assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T, class I > +inline const T& CUtlMemory::Element(I i) const +{ + assert(IsIdxValid(i)); + return m_pMemory[i]; +} + + +//----------------------------------------------------------------------------- +// is the memory externally allocated? +//----------------------------------------------------------------------------- +template< class T, class I > +bool CUtlMemory::IsExternallyAllocated() const +{ + return (m_nGrowSize < 0); +} + + +//----------------------------------------------------------------------------- +// is the memory read only? +//----------------------------------------------------------------------------- +template< class T, class I > +bool CUtlMemory::IsReadOnly() const +{ + return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER); +} + + +template< class T, class I > +void CUtlMemory::SetGrowSize(int nSize) +{ + assert(!IsExternallyAllocated()); + assert(nSize >= 0); + m_nGrowSize = nSize; + ValidateGrowSize(); +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- +template< class T, class I > +inline T* CUtlMemory::Base() +{ + assert(!IsReadOnly()); + return m_pMemory; +} + +template< class T, class I > +inline const T *CUtlMemory::Base() const +{ + return m_pMemory; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T, class I > +inline int CUtlMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + +template< class T, class I > +inline int CUtlMemory::Count() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T, class I > +inline bool CUtlMemory::IsIdxValid(I i) const +{ + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We Get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + return (x >= 0) && (x < m_nAllocationCount); +} + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +inline int UtlMemory_CalcNewAllocationCount(int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem) +{ + if(nGrowSize) { + nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize); + } else { + if(!nAllocationCount) { + // Compute an allocation which is at least as big as a cache line... + nAllocationCount = (31 + nBytesItem) / nBytesItem; + } + + while(nAllocationCount < nNewSize) { +#ifndef _X360 + nAllocationCount *= 2; +#else + int nNewAllocationCount = (nAllocationCount * 9) / 8; // 12.5 % + if(nNewAllocationCount > nAllocationCount) + nAllocationCount = nNewAllocationCount; + else + nAllocationCount *= 2; +#endif + } + } + + return nAllocationCount; +} + +template< class T, class I > +void CUtlMemory::Grow(int num) +{ + assert(num > 0); + + if(IsExternallyAllocated()) { + // Can't grow a buffer whose memory was externally allocated + assert(0); + return; + } + + + auto oldAllocationCount = m_nAllocationCount; + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = m_nAllocationCount + num; + + int nNewAllocationCount = UtlMemory_CalcNewAllocationCount(m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T)); + + // if m_nAllocationRequested wraps index type I, recalculate + if((int)(I)nNewAllocationCount < nAllocationRequested) { + if((int)(I)nNewAllocationCount == 0 && (int)(I)(nNewAllocationCount - 1) >= nAllocationRequested) { + --nNewAllocationCount; // deal w/ the common case of m_nAllocationCount == MAX_USHORT + 1 + } else { + if((int)(I)nAllocationRequested != nAllocationRequested) { + // we've been asked to grow memory to a size s.t. the index type can't address the requested amount of memory + assert(0); + return; + } + while((int)(I)nNewAllocationCount < nAllocationRequested) { + nNewAllocationCount = (nNewAllocationCount + nAllocationRequested) / 2; + } + } + } + + m_nAllocationCount = nNewAllocationCount; + + if(m_pMemory) { + auto ptr = new unsigned char[m_nAllocationCount * sizeof(T)]; + + memcpy(ptr, m_pMemory, oldAllocationCount * sizeof(T)); + m_pMemory = (T*)ptr; + } else { + m_pMemory = (T*)new unsigned char[m_nAllocationCount * sizeof(T)]; + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, class I > +inline void CUtlMemory::EnsureCapacity(int num) +{ + if(m_nAllocationCount >= num) + return; + + if(IsExternallyAllocated()) { + // Can't grow a buffer whose memory was externally allocated + assert(0); + return; + } + m_nAllocationCount = num; + + if(m_pMemory) { + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } else { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory::Purge() +{ + if(!IsExternallyAllocated()) { + if(m_pMemory) { + free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + +template< class T, class I > +void CUtlMemory::Purge(int numElements) +{ + assert(numElements >= 0); + + if(numElements > m_nAllocationCount) { + // Ensure this isn't a grow request in disguise. + assert(numElements <= m_nAllocationCount); + return; + } + + // If we have zero elements, simply do a purge: + if(numElements == 0) { + Purge(); + return; + } + + if(IsExternallyAllocated()) { + // Can't shrink a buffer whose memory was externally allocated, fail silently like purge + return; + } + + // If the number of elements is the same as the allocation count, we are done. + if(numElements == m_nAllocationCount) { + return; + } + + + if(!m_pMemory) { + // Allocation count is non zero, but memory is null. + assert(m_pMemory); + return; + } + m_nAllocationCount = numElements; + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); +} + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +class CUtlMemoryAligned : public CUtlMemory +{ +public: + // constructor, destructor + CUtlMemoryAligned(int nGrowSize = 0, int nInitSize = 0); + CUtlMemoryAligned(T* pMemory, int numElements); + CUtlMemoryAligned(const T* pMemory, int numElements); + ~CUtlMemoryAligned(); + + // Attaches the buffer to external memory.... + void SetExternalBuffer(T* pMemory, int numElements); + void SetExternalBuffer(const T* pMemory, int numElements); + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow(int num = 1); + + // Makes sure we've got at least this much memory + void EnsureCapacity(int num); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryAligned) + void Purge(int numElements) { assert(0); } + +private: + void *Align(const void *pAddr); +}; + + +//----------------------------------------------------------------------------- +// Aligns a pointer +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void *CUtlMemoryAligned::Align(const void *pAddr) +{ + size_t nAlignmentMask = nAlignment - 1; + return (void*)(((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask)); +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned(int nGrowSize, int nInitAllocationCount) +{ + CUtlMemory::m_pMemory = 0; + CUtlMemory::m_nAllocationCount = nInitAllocationCount; + CUtlMemory::m_nGrowSize = nGrowSize; + this->ValidateGrowSize(); + + // Alignment must be a power of two + COMPILE_TIME_ASSERT((nAlignment & (nAlignment - 1)) == 0); + assert((nGrowSize >= 0) && (nGrowSize != CUtlMemory::EXTERNAL_BUFFER_MARKER)); + if(CUtlMemory::m_nAllocationCount) { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)_aligned_malloc(nInitAllocationCount * sizeof(T), nAlignment); + } +} + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned(T* pMemory, int numElements) +{ + // Special marker indicating externally supplied memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned(const T* pMemory, int numElements) +{ + // Special marker indicating externally supplied memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned::~CUtlMemoryAligned() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned::SetExternalBuffer(T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); + + // Indicate that we don't own the memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; +} + +template< class T, int nAlignment > +void CUtlMemoryAligned::SetExternalBuffer(const T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); + + // Indicate that we don't own the memory + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; +} + + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned::Grow(int num) +{ + assert(num > 0); + + if(this->IsExternallyAllocated()) { + // Can't grow a buffer whose memory was externally allocated + assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = CUtlMemory::m_nAllocationCount + num; + + CUtlMemory::m_nAllocationCount = UtlMemory_CalcNewAllocationCount(CUtlMemory::m_nAllocationCount, CUtlMemory::m_nGrowSize, nAllocationRequested, sizeof(T)); + + UTLMEMORY_TRACK_ALLOC(); + + if(CUtlMemory::m_pMemory) { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_ReallocAligned(CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + assert(CUtlMemory::m_pMemory); + } else { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_AllocAligned(CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + assert(CUtlMemory::m_pMemory); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +inline void CUtlMemoryAligned::EnsureCapacity(int num) +{ + if(CUtlMemory::m_nAllocationCount >= num) + return; + + if(this->IsExternallyAllocated()) { + // Can't grow a buffer whose memory was externally allocated + assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + CUtlMemory::m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if(CUtlMemory::m_pMemory) { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_ReallocAligned(CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + } else { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_AllocAligned(CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned::Purge() +{ + if(!this->IsExternallyAllocated()) { + if(CUtlMemory::m_pMemory) { + UTLMEMORY_TRACK_FREE(); + MemAlloc_FreeAligned(CUtlMemory::m_pMemory); + CUtlMemory::m_pMemory = 0; + } + CUtlMemory::m_nAllocationCount = 0; + } +} \ No newline at end of file diff --git a/csgo2/sdk/tier1/UtlString.cpp b/csgo2/sdk/tier1/UtlString.cpp new file mode 100644 index 0000000..f2671ca --- /dev/null +++ b/csgo2/sdk/tier1/UtlString.cpp @@ -0,0 +1,309 @@ +#include "UtlString.hpp" + +#define NOMINMAX +#include +#include + +//----------------------------------------------------------------------------- +// Base class, containing simple memory management +//----------------------------------------------------------------------------- +CUtlBinaryBlock::CUtlBinaryBlock(int growSize, int initSize) : m_Memory(growSize, initSize) +{ + m_nActualLength = 0; +} + +CUtlBinaryBlock::CUtlBinaryBlock(void* pMemory, int nSizeInBytes, int nInitialLength) : m_Memory((unsigned char*)pMemory, nSizeInBytes) +{ + m_nActualLength = nInitialLength; +} + +CUtlBinaryBlock::CUtlBinaryBlock(const void* pMemory, int nSizeInBytes) : m_Memory((const unsigned char*)pMemory, nSizeInBytes) +{ + m_nActualLength = nSizeInBytes; +} + +CUtlBinaryBlock::CUtlBinaryBlock(const CUtlBinaryBlock& src) +{ + Set(src.Get(), src.Length()); +} + +void CUtlBinaryBlock::Get(void *pValue, int nLen) const +{ + assert(nLen > 0); + if(m_nActualLength < nLen) { + nLen = m_nActualLength; + } + + if(nLen > 0) { + memcpy(pValue, m_Memory.Base(), nLen); + } +} + +void CUtlBinaryBlock::SetLength(int nLength) +{ + assert(!m_Memory.IsReadOnly()); + + m_nActualLength = nLength; + if(nLength > m_Memory.NumAllocated()) { + int nOverFlow = nLength - m_Memory.NumAllocated(); + m_Memory.Grow(nOverFlow); + + // If the reallocation failed, clamp length + if(nLength > m_Memory.NumAllocated()) { + m_nActualLength = m_Memory.NumAllocated(); + } + } + +#ifdef _DEBUG + if(m_Memory.NumAllocated() > m_nActualLength) { + memset(((char *)m_Memory.Base()) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength); + } +#endif +} + +void CUtlBinaryBlock::Set(const void *pValue, int nLen) +{ + assert(!m_Memory.IsReadOnly()); + + if(!pValue) { + nLen = 0; + } + + SetLength(nLen); + + if(m_nActualLength) { + if(((const char *)m_Memory.Base()) >= ((const char *)pValue) + nLen || + ((const char *)m_Memory.Base()) + m_nActualLength <= ((const char *)pValue)) { + memcpy(m_Memory.Base(), pValue, m_nActualLength); + } else { + memmove(m_Memory.Base(), pValue, m_nActualLength); + } + } +} + + +CUtlBinaryBlock &CUtlBinaryBlock::operator=(const CUtlBinaryBlock &src) +{ + assert(!m_Memory.IsReadOnly()); + Set(src.Get(), src.Length()); + return *this; +} + + +bool CUtlBinaryBlock::operator==(const CUtlBinaryBlock &src) const +{ + if(src.Length() != Length()) + return false; + + return !memcmp(src.Get(), Get(), Length()); +} + + +//----------------------------------------------------------------------------- +// Simple string class. +//----------------------------------------------------------------------------- +CUtlString::CUtlString() +{ +} + +CUtlString::CUtlString(const char *pString) +{ + Set(pString); +} + +CUtlString::CUtlString(const CUtlString& string) +{ + Set(string.Get()); +} + +// Attaches the string to external memory. Useful for avoiding a copy +CUtlString::CUtlString(void* pMemory, int nSizeInBytes, int nInitialLength) : m_Storage(pMemory, nSizeInBytes, nInitialLength) +{ +} + +CUtlString::CUtlString(const void* pMemory, int nSizeInBytes) : m_Storage(pMemory, nSizeInBytes) +{ +} + +void CUtlString::Set(const char *pValue) +{ + assert(!m_Storage.IsReadOnly()); + int nLen = pValue ? strlen(pValue) + 1 : 0; + m_Storage.Set(pValue, nLen); +} + +// Returns strlen +int CUtlString::Length() const +{ + return m_Storage.Length() ? m_Storage.Length() - 1 : 0; +} + +// Sets the length (used to serialize into the buffer ) +void CUtlString::SetLength(int nLen) +{ + assert(!m_Storage.IsReadOnly()); + + // Add 1 to account for the NULL + m_Storage.SetLength(nLen > 0 ? nLen + 1 : 0); +} + +const char *CUtlString::Get() const +{ + if(m_Storage.Length() == 0) { + return ""; + } + + return reinterpret_cast(m_Storage.Get()); +} + +// Converts to c-strings +CUtlString::operator const char*() const +{ + return Get(); +} + +char *CUtlString::Get() +{ + assert(!m_Storage.IsReadOnly()); + + if(m_Storage.Length() == 0) { + // In general, we optimise away small mallocs for empty strings + // but if you ask for the non-const bytes, they must be writable + // so we can't return "" here, like we do for the const version - jd + m_Storage.SetLength(1); + m_Storage[0] = '\0'; + } + + return reinterpret_cast(m_Storage.Get()); +} + +CUtlString &CUtlString::operator=(const CUtlString &src) +{ + assert(!m_Storage.IsReadOnly()); + m_Storage = src.m_Storage; + return *this; +} + +CUtlString &CUtlString::operator=(const char *src) +{ + assert(!m_Storage.IsReadOnly()); + Set(src); + return *this; +} + +bool CUtlString::operator==(const CUtlString &src) const +{ + return m_Storage == src.m_Storage; +} + +bool CUtlString::operator==(const char *src) const +{ + return (strcmp(Get(), src) == 0); +} + +CUtlString &CUtlString::operator+=(const CUtlString &rhs) +{ + assert(!m_Storage.IsReadOnly()); + + const int lhsLength(Length()); + const int rhsLength(rhs.Length()); + const int requestedLength(lhsLength + rhsLength); + + SetLength(requestedLength); + const int allocatedLength(Length()); + const int copyLength(allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength); + memcpy(Get() + lhsLength, rhs.Get(), copyLength); + m_Storage[allocatedLength] = '\0'; + + return *this; +} + +CUtlString &CUtlString::operator+=(const char *rhs) +{ + assert(!m_Storage.IsReadOnly()); + + const int lhsLength(Length()); + const int rhsLength(strlen(rhs)); + const int requestedLength(lhsLength + rhsLength); + + SetLength(requestedLength); + const int allocatedLength(Length()); + const int copyLength(allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength); + memcpy(Get() + lhsLength, rhs, copyLength); + m_Storage[allocatedLength] = '\0'; + + return *this; +} + +CUtlString &CUtlString::operator+=(char c) +{ + assert(!m_Storage.IsReadOnly()); + + int nLength = Length(); + SetLength(nLength + 1); + m_Storage[nLength] = c; + m_Storage[nLength + 1] = '\0'; + return *this; +} + +CUtlString &CUtlString::operator+=(int rhs) +{ + assert(!m_Storage.IsReadOnly()); + assert(sizeof(rhs) == 4); + + char tmpBuf[12]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ] + snprintf(tmpBuf, sizeof(tmpBuf), "%d", rhs); + tmpBuf[sizeof(tmpBuf) - 1] = '\0'; + + return operator+=(tmpBuf); +} + +CUtlString &CUtlString::operator+=(double rhs) +{ + assert(!m_Storage.IsReadOnly()); + + char tmpBuf[256]; // How big can doubles be??? Dunno. + snprintf(tmpBuf, sizeof(tmpBuf), "%lg", rhs); + tmpBuf[sizeof(tmpBuf) - 1] = '\0'; + + return operator+=(tmpBuf); +} + +int CUtlString::Format(const char *pFormat, ...) +{ + assert(!m_Storage.IsReadOnly()); + + char tmpBuf[4096]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer + + va_list marker; + + va_start(marker, pFormat); + int len = _vsnprintf_s(tmpBuf, 4096, sizeof(tmpBuf) - 1, pFormat, marker); + va_end(marker); + + // Len < 0 represents an overflow + if(len < 0) { + len = sizeof(tmpBuf) - 1; + tmpBuf[sizeof(tmpBuf) - 1] = 0; + } + + Set(tmpBuf); + + return len; +} + +//----------------------------------------------------------------------------- +// Strips the trailing slash +//----------------------------------------------------------------------------- +void CUtlString::StripTrailingSlash() +{ + if(IsEmpty()) + return; + + int nLastChar = Length() - 1; + char c = m_Storage[nLastChar]; + if(c == '\\' || c == '/') { + m_Storage[nLastChar] = 0; + m_Storage.SetLength(m_Storage.Length() - 1); + } +} \ No newline at end of file diff --git a/csgo2/sdk/tier1/UtlString.hpp b/csgo2/sdk/tier1/UtlString.hpp new file mode 100644 index 0000000..cc34b0e --- /dev/null +++ b/csgo2/sdk/tier1/UtlString.hpp @@ -0,0 +1,204 @@ +#pragma once + +#include +#include + +#include "UtlMemory.hpp" + +class CUtlBinaryBlock +{ +public: + CUtlBinaryBlock(int growSize = 0, int initSize = 0); + + // NOTE: nInitialLength indicates how much of the buffer starts full + CUtlBinaryBlock(void* pMemory, int nSizeInBytes, int nInitialLength); + CUtlBinaryBlock(const void* pMemory, int nSizeInBytes); + CUtlBinaryBlock(const CUtlBinaryBlock& src); + + void Get(void *pValue, int nMaxLen) const; + void Set(const void *pValue, int nLen); + const void *Get() const; + void *Get(); + + unsigned char& operator[](int i); + const unsigned char& operator[](int i) const; + + int Length() const; + void SetLength(int nLength); // Undefined memory will result + bool IsEmpty() const; + void Clear(); + void Purge(); + + bool IsReadOnly() const; + + CUtlBinaryBlock &operator=(const CUtlBinaryBlock &src); + + // Test for equality + bool operator==(const CUtlBinaryBlock &src) const; + +private: + CUtlMemory m_Memory; + int m_nActualLength; +}; + + +//----------------------------------------------------------------------------- +// class inlines +//----------------------------------------------------------------------------- +inline const void *CUtlBinaryBlock::Get() const +{ + return m_Memory.Base(); +} + +inline void *CUtlBinaryBlock::Get() +{ + return m_Memory.Base(); +} + +inline int CUtlBinaryBlock::Length() const +{ + return m_nActualLength; +} + +inline unsigned char& CUtlBinaryBlock::operator[](int i) +{ + return m_Memory[i]; +} + +inline const unsigned char& CUtlBinaryBlock::operator[](int i) const +{ + return m_Memory[i]; +} + +inline bool CUtlBinaryBlock::IsReadOnly() const +{ + return m_Memory.IsReadOnly(); +} + +inline bool CUtlBinaryBlock::IsEmpty() const +{ + return Length() == 0; +} + +inline void CUtlBinaryBlock::Clear() +{ + SetLength(0); +} + +inline void CUtlBinaryBlock::Purge() +{ + SetLength(0); + m_Memory.Purge(); +} + +//----------------------------------------------------------------------------- +// Simple string class. +// NOTE: This is *not* optimal! Use in tools, but not runtime code +//----------------------------------------------------------------------------- +class CUtlString +{ +public: + CUtlString(); + CUtlString(const char *pString); + CUtlString(const CUtlString& string); + + // Attaches the string to external memory. Useful for avoiding a copy + CUtlString(void* pMemory, int nSizeInBytes, int nInitialLength); + CUtlString(const void* pMemory, int nSizeInBytes); + + const char *Get() const; + void Set(const char *pValue); + + // Set directly and don't look for a null terminator in pValue. + void SetDirect(const char *pValue, int nChars); + + // Converts to c-strings + operator const char*() const; + + // for compatibility switching items from UtlSymbol + const char *String() const { return Get(); } + + // Returns strlen + int Length() const; + bool IsEmpty() const; + + // Sets the length (used to serialize into the buffer ) + // Note: If nLen != 0, then this adds an extra uint8_t for a null-terminator. + void SetLength(int nLen); + char *Get(); + void Clear(); + void Purge(); + + // Strips the trailing slash + void StripTrailingSlash(); + + CUtlString &operator=(const CUtlString &src); + CUtlString &operator=(const char *src); + + // Test for equality + bool operator==(const CUtlString &src) const; + bool operator==(const char *src) const; + bool operator!=(const CUtlString &src) const { return !operator==(src); } + bool operator!=(const char *src) const { return !operator==(src); } + + CUtlString &operator+=(const CUtlString &rhs); + CUtlString &operator+=(const char *rhs); + CUtlString &operator+=(char c); + CUtlString &operator+=(int rhs); + CUtlString &operator+=(double rhs); + + CUtlString operator+(const char *pOther); + CUtlString operator+(int rhs); + + int Format(const char *pFormat, ...); + + // Take a piece out of the string. + // If you only specify nStart, it'll go from nStart to the end. + // You can use negative numbers and it'll wrap around to the start. + CUtlString Slice(int32_t nStart = 0, int32_t nEnd = INT32_MAX); + + // Grab a substring starting from the left or the right side. + CUtlString Left(int32_t nChars); + CUtlString Right(int32_t nChars); + + // Replace all instances of one character with another. + CUtlString Replace(char cFrom, char cTo); + + // Calls right through to V_MakeAbsolutePath. + CUtlString AbsPath(const char *pStartingDir = NULL); + + // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt). + CUtlString UnqualifiedFilename(); + + // Strips off one directory. Uses V_StripLastDir but strips the last slash also! + CUtlString DirName(); + + // Works like V_ComposeFileName. + static CUtlString PathJoin(const char *pStr1, const char *pStr2); + + // These can be used for utlvector sorts. + static int __cdecl SortCaseInsensitive(const CUtlString *pString1, const CUtlString *pString2); + static int __cdecl SortCaseSensitive(const CUtlString *pString1, const CUtlString *pString2); + +private: + CUtlBinaryBlock m_Storage; +}; + + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline bool CUtlString::IsEmpty() const +{ + return Length() == 0; +} + +inline int __cdecl CUtlString::SortCaseInsensitive(const CUtlString *pString1, const CUtlString *pString2) +{ + return _stricmp(pString1->String(), pString2->String()); +} + +inline int __cdecl CUtlString::SortCaseSensitive(const CUtlString *pString1, const CUtlString *pString2) +{ + return strcmp(pString1->String(), pString2->String()); +} diff --git a/csgo2/sdk/tier1/UtlVector.hpp b/csgo2/sdk/tier1/UtlVector.hpp new file mode 100644 index 0000000..c3552c0 --- /dev/null +++ b/csgo2/sdk/tier1/UtlVector.hpp @@ -0,0 +1,766 @@ +#pragma once + +#include +#include "UtlMemory.hpp" +template +inline T* CopyConstruct(T* pMemory, T const& src) +{ + return ::new(pMemory) T(src); +} + +template< class T, class A = CUtlMemory > +class CUtlVector +{ + typedef T *iterator; + typedef const T *const_iterator; + typedef A CAllocator; +public: + typedef T ElemType_t; + + // constructor, destructor + CUtlVector(int growSize = 0, int initSize = 0); + CUtlVector(T* pMemory, int allocationCount, int numElements = 0); + ~CUtlVector(); + + // Copy the array. + CUtlVector& operator=(const CUtlVector &other); + + // element access + T& operator[](int i); + const T& operator[](int i) const; + T& Element(int i); + const T& Element(int i) const; + T& Head(); + const T& Head() const; + T& Tail(); + const T& Tail() const; + + // Gets the base address (can change when adding elements!) + T* Base() { return m_Memory.Base(); } + const T* Base() const { return m_Memory.Base(); } + // Returns the number of elements in the vector + int Count() const; + // Is element index valid? + bool IsValidIndex(int i) const; + static int InvalidIndex(); + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + int InsertBefore(int elem); + int InsertAfter(int elem); + // Adds an element, uses copy constructor + int AddToHead(const T& src); + int AddToTail(const T& src); + int InsertBefore(int elem, const T& src); + int InsertAfter(int elem, const T& src); + // Adds multiple elements, uses default constructor + int AddMultipleToHead(int num); + int AddMultipleToTail(int num); + int AddMultipleToTail(int num, const T *pToCopy); + int InsertMultipleBefore(int elem, int num); + int InsertMultipleBefore(int elem, int num, const T *pToCopy); + int InsertMultipleAfter(int elem, int num); + // Calls RemoveAll() then AddMultipleToTail. + void SetSize(int size); + void SetCount(int count); + void SetCountNonDestructively(int count); //sets count by adding or removing elements to tail TODO: This should probably be the default behavior for SetCount + void CopyArray(const T *pArray, int size); //Calls SetSize and copies each element. + // Fast swap + void Swap(CUtlVector< T, A > &vec); + // Add the specified array to the tail. + int AddVectorToTail(CUtlVector const &src); + // Finds an element (element needs operator== defined) + int GetOffset(const T& src) const; + void FillWithValue(const T& src); + bool HasElement(const T& src) const; + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity(int num); + // Makes sure we have at least this many elements + void EnsureCount(int num); + // Element removal + void FastRemove(int elem); // doesn't preserve order + void Remove(int elem); // preserves order, shifts elements + bool FindAndRemove(const T& src); // removes first occurrence of src, preserves order, shifts elements + bool FindAndFastRemove(const T& src); // removes first occurrence of src, doesn't preserve order + void RemoveMultiple(int elem, int num); // preserves order, shifts elements + void RemoveMultipleFromHead(int num); // removes num elements from tail + void RemoveMultipleFromTail(int num); // removes num elements from tail + void RemoveAll(); // doesn't deallocate memory + void Purge(); // Memory deallocation + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + // Compacts the vector to the number of elements actually in use + void Compact(); + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize(int size) { m_Memory.SetGrowSize(size); } + int NumAllocated() const; // Only use this if you really know what you're doing! + void Sort(int(__cdecl *pfnCompare)(const T *, const T *)); + + iterator begin() { return Base(); } + const_iterator begin() const { return Base(); } + iterator end() { return Base() + Count(); } + const_iterator end() const { return Base() + Count(); } + +protected: + // Can't copy this unless we explicitly do it! + CUtlVector(CUtlVector const& vec) { assert(0); } + + // Grows the vector + void GrowVector(int num = 1); + + // Shifts elements.... + void ShiftElementsRight(int elem, int num = 1); + void ShiftElementsLeft(int elem, int num = 1); + +public: + CAllocator m_Memory; + int m_Size; + + // For easier access to the elements through the debugger + // it's in release builds so this can be used in libraries correctly + T *m_pElements; + + inline void ResetDbgInfo() + { + m_pElements = Base(); + } +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline CUtlVector::CUtlVector(int growSize, int initSize) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector::CUtlVector(T* pMemory, int allocationCount, int numElements) : + m_Memory(pMemory, allocationCount), m_Size(numElements) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector::~CUtlVector() +{ + Purge(); +} + +template< typename T, class A > +inline CUtlVector& CUtlVector::operator=(const CUtlVector &other) +{ + int nCount = other.Count(); + SetSize(nCount); + for(int i = 0; i < nCount; i++) { + (*this)[i] = other[i]; + } + return *this; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< typename T, class A > +inline T& CUtlVector::operator[](int i) +{ + assert(i < m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline const T& CUtlVector::operator[](int i) const +{ + assert(i < m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline T& CUtlVector::Element(int i) +{ + assert(i < m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline const T& CUtlVector::Element(int i) const +{ + assert(i < m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline T& CUtlVector::Head() +{ + assert(m_Size > 0); + return m_Memory[0]; +} + +template< typename T, class A > +inline const T& CUtlVector::Head() const +{ + assert(m_Size > 0); + return m_Memory[0]; +} + +template< typename T, class A > +inline T& CUtlVector::Tail() +{ + assert(m_Size > 0); + return m_Memory[m_Size - 1]; +} + +template< typename T, class A > +inline const T& CUtlVector::Tail() const +{ + assert(m_Size > 0); + return m_Memory[m_Size - 1]; +} + + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< typename T, class A > +inline bool CUtlVector::IsValidIndex(int i) const +{ + return (i >= 0) && (i < m_Size); +} + + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::InvalidIndex() +{ + return -1; +} + + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::GrowVector(int num) +{ + if(m_Size + num > m_Memory.NumAllocated()) { + m_Memory.Grow(m_Size + num - m_Memory.NumAllocated()); + } + + m_Size += num; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Sorts the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::Sort(int(__cdecl *pfnCompare)(const T *, const T *)) +{ + typedef int(__cdecl *QSortCompareFunc_t)(const void *, const void *); + if(Count() <= 1) + return; + + if(Base()) { + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); + } else { + assert(0); + // this path is untested + // if you want to sort vectors that use a non-sequential memory allocator, + // you'll probably want to patch in a quicksort algorithm here + // I just threw in this bubble sort to have something just in case... + + for(int i = m_Size - 1; i >= 0; --i) { + for(int j = 1; j <= i; ++j) { + if(pfnCompare(&Element(j - 1), &Element(j)) < 0) { + V_swap(Element(j - 1), Element(j)); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::EnsureCapacity(int num) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::EnsureCount(int num) +{ + if(Count() < num) { + AddMultipleToTail(num - Count()); + } +} + + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::ShiftElementsRight(int elem, int num) +{ + assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if((numToMove > 0) && (num > 0)) + memmove(&Element(elem + num), &Element(elem), numToMove * sizeof(T)); +} + +template< typename T, class A > +void CUtlVector::ShiftElementsLeft(int elem, int num) +{ + assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if((numToMove > 0) && (num > 0)) { + memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T)); + +#ifdef _DEBUG + memset(&Element(m_Size - num), 0xDD, num * sizeof(T)); +#endif + } +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::AddToHead() +{ + return InsertBefore(0); +} + +template< typename T, class A > +inline int CUtlVector::AddToTail() +{ + return InsertBefore(m_Size); +} + +template< typename T, class A > +inline int CUtlVector::InsertAfter(int elem) +{ + return InsertBefore(elem + 1); +} + +template< typename T, class A > +int CUtlVector::InsertBefore(int elem) +{ + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + Construct(&Element(elem)); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::AddToHead(const T& src) +{ + // Can't insert something that's in the list... reallocation may hose us + assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(0, src); +} + +template< typename T, class A > +inline int CUtlVector::AddToTail(const T& src) +{ + // Can't insert something that's in the list... reallocation may hose us + assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(m_Size, src); +} + +template< typename T, class A > +inline int CUtlVector::InsertAfter(int elem, const T& src) +{ + // Can't insert something that's in the list... reallocation may hose us + assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(elem + 1, src); +} + +template< typename T, class A > +int CUtlVector::InsertBefore(int elem, const T& src) +{ + // Can't insert something that's in the list... reallocation may hose us + assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct(&Element(elem), src); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds multiple elements, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector::AddMultipleToHead(int num) +{ + return InsertMultipleBefore(0, num); +} + +template< typename T, class A > +inline int CUtlVector::AddMultipleToTail(int num) +{ + return InsertMultipleBefore(m_Size, num); +} + +template< typename T, class A > +inline int CUtlVector::AddMultipleToTail(int num, const T *pToCopy) +{ + // Can't insert something that's in the list... reallocation may hose us + assert((Base() == NULL) || !pToCopy || (pToCopy + num <= Base()) || (pToCopy >= (Base() + Count()))); + + return InsertMultipleBefore(m_Size, num, pToCopy); +} + +template< typename T, class A > +int CUtlVector::InsertMultipleAfter(int elem, int num) +{ + return InsertMultipleBefore(elem + 1, num); +} + + +template< typename T, class A > +void CUtlVector::SetCount(int count) +{ + RemoveAll(); + AddMultipleToTail(count); +} + +template< typename T, class A > +inline void CUtlVector::SetSize(int size) +{ + SetCount(size); +} + +template< typename T, class A > +void CUtlVector::SetCountNonDestructively(int count) +{ + int delta = count - m_Size; + if(delta > 0) AddMultipleToTail(delta); + else if(delta < 0) RemoveMultipleFromTail(-delta); +} + +template< typename T, class A > +void CUtlVector::CopyArray(const T *pArray, int size) +{ + // Can't insert something that's in the list... reallocation may hose us + assert((Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()))); + + SetSize(size); + for(int i = 0; i < size; i++) { + (*this)[i] = pArray[i]; + } +} + +template< typename T, class A > +void CUtlVector::Swap(CUtlVector< T, A > &vec) +{ + m_Memory.Swap(vec.m_Memory); + V_swap(m_Size, vec.m_Size); +#ifndef _X360 + V_swap(m_pElements, vec.m_pElements); +#endif +} + +template< typename T, class A > +int CUtlVector::AddVectorToTail(CUtlVector const &src) +{ + assert(&src != this); + + int base = Count(); + + // Make space. + int nSrcCount = src.Count(); + EnsureCapacity(base + nSrcCount); + + // Copy the elements. + m_Size += nSrcCount; + for(int i = 0; i < nSrcCount; i++) { + CopyConstruct(&Element(base + i), src[i]); + } + return base; +} + +template< typename T, class A > +inline int CUtlVector::InsertMultipleBefore(int elem, int num) +{ + if(num == 0) + return elem; + + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(num); + ShiftElementsRight(elem, num); + + // Invoke default constructors + for(int i = 0; i < num; ++i) { + Construct(&Element(elem + i)); + } + + return elem; +} + +template< typename T, class A > +inline int CUtlVector::InsertMultipleBefore(int elem, int num, const T *pToInsert) +{ + if(num == 0) + return elem; + + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(num); + ShiftElementsRight(elem, num); + + // Invoke default constructors + if(!pToInsert) { + for(int i = 0; i < num; ++i) { + Construct(&Element(elem + i)); + } + } else { + for(int i = 0; i < num; i++) { + CopyConstruct(&Element(elem + i), pToInsert[i]); + } + } + + return elem; +} + + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< typename T, class A > +int CUtlVector::GetOffset(const T& src) const +{ + for(int i = 0; i < Count(); ++i) { + if(Element(i) == src) + return i; + } + return -1; +} + +template< typename T, class A > +void CUtlVector::FillWithValue(const T& src) +{ + for(int i = 0; i < Count(); i++) { + Element(i) = src; + } +} + +template< typename T, class A > +bool CUtlVector::HasElement(const T& src) const +{ + return (GetOffset(src) >= 0); +} + + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector::FastRemove(int elem) +{ + assert(IsValidIndex(elem)); + + Destruct(&Element(elem)); + if(m_Size > 0) { + if(elem != m_Size - 1) + memcpy(&Element(elem), &Element(m_Size - 1), sizeof(T)); + --m_Size; + } +} + +template< typename T, class A > +void CUtlVector::Remove(int elem) +{ + Destruct(&Element(elem)); + ShiftElementsLeft(elem); + --m_Size; +} + +template< typename T, class A > +bool CUtlVector::FindAndRemove(const T& src) +{ + int elem = GetOffset(src); + if(elem != -1) { + Remove(elem); + return true; + } + return false; +} + +template< typename T, class A > +bool CUtlVector::FindAndFastRemove(const T& src) +{ + int elem = GetOffset(src); + if(elem != -1) { + FastRemove(elem); + return true; + } + return false; +} + +template< typename T, class A > +void CUtlVector::RemoveMultiple(int elem, int num) +{ + assert(elem >= 0); + assert(elem + num <= Count()); + + for(int i = elem + num; --i >= elem; ) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveMultipleFromHead(int num) +{ + assert(num <= Count()); + + for(int i = num; --i >= 0; ) + Destruct(&Element(i)); + + ShiftElementsLeft(0, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveMultipleFromTail(int num) +{ + assert(num <= Count()); + + for(int i = m_Size - num; i < m_Size; i++) + Destruct(&Element(i)); + + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveAll() +{ + for(int i = m_Size; --i >= 0; ) { + Destruct(&Element(i)); + } + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< typename T, class A > +inline void CUtlVector::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + + +template< typename T, class A > +inline void CUtlVector::PurgeAndDeleteElements() +{ + for(int i = 0; i < m_Size; i++) { + delete Element(i); + } + Purge(); +} + +template< typename T, class A > +inline void CUtlVector::Compact() +{ + m_Memory.Purge(m_Size); +} + +template< typename T, class A > +inline int CUtlVector::NumAllocated() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Data and memory validation +//----------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +template< typename T, class A > +void CUtlVector::Validate(CValidator &validator, char *pchName) +{ + validator.Push(typeid(*this).name(), this, pchName); + + m_Memory.Validate(validator, "m_Memory"); + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE + +// A vector class for storing pointers, so that the elements pointed to by the pointers are deleted +// on exit. +template class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> > +{ +public: + ~CUtlVectorAutoPurge(void) + { + this->PurgeAndDeleteElements(); + } +}; + +// easy string list class with dynamically allocated strings. For use with V_SplitString, etc. +// Frees the dynamic strings in destructor. +class CUtlStringList : public CUtlVectorAutoPurge< char *> +{ +public: + void CopyAndAddToTail(char const *pString) // clone the string and add to the end + { + char *pNewStr = new char[1 + strlen(pString)]; + strcpy_s(pNewStr, 1 + strlen(pString), pString); + AddToTail(pNewStr); + } + + static int __cdecl SortFunc(char * const * sz1, char * const * sz2) + { + return strcmp(*sz1, *sz2); + } + +}; \ No newline at end of file diff --git a/csgo2/sdk/tier1/bufferstring.h b/csgo2/sdk/tier1/bufferstring.h new file mode 100644 index 0000000..9a30101 --- /dev/null +++ b/csgo2/sdk/tier1/bufferstring.h @@ -0,0 +1,272 @@ +#pragma once +#include "../sdk.h" +#define DLL_CLASS_IMPORT __declspec( dllimport ) + +class CFormatStringElement; +class IFormatOutputStream; + +template +class CBufferStringGrowable; + +/* + Main idea of CBufferString is to provide the base class for the CBufferStringGrowable wich implements stack allocation + with the ability to convert to the heap allocation if allowed. + + Example usage of CBufferStringGrowable class: + + * Basic buffer allocation: + ``` + CBufferStringGrowable<256> buff; + buff.Insert(0, "Hello World!"); + printf("Result: %s\n", buff.Get()); + ``` + additionaly the heap allocation of the buffer could be disabled, by providing ``AllowHeapAllocation`` template argument, + by disabling heap allocation, if the buffer capacity is not enough to perform the operation, the app would exit with an Assert; + + * Additional usage: + CBufferString::IsStackAllocated() - could be used to check if the buffer is stack allocated; + CBufferString::IsHeapAllocated() - could be used to check if the buffer is heap allocated; + CBufferString::Get() - would return a pointer to the data, or an empty string if it's not allocated. + + * Additionaly current length of the buffer could be read via CBufferString::GetTotalNumber() + and currently allocated amount of bytes could be read via CBufferString::GetAllocatedNumber() + + * Most, if not all the functions would ensure the buffer capacity and enlarge it when needed, + in case of stack allocated buffers, it would switch to heap allocation instead. +*/ + +class CBufferString +{ +protected: + // You shouldn't be initializing this class, use CBufferStringGrowable instead. + CBufferString() {} + +public: + enum EAllocationOption_t + { + UNK1 = -1, + UNK2 = 0, + UNK3 = (1 << 1), + UNK4 = (1 << 8), + UNK5 = (1 << 9), + ALLOW_HEAP_ALLOCATION = (1 << 31) + }; + + enum EAllocationFlags_t + { + LENGTH_MASK = (1 << 30) - 1, + FLAGS_MASK = ~LENGTH_MASK, + + STACK_ALLOCATION_MARKER = (1 << 30), + HEAP_ALLOCATION_MARKER = (1 << 31) + }; + +public: + DLL_CLASS_IMPORT const char *AppendConcat(int, const char * const *, const int *, bool bIgnoreAlignment = false); + DLL_CLASS_IMPORT const char *AppendConcat(const char *, const char *, ...) FMTFUNCTION(3, 4); + DLL_CLASS_IMPORT const char *AppendConcatV(const char *, const char *, va_list, bool bIgnoreAlignment = false); + DLL_CLASS_IMPORT const char *Concat(const char *, const char *, ...) FMTFUNCTION(3, 4); + + DLL_CLASS_IMPORT int AppendFormat(const char *pFormat, ...) FMTFUNCTION(2, 3); + DLL_CLASS_IMPORT int AppendFormatV(const char *pFormat, va_list pData); + + DLL_CLASS_IMPORT const char *AppendRepeat(char cChar, int nChars, bool bIgnoreAlignment = false); + + DLL_CLASS_IMPORT const char *ComposeFileName(const char *pPath, const char *pFile, char cSeparator); + + DLL_CLASS_IMPORT const char *ConvertIn(unsigned int const *pData, int nSize, bool bIgnoreAlignment = false); + DLL_CLASS_IMPORT const char *ConvertIn(wchar_t const *pData, int nSize, bool bIgnoreAlignment = false); + + DLL_CLASS_IMPORT const char *DefaultExtension(const char *pExt); + + DLL_CLASS_IMPORT bool EndsWith(const char *pMatch) const; + DLL_CLASS_IMPORT bool EndsWith_FastCaseInsensitive(const char *pMatch) const; + + // Ensures the nCapacity condition is met and grows the local buffer if needed. + // Returns pResultingBuffer pointer to the newly allocated data, as well as resulting capacity that was allocated in bytes. + DLL_CLASS_IMPORT int EnsureCapacity(int nCapacity, char **pResultingBuffer, bool bIgnoreAlignment = false, bool bForceGrow = true); + DLL_CLASS_IMPORT int EnsureAddedCapacity(int nCapacity, char **pResultingBuffer, bool bIgnoreAlignment = false, bool bForceGrow = true); + + DLL_CLASS_IMPORT char *EnsureLength(int nCapacity, bool bIgnoreAlignment = false, int *pNewCapacity = NULL); + DLL_CLASS_IMPORT char *EnsureOwnedAllocation(CBufferString::EAllocationOption_t eAlloc); + + DLL_CLASS_IMPORT const char *EnsureTrailingSlash(char cSeparator, bool bDontAppendIfEmpty = true); + + DLL_CLASS_IMPORT const char *ExtendPath(const char *pPath, char cSeparator); + + DLL_CLASS_IMPORT const char *ExtractFileBase(const char *pPath); + DLL_CLASS_IMPORT const char *ExtractFileExtension(const char *pPath); + DLL_CLASS_IMPORT const char *ExtractFilePath(const char *pPath, bool); + DLL_CLASS_IMPORT const char *ExtractFirstDir(const char *pPath); + + DLL_CLASS_IMPORT const char *FixSlashes(char cSeparator = CORRECT_PATH_SEPARATOR); + DLL_CLASS_IMPORT const char *FixupPathName(char cSeparator); + + DLL_CLASS_IMPORT int Format(const char *pFormat, ...) FMTFUNCTION(2, 3); + DLL_CLASS_IMPORT void FormatTo(IFormatOutputStream* pOutputStream, CFormatStringElement pElement) const; + +protected: + // Returns aligned size based on capacity requested + DLL_CLASS_IMPORT static int GetAllocChars(int nSize, int nCapacity); + +public: + // Inserts the nCount bytes of data from pBuf buffer at nIndex position. + // If nCount is -1, it would count the bytes of the input buffer manualy. + // Returns the resulting char buffer (Same as to what CBufferString->Get() returns). + DLL_CLASS_IMPORT const char *Insert(int nIndex, const char *pBuf, int nCount = -1, bool bIgnoreAlignment = false); + + DLL_CLASS_IMPORT char *GetInsertPtr(int nIndex, int nChars, bool bIgnoreAlignment = false, int *pNewCapacity = NULL); + DLL_CLASS_IMPORT char *GetReplacePtr(int nIndex, int nOldChars, int nNewChars, bool bIgnoreAlignment = false, int *pNewCapacity = NULL); + + DLL_CLASS_IMPORT int GrowByChunks(int, int); + + // Wrapper around V_MakeAbsolutePath() + DLL_CLASS_IMPORT const char *MakeAbsolutePath(const char *pPath, const char *pStartingDir); + // Wrapper around V_MakeAbsolutePath() but also does separator fixup + DLL_CLASS_IMPORT const char *MakeFixedAbsolutePath(const char *pPath, const char *pStartingDir, char cSeparator = CORRECT_PATH_SEPARATOR); + // Wrapper around V_MakeRelativePath() + DLL_CLASS_IMPORT const char *MakeRelativePath(const char *pFullPath, const char *pDirectory); + + DLL_CLASS_IMPORT void MoveFrom(CBufferString &pOther); + + DLL_CLASS_IMPORT void Purge(int nLength); + + DLL_CLASS_IMPORT char *Relinquish(CBufferString::EAllocationOption_t eAlloc); + + DLL_CLASS_IMPORT const char *RemoveAt(int nIndex, int nChars); + DLL_CLASS_IMPORT const char *RemoveAtUTF8(int nByteIndex, int nCharacters); + + DLL_CLASS_IMPORT const char *RemoveDotSlashes(char cSeparator); + DLL_CLASS_IMPORT int RemoveWhitespace(); + + DLL_CLASS_IMPORT const char *RemoveFilePath(); + DLL_CLASS_IMPORT const char *RemoveFirstDir(CBufferString *pRemovedDir); + DLL_CLASS_IMPORT const char *RemoveToFileBase(); + + DLL_CLASS_IMPORT bool RemovePartialUTF8Tail(bool); + DLL_CLASS_IMPORT const char *RemoveTailUTF8(int nIndex); + + DLL_CLASS_IMPORT int Replace(char cFrom, char cTo); + DLL_CLASS_IMPORT int Replace(const char *pMatch, const char *pReplace, bool bDontUseStrStr = false); + + DLL_CLASS_IMPORT const char *ReplaceAt(int nIndex, int nOldChars, const char *pData, int nDataLen = -1, bool bIgnoreAlignment = false); + DLL_CLASS_IMPORT const char *ReplaceAt(int nIndex, const char *pData, int nDataLen = -1, bool bIgnoreAlignment = false); + + DLL_CLASS_IMPORT const char *ReverseChars(int nIndex, int nChars); + + // Appends the pExt to the local buffer, also appends '.' in between even if it wasn't provided in pExt. + DLL_CLASS_IMPORT const char *SetExtension(const char *pExt); + + DLL_CLASS_IMPORT char *SetLength(int nLen, bool bIgnoreAlignment = false, int *pNewCapacity = NULL); + DLL_CLASS_IMPORT void SetPtr(char *pBuf, int nBufferChars, int, bool, bool); + + // Frees the buffer (if it was heap allocated) and writes "~DSTRCT" to the local buffer. + DLL_CLASS_IMPORT void SetUnusable(); + + DLL_CLASS_IMPORT const char *ShortenPath(bool); + + DLL_CLASS_IMPORT bool StartsWith(const char *pMatch) const; + DLL_CLASS_IMPORT bool StartsWith_FastCaseInsensitive(const char *pMatch) const; + + DLL_CLASS_IMPORT const char *StrAppendFormat(const char *pFormat, ...) FMTFUNCTION(2, 3); + DLL_CLASS_IMPORT const char *StrFormat(const char *pFormat, ...) FMTFUNCTION(2, 3); + + DLL_CLASS_IMPORT const char *StripExtension(); + DLL_CLASS_IMPORT const char *StripTrailingSlash(); + + DLL_CLASS_IMPORT void ToLowerFast(int nStart); + DLL_CLASS_IMPORT void ToUpperFast(int nStart); + + DLL_CLASS_IMPORT const char *Trim(const char *pTrimChars = "\t\r\n "); + DLL_CLASS_IMPORT const char *TrimHead(const char *pTrimChars = "\t\r\n "); + DLL_CLASS_IMPORT const char *TrimTail(const char *pTrimChars = "\t\r\n "); + + DLL_CLASS_IMPORT const char *TruncateAt(int nIndex, bool bIgnoreAlignment = false); + DLL_CLASS_IMPORT const char *TruncateAt(const char *pStr, bool bIgnoreAlignment = false); + + DLL_CLASS_IMPORT int UnicodeCaseConvert(int, EStringConvertErrorPolicy eErrorPolicy); + + // Casts to CBufferStringGrowable. Very dirty solution until someone figures out the sane one. + template> + T *ToGrowable() + { + return (T *)this; + } +}; + +template +class CBufferStringGrowable : public CBufferString +{ + friend class CBufferString; + +public: + CBufferStringGrowable() : m_nAllocated(STACK_ALLOCATION_MARKER | (MAX_SIZE & LENGTH_MASK)), m_nTotalCount(0), m_Memory() + { + if (AllowHeapAllocation) + { + m_nAllocated |= ALLOW_HEAP_ALLOCATION; + } + } + + ~CBufferStringGrowable() + { + if (IsHeapAllocated() && m_Memory.m_pString) + { +#if PLATFORM_WINDOWS + g_pMemAlloc->Free((void*)m_Memory.m_pString); +#else + delete[] m_Memory.m_pString; +#endif + } + } + + inline int GetAllocatedNumber() const + { + return m_nAllocated & LENGTH_MASK; + } + + inline int GetTotalNumber() const + { + return m_nTotalCount & LENGTH_MASK; + } + + inline bool IsStackAllocated() const + { + return (m_nAllocated & STACK_ALLOCATION_MARKER) != 0; + } + + inline bool IsHeapAllocated() const + { + return (m_nTotalCount & HEAP_ALLOCATION_MARKER) != 0; + } + + inline bool IsInputStringUnsafe(const char *pData) const + { + return ((void *)pData >= this && (void *)pData < &this[1]) || + (GetAllocatedNumber() != 0 && pData >= Get() && pData < (Get() + GetAllocatedNumber())); + } + + inline const char *Get() const + { + if (IsStackAllocated()) + { + return m_Memory.m_szString; + } + else if (GetAllocatedNumber() != 0) + { + return m_Memory.m_pString; + } + + return StringFuncs::EmptyString(); + } + +private: + int m_nTotalCount; + int m_nAllocated; + + union + { + const char *m_pString; + const char m_szString[MAX_SIZE]; + } m_Memory; +}; diff --git a/csgo2/stb.hh b/csgo2/stb.hh new file mode 100644 index 0000000..80d75fd --- /dev/null +++ b/csgo2/stb.hh @@ -0,0 +1,226 @@ +/** + * @file stb.hh + * @author Cristei Gabriel-Marian (cristei.g772@gmail.com) + * @brief Compile-time String To Bytes (STB) + * @version 1.0 + * @date 2023-03-23 + * + * Last update: 03/23/2023 (mm/dd/yyyy): [Breaking update] + * Modernize, undo some cancer, change some naming, file structure, + * implement tests directly in file. + * + */ + +#ifndef STB_DEFINED +#define STB_DEFINED + +#include +#include + +namespace stb { +namespace detail { + // detail methods assume null terminator. + + template + constexpr auto find_first_of_start(std::array const& data, std::size_t start, char ch) noexcept { + std::size_t idx = start; + while (data[idx] != ch && idx < N) + ++idx; + + return idx; + } + + template + constexpr auto find_first_not_of_start(std::array const& data, std::size_t start, char ch) noexcept { + if (start < N && data[start] != ch) + return start; + + std::size_t idx = start; + while (data[idx] == ch && idx < N) + ++idx; + + return idx; + } + + template + constexpr auto find_last_of(std::array const& data, char ch) noexcept { + std::size_t idx = data.size() - 2; + while (data[idx] != ch && idx >= 0) + --idx; + + return idx; + } + + template + constexpr auto find_last_not_of(std::array const& data, char ch) noexcept { + std::size_t idx = data.size() - 2; + while (data[idx] == ch && idx >= 0) + --idx; + + return idx; + } + + constexpr auto char_to_hex(char ch) noexcept { + if (ch >= '0' && ch <= '9') + return ch - '0'; + + if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + + return ch - 'a' + 10; + } + + template + constexpr T concat_hex(T lhs, T rhs) noexcept { + return F * lhs + rhs; + } +} // namespace detail + +template +struct consteval_value { + constexpr static decltype(V) value = V; +}; + +template +struct fixed_string: public std::array { + using std::array::array; + + constexpr fixed_string(const char* str) noexcept + : std::array() { + for (auto i = 0; i != N; ++i) + (*this)[i] = str[i]; + } +}; + +template +fixed_string(const char (&)[N]) noexcept -> fixed_string; + +template +struct basic_hex_string_array_conversion { + template + struct build { + private: + struct parse { + struct result { + std::size_t delimiter_count; + std::size_t start; + std::size_t next; + std::size_t end; + }; + + constexpr static auto get() noexcept { + std::size_t count = 1; + + constexpr std::size_t start = detail::find_first_not_of_start(str, 0, delimiter); + constexpr std::size_t next = detail::find_first_of_start(str, start, delimiter); + constexpr std::size_t end = detail::find_last_not_of(str, delimiter); + + bool previous_delimiter = false; + for (auto i = next; i < end; ++i) { + if (str[i] == delimiter) { + if (!previous_delimiter) + ++count; + + previous_delimiter = true; + } else + previous_delimiter = false; + } + + return result { + count, + start, + next, + end}; + } + }; + + constexpr static auto make() noexcept { + constexpr auto data = parse::get(); + constexpr auto count = data.delimiter_count; + constexpr auto start = data.start; + constexpr auto next = data.next; + constexpr auto end = data.end; + + std::array result = {}; + std::array skips = {}; + std::size_t skipped = 0; + std::size_t traversed = start; + + bool previous_skip = false; + for (auto i = start; i < end; ++i) { + if (str[i] == delimiter) { + if (!previous_skip) + skips[skipped++] = traversed; + + previous_skip = true; + } else + previous_skip = false; + + ++traversed; + } + + bool one_char = str[start + 1] == delimiter; + result[0] = static_cast(str[start] == mask ? masked : (one_char ? detail::char_to_hex(str[start]) : detail::concat_hex(detail::char_to_hex(str[start]), detail::char_to_hex(str[start + 1])))); + + std::size_t conversions = 1; + for (auto i = next; i < end; ++i) { + for (auto entry : skips) { + if (entry == i && entry < end) { + std::size_t idx = detail::find_first_not_of_start(str, i + 1, delimiter); + one_char = str[idx + 1] == delimiter; + result[conversions++] = static_cast(str[idx] == mask ? masked : (one_char ? detail::char_to_hex(str[idx]) : detail::concat_hex(detail::char_to_hex(str[idx]), detail::char_to_hex(str[idx + 1])))); + } + } + } + + return result; + } + + public: + constexpr static auto value = consteval_value::value; + }; +}; + +using hex_string_array_conversion = basic_hex_string_array_conversion<' ', '?', int, -1>; +using simple_conversion = hex_string_array_conversion; +} // namespace stb + +#ifndef STB_OMIT_TESTS +struct _ignore_me_stb_compliance_tests { + using conv_type = stb::simple_conversion; + + constexpr static auto value_1 = conv_type::build<"AA BB CC DD EE FF">::value; + static_assert(value_1[0] == 0xAA); + static_assert(value_1[1] == 0xBB); + static_assert(value_1[2] == 0xCC); + static_assert(value_1[3] == 0xDD); + static_assert(value_1[4] == 0xEE); + static_assert(value_1[5] == 0xFF); + static_assert(value_1.size() == 6); + + constexpr static auto value_2 = conv_type::build<" C 0f C a B ef ">::value; + static_assert(value_2[0] == 0x0C); + static_assert(value_2[1] == 0x0F); + static_assert(value_2[2] == 0x0C); + static_assert(value_2[3] == 0x0A); + static_assert(value_2[4] == 0x0B); + static_assert(value_2[5] == 0xEF); + static_assert(value_2.size() == 6); + + constexpr static auto value_3 = conv_type::build<"AA bb CC dd ">::value; + static_assert(value_3[0] == 0xAA); + static_assert(value_3[1] == 0xBB); + static_assert(value_3[2] == 0xCC); + static_assert(value_3[3] == 0xDD); + static_assert(value_3.size() == 4); + + constexpr static auto value_4 = conv_type::build<" aa bb ee ff">::value; + static_assert(value_4[0] == 0xAA); + static_assert(value_4[1] == 0xBB); + static_assert(value_4[2] == 0xEE); + static_assert(value_4[3] == 0xFF); + static_assert(value_4.size() == 4); +}; +#endif + +#endif diff --git a/csgo2/vmt.cpp b/csgo2/vmt.cpp new file mode 100644 index 0000000..8e77a09 --- /dev/null +++ b/csgo2/vmt.cpp @@ -0,0 +1 @@ +#include "vmt.h" diff --git a/csgo2/vmt.h b/csgo2/vmt.h new file mode 100644 index 0000000..de1ebd7 --- /dev/null +++ b/csgo2/vmt.h @@ -0,0 +1,19 @@ +#pragma once +#include "pch.h" + +#define CALL_VIRTUAL(retType, idx, ...) \ + vmt::CallVirtual(idx, __VA_ARGS__) +namespace vmt { + template + inline T GetVMethod(uint32_t uIndex, void* pClass) { + void** pVTable = *static_cast(pClass); + return reinterpret_cast(pVTable[uIndex]); + } + + template + inline T CallVirtual(uint32_t uIndex, void* pClass, Args... args) { + auto pFunc = GetVMethod(uIndex, pClass); + return pFunc(pClass, args...); + } +} // namespace vmt +