添加项目文件。

This commit is contained in:
Huoji's
2023-10-01 02:28:13 +08:00
parent ee12160e20
commit effb823be9
73 changed files with 7735 additions and 0 deletions

31
csgo2.sln Normal file
View File

@@ -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

1
csgo2/MinHook/.gitkeep Normal file
View File

@@ -0,0 +1 @@

View File

@@ -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 <windows.h>
// 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

View File

@@ -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__)

View File

@@ -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_ */

View File

@@ -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__)

View File

@@ -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_ */

View File

@@ -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 <windows.h>
// 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;

View File

@@ -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
};

View File

@@ -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
};

312
csgo2/MinHook/src/buffer.c Normal file
View File

@@ -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 <windows.h>
#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));
}

View File

@@ -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);

888
csgo2/MinHook/src/hook.c Normal file
View File

@@ -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 <windows.h>
#include <tlhelp32.h>
#include <limits.h>
#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)";
}

View File

@@ -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 <windows.h>
#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;
}

View File

@@ -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);

100
csgo2/VTHook.h Normal file
View File

@@ -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;
};

4
csgo2/cpp.hint Normal file
View File

@@ -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)

234
csgo2/csgo2.vcxproj Normal file
View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{0af170b6-cc8d-4a56-9879-5064f3d3ebdb}</ProjectGuid>
<RootNamespace>csgo2</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;CSGO2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="events.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="global.h" />
<ClInclude Include="hooks.h" />
<ClInclude Include="interface.h" />
<ClInclude Include="math\types\vector.hpp" />
<ClInclude Include="math\types\vmatrix.hpp" />
<ClInclude Include="memory.h" />
<ClInclude Include="MinHook\include\MinHook.h" />
<ClInclude Include="MinHook\src\buffer.h" />
<ClInclude Include="MinHook\src\HDE\hde32.h" />
<ClInclude Include="MinHook\src\HDE\hde64.h" />
<ClInclude Include="MinHook\src\HDE\pstdint.h" />
<ClInclude Include="MinHook\src\HDE\table32.h" />
<ClInclude Include="MinHook\src\HDE\table64.h" />
<ClInclude Include="MinHook\src\trampoline.h" />
<ClInclude Include="module.h" />
<ClInclude Include="native_sdk\cgameentitysystem.h" />
<ClInclude Include="native_sdk\cgameresourceserviceserver.h" />
<ClInclude Include="native_sdk\cschemasystem.h" />
<ClInclude Include="native_sdk\entity\cbaseentity.h" />
<ClInclude Include="native_sdk\entity\cbaseplayercontroller.h" />
<ClInclude Include="native_sdk\handle\handle.h" />
<ClInclude Include="offset.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="player.h" />
<ClInclude Include="schema.h" />
<ClInclude Include="sdk\convar\convar.hpp" />
<ClInclude Include="sdk\gameevent\IGameEvent.h" />
<ClInclude Include="sdk\handle\basehandle.h" />
<ClInclude Include="sdk\interfaces\interfaces.h" />
<ClInclude Include="sdk\player\player.h" />
<ClInclude Include="sdk\player\playerslot.h" />
<ClInclude Include="sdk\public\eiface.h" />
<ClInclude Include="sdk\public\IAppSystem.h" />
<ClInclude Include="sdk\sdk.h" />
<ClInclude Include="sdk\tier1\bufferstring.h" />
<ClInclude Include="sdk\tier1\UtlMemory.hpp" />
<ClInclude Include="sdk\tier1\UtlString.hpp" />
<ClInclude Include="sdk\tier1\UtlVector.hpp" />
<ClInclude Include="stb.hh" />
<ClInclude Include="vmt.h" />
<ClInclude Include="VTHook.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="events.cpp" />
<ClCompile Include="global.cpp" />
<ClCompile Include="hooks.cpp" />
<ClCompile Include="interface.cpp" />
<ClCompile Include="memory.cpp" />
<ClCompile Include="MinHook\src\buffer.c" />
<ClCompile Include="MinHook\src\HDE\hde32.c" />
<ClCompile Include="MinHook\src\HDE\hde64.c" />
<ClCompile Include="MinHook\src\hook.c" />
<ClCompile Include="MinHook\src\trampoline.c" />
<ClCompile Include="native_sdk\cgameentitysystem.cpp" />
<ClCompile Include="native_sdk\cschemasystem.cpp" />
<ClCompile Include="native_sdk\handle\handle.cpp" />
<ClCompile Include="offset.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="player.cpp" />
<ClCompile Include="schema.cpp" />
<ClCompile Include="sdk\convar\convar.cpp" />
<ClCompile Include="sdk\tier1\UtlString.cpp" />
<ClCompile Include="vmt.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

282
csgo2/csgo2.vcxproj.filters Normal file
View File

@@ -0,0 +1,282 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="头文件\minhook">
<UniqueIdentifier>{89393917-f155-4ae6-9e03-2529967f88c3}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk">
<UniqueIdentifier>{88318acc-d490-446b-8333-f20a22d748a6}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\math">
<UniqueIdentifier>{aed2a097-5c17-4c61-a5de-65cde80a84a4}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\memory">
<UniqueIdentifier>{c3ddaa59-6f23-48e1-b43c-03e626960a5e}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\memory">
<UniqueIdentifier>{d8b32656-ba7f-49d3-be6d-c97f9bc02ba0}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\gameevent">
<UniqueIdentifier>{87180362-2725-4f7b-a702-17cb8cff94d3}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\handle">
<UniqueIdentifier>{8ce5a064-6e56-4bfb-9c12-b6da38016dbc}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\player">
<UniqueIdentifier>{b8db59a4-0a74-4cd8-9f3d-5e30e04a52f3}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\events">
<UniqueIdentifier>{a4fd0778-933c-4ac7-a724-70b62977c3f9}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\events">
<UniqueIdentifier>{341ff6a7-81b6-4c44-9d66-ac9c4fbe8684}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\interfaces">
<UniqueIdentifier>{76acdb22-3f64-4cf6-8447-986ab46533ae}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\native_sdk">
<UniqueIdentifier>{c28f9f29-7571-4821-9cbd-11f27692566a}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\native_sdk\interfaces">
<UniqueIdentifier>{e26bdf5e-ad8d-4ed2-965c-1fdb958a6098}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\native_sdk">
<UniqueIdentifier>{c5938a38-9035-4f7a-952c-156a8549bb54}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\native_sdk\interfaces">
<UniqueIdentifier>{ec02337e-1abc-42a9-b29c-355278bf4bf2}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\native_sdk\entity">
<UniqueIdentifier>{6c9da4be-92c5-4504-8c46-ab0cc612bfe5}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\native_sdk\entity">
<UniqueIdentifier>{f1101bd0-b17e-4c9e-87f1-e34d97979e77}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\native_sdk\handle">
<UniqueIdentifier>{63beb427-0b96-4062-83e0-752efb2ed5f0}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\native_sdk\handle">
<UniqueIdentifier>{68556c7c-97c0-4e1e-82f0-e4b45b9ad40d}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\convar">
<UniqueIdentifier>{befb97b4-a3ba-48a8-84a8-c36a74d2d48c}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\tier1">
<UniqueIdentifier>{a403d20d-862c-4c26-965b-9cc23e67745f}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sdk\public">
<UniqueIdentifier>{c359acb2-cc33-4be0-b5dd-3dfef50ba594}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="MinHook\include\MinHook.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\buffer.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\trampoline.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\HDE\hde32.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\HDE\hde64.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\HDE\pstdint.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\HDE\table32.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="MinHook\src\HDE\table64.h">
<Filter>头文件\minhook</Filter>
</ClInclude>
<ClInclude Include="interface.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="stb.hh">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="math\types\vector.hpp">
<Filter>头文件\math</Filter>
</ClInclude>
<ClInclude Include="math\types\vmatrix.hpp">
<Filter>头文件\math</Filter>
</ClInclude>
<ClInclude Include="global.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="vmt.h">
<Filter>头文件\memory</Filter>
</ClInclude>
<ClInclude Include="memory.h">
<Filter>头文件\memory</Filter>
</ClInclude>
<ClInclude Include="hooks.h">
<Filter>头文件\memory</Filter>
</ClInclude>
<ClInclude Include="module.h">
<Filter>头文件\memory</Filter>
</ClInclude>
<ClInclude Include="offset.h">
<Filter>头文件\memory</Filter>
</ClInclude>
<ClInclude Include="sdk\sdk.h">
<Filter>头文件\sdk</Filter>
</ClInclude>
<ClInclude Include="sdk\gameevent\IGameEvent.h">
<Filter>头文件\sdk\gameevent</Filter>
</ClInclude>
<ClInclude Include="sdk\handle\basehandle.h">
<Filter>头文件\sdk\handle</Filter>
</ClInclude>
<ClInclude Include="sdk\player\playerslot.h">
<Filter>头文件\sdk\player</Filter>
</ClInclude>
<ClInclude Include="sdk\player\player.h">
<Filter>头文件\sdk\player</Filter>
</ClInclude>
<ClInclude Include="events.h">
<Filter>头文件\events</Filter>
</ClInclude>
<ClInclude Include="sdk\interfaces\interfaces.h">
<Filter>头文件\sdk\interfaces</Filter>
</ClInclude>
<ClInclude Include="schema.h">
<Filter>头文件\native_sdk\interfaces</Filter>
</ClInclude>
<ClInclude Include="native_sdk\cschemasystem.h">
<Filter>头文件\native_sdk\interfaces</Filter>
</ClInclude>
<ClInclude Include="native_sdk\cgameentitysystem.h">
<Filter>头文件\native_sdk\interfaces</Filter>
</ClInclude>
<ClInclude Include="native_sdk\entity\cbaseentity.h">
<Filter>头文件\native_sdk\entity</Filter>
</ClInclude>
<ClInclude Include="VTHook.h">
<Filter>头文件\memory</Filter>
</ClInclude>
<ClInclude Include="native_sdk\entity\cbaseplayercontroller.h">
<Filter>头文件\native_sdk\entity</Filter>
</ClInclude>
<ClInclude Include="native_sdk\handle\handle.h">
<Filter>头文件\native_sdk\handle</Filter>
</ClInclude>
<ClInclude Include="player.h">
<Filter>头文件\native_sdk\entity</Filter>
</ClInclude>
<ClInclude Include="native_sdk\cgameresourceserviceserver.h">
<Filter>头文件\native_sdk\interfaces</Filter>
</ClInclude>
<ClInclude Include="sdk\convar\convar.hpp">
<Filter>头文件\sdk\convar</Filter>
</ClInclude>
<ClInclude Include="sdk\tier1\UtlMemory.hpp">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\tier1\UtlString.hpp">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\tier1\UtlVector.hpp">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\public\eiface.h">
<Filter>头文件\sdk\public</Filter>
</ClInclude>
<ClInclude Include="sdk\public\IAppSystem.h">
<Filter>头文件\sdk\public</Filter>
</ClInclude>
<ClInclude Include="sdk\tier1\bufferstring.h">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="MinHook\src\buffer.c">
<Filter>头文件\minhook</Filter>
</ClCompile>
<ClCompile Include="MinHook\src\hook.c">
<Filter>头文件\minhook</Filter>
</ClCompile>
<ClCompile Include="MinHook\src\trampoline.c">
<Filter>头文件\minhook</Filter>
</ClCompile>
<ClCompile Include="MinHook\src\HDE\hde32.c">
<Filter>头文件\minhook</Filter>
</ClCompile>
<ClCompile Include="MinHook\src\HDE\hde64.c">
<Filter>头文件\minhook</Filter>
</ClCompile>
<ClCompile Include="interface.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="global.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="offset.cpp">
<Filter>源文件\memory</Filter>
</ClCompile>
<ClCompile Include="memory.cpp">
<Filter>源文件\memory</Filter>
</ClCompile>
<ClCompile Include="hooks.cpp">
<Filter>源文件\memory</Filter>
</ClCompile>
<ClCompile Include="events.cpp">
<Filter>源文件\events</Filter>
</ClCompile>
<ClCompile Include="schema.cpp">
<Filter>源文件\native_sdk\interfaces</Filter>
</ClCompile>
<ClCompile Include="vmt.cpp">
<Filter>源文件\memory</Filter>
</ClCompile>
<ClCompile Include="native_sdk\cschemasystem.cpp">
<Filter>源文件\native_sdk\interfaces</Filter>
</ClCompile>
<ClCompile Include="native_sdk\cgameentitysystem.cpp">
<Filter>源文件\native_sdk\interfaces</Filter>
</ClCompile>
<ClCompile Include="player.cpp">
<Filter>源文件\native_sdk\entity</Filter>
</ClCompile>
<ClCompile Include="native_sdk\handle\handle.cpp">
<Filter>源文件\native_sdk\handle</Filter>
</ClCompile>
<ClCompile Include="sdk\convar\convar.cpp">
<Filter>头文件\sdk\convar</Filter>
</ClCompile>
<ClCompile Include="sdk\tier1\UtlString.cpp">
<Filter>头文件\sdk\tier1</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
</ItemGroup>
</Project>

62
csgo2/dllmain.cpp Normal file
View File

@@ -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<FILE**> stdout, "CONOUT$", "w", stdout);
CreateThread(NULL, 0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(WatchExitThread),
NULL, 0, NULL);
while (Offset::Module_tier0 == 0)
{
if (global::Exit) {
return false;
}
Offset::Module_tier0 = reinterpret_cast<uint64_t>(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<LPTHREAD_START_ROUTINE>(init),
NULL, 0, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return result;
}

28
csgo2/events.cpp Normal file
View File

@@ -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<CCSPlayerController*>(event->GetPlayerPawn(&userIdNameParams));
const auto attacker = reinterpret_cast<CCSPlayerController*>(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<CCSPlayerController*>(event->GetPlayer(&userIdNameParams));
const auto text = event->GetString("text");
const auto chaterName = chater->m_iszPlayerName();
LOG("player: %s say: %s \n", chaterName, text);
}
}

8
csgo2/events.h Normal file
View File

@@ -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;
}

5
csgo2/framework.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

4
csgo2/global.cpp Normal file
View File

@@ -0,0 +1,4 @@
#include "global.h"
namespace global {
bool Exit;
}

5
csgo2/global.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include "pch.h"
namespace global {
extern bool Exit;
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
// 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);
}

120
csgo2/hooks.cpp Normal file
View File

@@ -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<CCommand*>(args);
const auto theEntity = reinterpret_cast<CBaseEntity*>(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;
//V<><56>bug,<2C><EFBFBD><E2B2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/*
case player_chat:
events::OnPlayerChat(event);
break;
}
*/
}
} while (false);
return original_FireEventServerSide(rcx, event, serverSide);
}
auto initMinHook() -> bool {
bool isSuccess = false;
// <20><>ʼ<EFBFBD><CABC>MiniHook
do {
if (MH_Initialize() != MH_OK) {
LOG("MH_Initialize() != MH_OK\n");
break;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (MH_CreateHook((LPVOID)Offset::FireEventServerSidePtr,
&hook_FireEventServerSide,
reinterpret_cast<LPVOID*>(
&original_FireEventServerSide)) != MH_OK) {
LOG("MH_CreateHook original_FireEventServerSide\n");
break;
}
if (MH_CreateHook((LPVOID)Offset::Host_SayPtr,
&hook_Host_Say,
reinterpret_cast<LPVOID*>(
&original_Host_Say)) != MH_OK) {
LOG("MH_CreateHook original_Host_Say\n");
break;
}
// <20><><EFBFBD>ù<EFBFBD><C3B9><EFBFBD>
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();
}
}

15
csgo2/hooks.h Normal file
View File

@@ -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;
}

4
csgo2/interface.cpp Normal file
View File

@@ -0,0 +1,4 @@
#include "pch.h"
namespace interfaces {
} // namespace interfaces

5
csgo2/interface.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include "pch.h"
namespace interfaces {
} // namespace interfaces

0
csgo2/memory.cpp Normal file
View File

18
csgo2/memory.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "pch.h"
namespace Memory {
template<class T>
void write(uintptr_t address, T value)
{
WriteProcessMemory(GetCurrentProcess(), (void*)address, &value, sizeof(T), 0);
}
template<class T>
T read(uintptr_t address)
{
T buffer{};
ReadProcessMemory(GetCurrentProcess(), (void*)address, &buffer, sizeof(T), 0);
return buffer;
}
};

146
csgo2/module.h Normal file
View File

@@ -0,0 +1,146 @@
#pragma once
#include "pch.h"
#define IS_WINDOWS 1
class InterfaceReg;
// Pointer arithmetic utility class.
struct UTILPtr {
public:
template <typename T>
UTILPtr(T val) {
m_val = (uintptr_t)(val);
}
template <typename T = void*>
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 <typename T>
void Get(T& dst, const char* variableName = nullptr) {
dst = Get<T>(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<HMODULE>(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<InterfaceReg*>();
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 <size_t N>
UTILPtr FindPattern(const std::array<int, N>& signature) const {
UTILPtr rv = 0;
if (this->IsLoaded()) {
const int* pSigData = signature.data();
uint8_t* pBytes = reinterpret_cast<uint8_t*>(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<uintptr_t>(&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<void*>(GetModuleHandleA(this->GetName()));
#endif
}
void InitializeBounds() {
if (!this->IsLoaded()) return;
#ifdef IS_WINDOWS
MODULEINFO mi;
BOOL status = GetModuleInformation(GetCurrentProcess(),
static_cast<HMODULE>(this->m_handle),
&mi, sizeof(mi));
if (status != 0) {
this->m_start = reinterpret_cast<uintptr_t>(this->m_handle);
this->m_end = static_cast<uintptr_t>(mi.SizeOfImage);
}
#endif
}
void* m_handle = nullptr;
uintptr_t m_start = 0, m_end = 0;
const char* m_name = "";
};

View File

@@ -0,0 +1,6 @@
#include "cgameentitysystem.h"
#include "../pch.h"
CGameEntitySystem* CGameEntitySystem::GetInstance(){
return Offset::InterFaces::GameResourceServiceServer->GetGameEntitySystem();
}

View File

@@ -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();
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include "../pch.h"
class CGameEntitySystem;
class CGameResourceService
{
public:
CGameEntitySystem *GetGameEntitySystem()
{
return *reinterpret_cast<CGameEntitySystem **>((uintptr_t)(this) + 0x58);
}
};

View File

@@ -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);
}

View File

@@ -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*;
};

View File

@@ -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)
};

View File

@@ -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)
};

View File

@@ -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)
};

View File

@@ -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)
};

View File

@@ -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)
};

View File

@@ -0,0 +1,9 @@
#pragma once
#include "cbaseplayerpawn.h"
class CCSPlayerPawn : public CBasePlayerPawn
{
public:
DECLARE_CLASS(CCSPlayerPawn);
};

View File

@@ -0,0 +1,18 @@
#pragma once
#include <platform.h>
#include "../schema.h"
class CPlayer_MovementServices
{
public:
DECLARE_CLASS(CPlayer_MovementServices);
};
class CCSPlayerController_InGameMoneyServices
{
public:
DECLARE_CLASS(CCSPlayerController_InGameMoneyServices);
SCHEMA_FIELD(int, m_iAccount)
};

View File

@@ -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());
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#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 <typename T = CBaseEntity>
T* Get() const
{
return reinterpret_cast<T*>(GetBaseEntity());
}
uint32_t m_Index;
};

56
csgo2/offset.cpp Normal file
View File

@@ -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<CSchemaSystem*>(schemasystem.FindInterface("SchemaSystem_001").Get());
// engine.dll
InterFaces::GameEventManager = reinterpret_cast<IGameEventManager2*>(engine.FindInterface("GameEventSystemServerV001").Get());
InterFaces::GameResourceServiceServer = reinterpret_cast<CGameResourceService*>(engine.FindInterface("Source2GameClients001").Get());
// server.dll
InterFaces::IServerGameClient = reinterpret_cast<IServerGameClients*>(server.FindInterface("GameResourceServiceServerV001").Get());
// only init in console server
InterFaces::CGameEventManger = reinterpret_cast<CGameEventManager*>(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

38
csgo2/offset.h Normal file
View File

@@ -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

17
csgo2/pch.cpp Normal file
View File

@@ -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<char*>(temp.c_str()), num_of_chars + 1, format,
marker);
OutputDebugStringA(temp.c_str());
}
// 当使用预编译的头时,需要使用此源文件,编译才能成功。

34
csgo2/pch.h Normal file
View File

@@ -0,0 +1,34 @@
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#include <string>
#include <array>
#include <Windows.h>
#include <Psapi.h>
#include <thread>
#include <unordered_map>
#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<stb::fixed_string{sig}>::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"

6
csgo2/player.cpp Normal file
View File

@@ -0,0 +1,6 @@
#include "player.h"
auto CBasePlayer::ForceRespawn() -> void
{
return CALL_VIRTUAL(void, 26, this);
}

38
csgo2/player.h Normal file
View File

@@ -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)
};

81
csgo2/schema.cpp Normal file
View File

@@ -0,0 +1,81 @@
#include "schema.h"
#include "native_sdk/cgameentitysystem.h"
#include "native_sdk/cschemasystem.h"
using SchemaKeyValueMap_t = std::unordered_map<uint32_t, int16_t>;
using SchemaTableMap_t = std::unordered_map<uint32_t, SchemaKeyValueMap_t>;
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);
}

60
csgo2/schema.h Normal file
View File

@@ -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<type> 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<std::add_pointer_t<type>>( \
(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<FnNetworkStateChanged>(Offset::NetworkStateChangedPtr)((uintptr_t)(this) + m_chain, m_offset + extra_offset, 0xFFFFFFFF); \
} \
*reinterpret_cast<std::add_pointer_t<type>>((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<std::add_pointer_t<type>>( \
(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;

View File

@@ -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);
}

128
csgo2/sdk/convar/convar.hpp Normal file
View File

@@ -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<T>::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<T, MAX_SIZE > >
{
typedef CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > 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<char, COMMAND_MAX_LENGTH> m_ArgSBuffer;
CUtlVectorFixedGrowable<char, COMMAND_MAX_LENGTH> m_ArgvBuffer;
CUtlVectorFixedGrowable<char*, COMMAND_MAX_ARGC> m_Args;
};

View File

@@ -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;
};

View File

@@ -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;
};
};

View File

@@ -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.
};

View File

@@ -0,0 +1,3 @@
#pragma once
#include "../sdk.h"
class CBasePlayer;

View File

@@ -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;
};

View File

@@ -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;
};

119
csgo2/sdk/public/eiface.h Normal file
View File

@@ -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;

21
csgo2/sdk/sdk.h Normal file
View File

@@ -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"

View File

@@ -0,0 +1,699 @@
#pragma once
#include <malloc.h>
#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<T, I>::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<T, I>::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<T, I>::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<T, I>::~CUtlMemory()
{
Purge();
}
template< class T, class I >
void CUtlMemory<T, I>::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<T, I>::Swap(CUtlMemory<T, I> &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<T, I>::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<T, I>::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<T, I>::SetExternalBuffer(const T* pMemory, int numElements)
{
// Blow away any existing allocated memory
Purge();
m_pMemory = const_cast<T*>(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<T, I>::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<T, I>::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<T, I>::Detach()
{
return (T*)DetachMemory();
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< class T, class I >
inline T& CUtlMemory<T, I>::operator[](I i)
{
assert(!IsReadOnly());
assert(IsIdxValid(i));
return m_pMemory[i];
}
template< class T, class I >
inline const T& CUtlMemory<T, I>::operator[](I i) const
{
assert(IsIdxValid(i));
return m_pMemory[i];
}
template< class T, class I >
inline T& CUtlMemory<T, I>::Element(I i)
{
assert(!IsReadOnly());
assert(IsIdxValid(i));
return m_pMemory[i];
}
template< class T, class I >
inline const T& CUtlMemory<T, I>::Element(I i) const
{
assert(IsIdxValid(i));
return m_pMemory[i];
}
//-----------------------------------------------------------------------------
// is the memory externally allocated?
//-----------------------------------------------------------------------------
template< class T, class I >
bool CUtlMemory<T, I>::IsExternallyAllocated() const
{
return (m_nGrowSize < 0);
}
//-----------------------------------------------------------------------------
// is the memory read only?
//-----------------------------------------------------------------------------
template< class T, class I >
bool CUtlMemory<T, I>::IsReadOnly() const
{
return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER);
}
template< class T, class I >
void CUtlMemory<T, I>::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<T, I>::Base()
{
assert(!IsReadOnly());
return m_pMemory;
}
template< class T, class I >
inline const T *CUtlMemory<T, I>::Base() const
{
return m_pMemory;
}
//-----------------------------------------------------------------------------
// Size
//-----------------------------------------------------------------------------
template< class T, class I >
inline int CUtlMemory<T, I>::NumAllocated() const
{
return m_nAllocationCount;
}
template< class T, class I >
inline int CUtlMemory<T, I>::Count() const
{
return m_nAllocationCount;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T, class I >
inline bool CUtlMemory<T, I>::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<T, I>::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<T, I>::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<T, I>::Purge()
{
if(!IsExternallyAllocated()) {
if(m_pMemory) {
free((void*)m_pMemory);
m_pMemory = 0;
}
m_nAllocationCount = 0;
}
}
template< class T, class I >
void CUtlMemory<T, I>::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<T>
{
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<T, nAlignment>::Align(const void *pAddr)
{
size_t nAlignmentMask = nAlignment - 1;
return (void*)(((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask));
}
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template< class T, int nAlignment >
CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned(int nGrowSize, int nInitAllocationCount)
{
CUtlMemory<T>::m_pMemory = 0;
CUtlMemory<T>::m_nAllocationCount = nInitAllocationCount;
CUtlMemory<T>::m_nGrowSize = nGrowSize;
this->ValidateGrowSize();
// Alignment must be a power of two
COMPILE_TIME_ASSERT((nAlignment & (nAlignment - 1)) == 0);
assert((nGrowSize >= 0) && (nGrowSize != CUtlMemory<T>::EXTERNAL_BUFFER_MARKER));
if(CUtlMemory<T>::m_nAllocationCount) {
UTLMEMORY_TRACK_ALLOC();
MEM_ALLOC_CREDIT_CLASS();
CUtlMemory<T>::m_pMemory = (T*)_aligned_malloc(nInitAllocationCount * sizeof(T), nAlignment);
}
}
template< class T, int nAlignment >
CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned(T* pMemory, int numElements)
{
// Special marker indicating externally supplied memory
CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER;
CUtlMemory<T>::m_pMemory = (T*)Align(pMemory);
CUtlMemory<T>::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory) / sizeof(T);
}
template< class T, int nAlignment >
CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned(const T* pMemory, int numElements)
{
// Special marker indicating externally supplied memory
CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER;
CUtlMemory<T>::m_pMemory = (T*)Align(pMemory);
CUtlMemory<T>::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory) / sizeof(T);
}
template< class T, int nAlignment >
CUtlMemoryAligned<T, nAlignment>::~CUtlMemoryAligned()
{
Purge();
}
//-----------------------------------------------------------------------------
// Attaches the buffer to external memory....
//-----------------------------------------------------------------------------
template< class T, int nAlignment >
void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer(T* pMemory, int numElements)
{
// Blow away any existing allocated memory
Purge();
CUtlMemory<T>::m_pMemory = (T*)Align(pMemory);
CUtlMemory<T>::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory) / sizeof(T);
// Indicate that we don't own the memory
CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER;
}
template< class T, int nAlignment >
void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer(const T* pMemory, int numElements)
{
// Blow away any existing allocated memory
Purge();
CUtlMemory<T>::m_pMemory = (T*)Align(pMemory);
CUtlMemory<T>::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory) / sizeof(T);
// Indicate that we don't own the memory
CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER;
}
//-----------------------------------------------------------------------------
// Grows the memory
//-----------------------------------------------------------------------------
template< class T, int nAlignment >
void CUtlMemoryAligned<T, nAlignment>::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<T>::m_nAllocationCount + num;
CUtlMemory<T>::m_nAllocationCount = UtlMemory_CalcNewAllocationCount(CUtlMemory<T>::m_nAllocationCount, CUtlMemory<T>::m_nGrowSize, nAllocationRequested, sizeof(T));
UTLMEMORY_TRACK_ALLOC();
if(CUtlMemory<T>::m_pMemory) {
MEM_ALLOC_CREDIT_CLASS();
CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned(CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment);
assert(CUtlMemory<T>::m_pMemory);
} else {
MEM_ALLOC_CREDIT_CLASS();
CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned(CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment);
assert(CUtlMemory<T>::m_pMemory);
}
}
//-----------------------------------------------------------------------------
// Makes sure we've got at least this much memory
//-----------------------------------------------------------------------------
template< class T, int nAlignment >
inline void CUtlMemoryAligned<T, nAlignment>::EnsureCapacity(int num)
{
if(CUtlMemory<T>::m_nAllocationCount >= num)
return;
if(this->IsExternallyAllocated()) {
// Can't grow a buffer whose memory was externally allocated
assert(0);
return;
}
UTLMEMORY_TRACK_FREE();
CUtlMemory<T>::m_nAllocationCount = num;
UTLMEMORY_TRACK_ALLOC();
if(CUtlMemory<T>::m_pMemory) {
MEM_ALLOC_CREDIT_CLASS();
CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned(CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment);
} else {
MEM_ALLOC_CREDIT_CLASS();
CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned(CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment);
}
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< class T, int nAlignment >
void CUtlMemoryAligned<T, nAlignment>::Purge()
{
if(!this->IsExternallyAllocated()) {
if(CUtlMemory<T>::m_pMemory) {
UTLMEMORY_TRACK_FREE();
MemAlloc_FreeAligned(CUtlMemory<T>::m_pMemory);
CUtlMemory<T>::m_pMemory = 0;
}
CUtlMemory<T>::m_nAllocationCount = 0;
}
}

View File

@@ -0,0 +1,309 @@
#include "UtlString.hpp"
#define NOMINMAX
#include <Windows.h>
#include <stdio.h>
//-----------------------------------------------------------------------------
// 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<const char*>(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<char*>(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);
}
}

View File

@@ -0,0 +1,204 @@
#pragma once
#include <cstdint>
#include <cstring>
#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<unsigned char> 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());
}

View File

@@ -0,0 +1,766 @@
#pragma once
#include <cstring>
#include "UtlMemory.hpp"
template <class T>
inline T* CopyConstruct(T* pMemory, T const& src)
{
return ::new(pMemory) T(src);
}
template< class T, class A = CUtlMemory<T> >
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<T, A>& operator=(const CUtlVector<T, A> &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<T, A> 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<T, A>::CUtlVector(int growSize, int initSize) :
m_Memory(growSize, initSize), m_Size(0)
{
ResetDbgInfo();
}
template< typename T, class A >
inline CUtlVector<T, A>::CUtlVector(T* pMemory, int allocationCount, int numElements) :
m_Memory(pMemory, allocationCount), m_Size(numElements)
{
ResetDbgInfo();
}
template< typename T, class A >
inline CUtlVector<T, A>::~CUtlVector()
{
Purge();
}
template< typename T, class A >
inline CUtlVector<T, A>& CUtlVector<T, A>::operator=(const CUtlVector<T, A> &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<T, A>::operator[](int i)
{
assert(i < m_Size);
return m_Memory[i];
}
template< typename T, class A >
inline const T& CUtlVector<T, A>::operator[](int i) const
{
assert(i < m_Size);
return m_Memory[i];
}
template< typename T, class A >
inline T& CUtlVector<T, A>::Element(int i)
{
assert(i < m_Size);
return m_Memory[i];
}
template< typename T, class A >
inline const T& CUtlVector<T, A>::Element(int i) const
{
assert(i < m_Size);
return m_Memory[i];
}
template< typename T, class A >
inline T& CUtlVector<T, A>::Head()
{
assert(m_Size > 0);
return m_Memory[0];
}
template< typename T, class A >
inline const T& CUtlVector<T, A>::Head() const
{
assert(m_Size > 0);
return m_Memory[0];
}
template< typename T, class A >
inline T& CUtlVector<T, A>::Tail()
{
assert(m_Size > 0);
return m_Memory[m_Size - 1];
}
template< typename T, class A >
inline const T& CUtlVector<T, A>::Tail() const
{
assert(m_Size > 0);
return m_Memory[m_Size - 1];
}
//-----------------------------------------------------------------------------
// Count
//-----------------------------------------------------------------------------
template< typename T, class A >
inline int CUtlVector<T, A>::Count() const
{
return m_Size;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< typename T, class A >
inline bool CUtlVector<T, A>::IsValidIndex(int i) const
{
return (i >= 0) && (i < m_Size);
}
//-----------------------------------------------------------------------------
// Returns in invalid index
//-----------------------------------------------------------------------------
template< typename T, class A >
inline int CUtlVector<T, A>::InvalidIndex()
{
return -1;
}
//-----------------------------------------------------------------------------
// Grows the vector
//-----------------------------------------------------------------------------
template< typename T, class A >
void CUtlVector<T, A>::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<T, A>::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<T, A>::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<T, A>::EnsureCount(int num)
{
if(Count() < num) {
AddMultipleToTail(num - Count());
}
}
//-----------------------------------------------------------------------------
// Shifts elements
//-----------------------------------------------------------------------------
template< typename T, class A >
void CUtlVector<T, A>::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<T, A>::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<T, A>::AddToHead()
{
return InsertBefore(0);
}
template< typename T, class A >
inline int CUtlVector<T, A>::AddToTail()
{
return InsertBefore(m_Size);
}
template< typename T, class A >
inline int CUtlVector<T, A>::InsertAfter(int elem)
{
return InsertBefore(elem + 1);
}
template< typename T, class A >
int CUtlVector<T, A>::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<T, A>::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<T, A>::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<T, A>::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<T, A>::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<T, A>::AddMultipleToHead(int num)
{
return InsertMultipleBefore(0, num);
}
template< typename T, class A >
inline int CUtlVector<T, A>::AddMultipleToTail(int num)
{
return InsertMultipleBefore(m_Size, num);
}
template< typename T, class A >
inline int CUtlVector<T, A>::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<T, A>::InsertMultipleAfter(int elem, int num)
{
return InsertMultipleBefore(elem + 1, num);
}
template< typename T, class A >
void CUtlVector<T, A>::SetCount(int count)
{
RemoveAll();
AddMultipleToTail(count);
}
template< typename T, class A >
inline void CUtlVector<T, A>::SetSize(int size)
{
SetCount(size);
}
template< typename T, class A >
void CUtlVector<T, A>::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<T, A>::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<T, A>::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<T, A>::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<T, A>::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<T, A>::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<T, A>::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<T, A>::FillWithValue(const T& src)
{
for(int i = 0; i < Count(); i++) {
Element(i) = src;
}
}
template< typename T, class A >
bool CUtlVector<T, A>::HasElement(const T& src) const
{
return (GetOffset(src) >= 0);
}
//-----------------------------------------------------------------------------
// Element removal
//-----------------------------------------------------------------------------
template< typename T, class A >
void CUtlVector<T, A>::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<T, A>::Remove(int elem)
{
Destruct(&Element(elem));
ShiftElementsLeft(elem);
--m_Size;
}
template< typename T, class A >
bool CUtlVector<T, A>::FindAndRemove(const T& src)
{
int elem = GetOffset(src);
if(elem != -1) {
Remove(elem);
return true;
}
return false;
}
template< typename T, class A >
bool CUtlVector<T, A>::FindAndFastRemove(const T& src)
{
int elem = GetOffset(src);
if(elem != -1) {
FastRemove(elem);
return true;
}
return false;
}
template< typename T, class A >
void CUtlVector<T, A>::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<T, A>::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<T, A>::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<T, A>::RemoveAll()
{
for(int i = m_Size; --i >= 0; ) {
Destruct(&Element(i));
}
m_Size = 0;
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< typename T, class A >
inline void CUtlVector<T, A>::Purge()
{
RemoveAll();
m_Memory.Purge();
ResetDbgInfo();
}
template< typename T, class A >
inline void CUtlVector<T, A>::PurgeAndDeleteElements()
{
for(int i = 0; i < m_Size; i++) {
delete Element(i);
}
Purge();
}
template< typename T, class A >
inline void CUtlVector<T, A>::Compact()
{
m_Memory.Purge(m_Size);
}
template< typename T, class A >
inline int CUtlVector<T, A>::NumAllocated() const
{
return m_Memory.NumAllocated();
}
//-----------------------------------------------------------------------------
// Data and memory validation
//-----------------------------------------------------------------------------
#ifdef DBGFLAG_VALIDATE
template< typename T, class A >
void CUtlVector<T, A>::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 T> 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);
}
};

View File

@@ -0,0 +1,272 @@
#pragma once
#include "../sdk.h"
#define DLL_CLASS_IMPORT __declspec( dllimport )
class CFormatStringElement;
class IFormatOutputStream;
template<size_t MAX_SIZE, bool AllowHeapAllocation>
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<size_t MAX_SIZE = 8, bool AllowHeapAllocation = true, typename T = CBufferStringGrowable<MAX_SIZE, AllowHeapAllocation>>
T *ToGrowable()
{
return (T *)this;
}
};
template<size_t MAX_SIZE, bool AllowHeapAllocation = true>
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<char>::EmptyString();
}
private:
int m_nTotalCount;
int m_nAllocated;
union
{
const char *m_pString;
const char m_szString[MAX_SIZE];
} m_Memory;
};

226
csgo2/stb.hh Normal file
View File

@@ -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 <cstdint>
#include <array>
namespace stb {
namespace detail {
// detail methods assume null terminator.
template<std::size_t N>
constexpr auto find_first_of_start(std::array<char, N> const& data, std::size_t start, char ch) noexcept {
std::size_t idx = start;
while (data[idx] != ch && idx < N)
++idx;
return idx;
}
template<std::size_t N>
constexpr auto find_first_not_of_start(std::array<char, N> 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<std::size_t N>
constexpr auto find_last_of(std::array<char, N> const& data, char ch) noexcept {
std::size_t idx = data.size() - 2;
while (data[idx] != ch && idx >= 0)
--idx;
return idx;
}
template<std::size_t N>
constexpr auto find_last_not_of(std::array<char, N> 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<typename T, T F = 16>
constexpr T concat_hex(T lhs, T rhs) noexcept {
return F * lhs + rhs;
}
} // namespace detail
template<auto V>
struct consteval_value {
constexpr static decltype(V) value = V;
};
template<std::size_t N>
struct fixed_string: public std::array<char, N + 1> {
using std::array<char, N + 1>::array;
constexpr fixed_string(const char* str) noexcept
: std::array<char, N + 1>() {
for (auto i = 0; i != N; ++i)
(*this)[i] = str[i];
}
};
template<std::size_t N>
fixed_string(const char (&)[N]) noexcept -> fixed_string<N - 1>;
template<char delimiter, char mask, typename element_type, element_type masked>
struct basic_hex_string_array_conversion {
template<fixed_string str>
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<element_type, count> result = {};
std::array<std::size_t, count> 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<element_type>(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<element_type>(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<make()>::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

1
csgo2/vmt.cpp Normal file
View File

@@ -0,0 +1 @@
#include "vmt.h"

19
csgo2/vmt.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "pch.h"
#define CALL_VIRTUAL(retType, idx, ...) \
vmt::CallVirtual<retType>(idx, __VA_ARGS__)
namespace vmt {
template <typename T = void*>
inline T GetVMethod(uint32_t uIndex, void* pClass) {
void** pVTable = *static_cast<void***>(pClass);
return reinterpret_cast<T>(pVTable[uIndex]);
}
template <typename T, typename... Args>
inline T CallVirtual(uint32_t uIndex, void* pClass, Args... args) {
auto pFunc = GetVMethod<T(__thiscall*)(void*, Args...)>(uIndex, pClass);
return pFunc(pClass, args...);
}
} // namespace vmt