Merge pull request #25 from Arkshine/feature-client_buy-forward
Implement CS_OnBuy forward + Do some clean up (bug 5906)
This commit is contained in:
commit
08378eed4b
|
@ -225,6 +225,7 @@ class AMXXConfig(object):
|
||||||
'-arch', 'i386',
|
'-arch', 'i386',
|
||||||
'-lstdc++',
|
'-lstdc++',
|
||||||
'-stdlib=libstdc++',
|
'-stdlib=libstdc++',
|
||||||
|
'-framework', 'CoreServices',
|
||||||
]
|
]
|
||||||
cfg.cxxflags += ['-stdlib=libstdc++']
|
cfg.cxxflags += ['-stdlib=libstdc++']
|
||||||
elif builder.target_platform == 'windows':
|
elif builder.target_platform == 'windows':
|
||||||
|
@ -238,7 +239,9 @@ class AMXXConfig(object):
|
||||||
]
|
]
|
||||||
|
|
||||||
cfg.includes += [os.path.join(builder.buildPath, 'includes')]
|
cfg.includes += [os.path.join(builder.buildPath, 'includes')]
|
||||||
|
cfg.includes += [os.path.join(builder.sourcePath, 'public')]
|
||||||
cfg.includes += [os.path.join(builder.sourcePath, 'public', 'amtl')]
|
cfg.includes += [os.path.join(builder.sourcePath, 'public', 'amtl')]
|
||||||
|
cfg.includes += [os.path.join(builder.sourcePath, 'public', 'memtools')]
|
||||||
return
|
return
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -5,9 +5,14 @@ binary = AMXX.MetaModule(builder, 'cstrike')
|
||||||
|
|
||||||
binary.sources = [
|
binary.sources = [
|
||||||
'sdk/amxxmodule.cpp',
|
'sdk/amxxmodule.cpp',
|
||||||
|
'amxx_api.cpp',
|
||||||
'CstrikePlayer.cpp',
|
'CstrikePlayer.cpp',
|
||||||
'cstrike.cpp',
|
'CstrikeNatives.cpp',
|
||||||
'CstrikeHacks.cpp',
|
'CstrikeHacks.cpp',
|
||||||
|
'CstrikeUtils.cpp',
|
||||||
|
'../../../public/memtools/MemoryUtils.cpp',
|
||||||
|
'../../../public/memtools/CDetour/detours.cpp',
|
||||||
|
'../../../public/memtools/CDetour/asm/asm.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
AMXX.modules += [builder.Add(binary)]
|
AMXX.modules += [builder.Add(binary)]
|
||||||
|
|
217
dlls/cstrike/cstrike/cstrike.h → dlls/cstrike/cstrike/CstrikeDatas.h
Executable file → Normal file
217
dlls/cstrike/cstrike/cstrike.h → dlls/cstrike/cstrike/CstrikeDatas.h
Executable file → Normal file
|
@ -1,48 +1,39 @@
|
||||||
/* AMX Mod X
|
/* AMX Mod X
|
||||||
* Counter-Strike Module
|
* Counter-Strike Module
|
||||||
*
|
*
|
||||||
* by the AMX Mod X Development Team
|
* by the AMX Mod X Development Team
|
||||||
*
|
*
|
||||||
* This file is part of AMX Mod X.
|
* This file is part of AMX Mod X.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
* Free Software Foundation; either version 2 of the License, or (at
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
* your option) any later version.
|
* your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
* In addition, as a special exception, the author gives permission to
|
* In addition, as a special exception, the author gives permission to
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
* you do not wish to do so, delete this exception statement from your
|
* you do not wish to do so, delete this exception statement from your
|
||||||
* version.
|
* version.
|
||||||
*/
|
*/
|
||||||
|
#ifndef CSTRIKE_DATA_H
|
||||||
// cstrike MODULE TO DO HERE: http://www.amxmodx.org/forums/viewtopic.php?t=45
|
#define CSTRIKE_DATA_H
|
||||||
// This implementation uses Vexd's way (lightly modified) of setting models on players.
|
|
||||||
|
|
||||||
#include "amxxmodule.h"
|
#include "amxxmodule.h"
|
||||||
#include <extdll.h>
|
|
||||||
#include <meta_api.h>
|
|
||||||
#include "CstrikePlayer.h"
|
|
||||||
|
|
||||||
#define GETINFOKEYBUFFER (*g_engfuncs.pfnGetInfoKeyBuffer)
|
|
||||||
#define SETCLIENTKEYVALUE (*g_engfuncs.pfnSetClientKeyValue)
|
|
||||||
#define GETCLIENTKEYVALUE (*g_engfuncs.pfnInfoKeyValue)
|
|
||||||
#define CREATENAMEDENTITY (*g_engfuncs.pfnCreateNamedEntity)
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined (__APPLE__)
|
#if defined(__linux__) || defined (__APPLE__)
|
||||||
#define EXTRAOFFSET 5 // offsets 5 higher in Linux builds
|
#define EXTRAOFFSET 5 // offsets 5 higher in Linux builds
|
||||||
|
@ -52,7 +43,8 @@
|
||||||
#define EXTRAOFFSET 0 // no change in Windows builds
|
#define EXTRAOFFSET 0 // no change in Windows builds
|
||||||
#define EXTRAOFFSET_WEAPONS 0
|
#define EXTRAOFFSET_WEAPONS 0
|
||||||
#define ACTUAL_EXTRA_OFFSET 0
|
#define ACTUAL_EXTRA_OFFSET 0
|
||||||
#endif // defined(__linux__) || defined(__APPLE__)
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Offset history:
|
Offset history:
|
||||||
041029:
|
041029:
|
||||||
|
@ -61,9 +53,6 @@
|
||||||
Also backpack ammo offsets were all obviously 5 steps too high since unknown time...
|
Also backpack ammo offsets were all obviously 5 steps too high since unknown time...
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define HAS_SHIELD (1<<24) //16777216
|
|
||||||
|
|
||||||
// "player" entities
|
// "player" entities
|
||||||
#if !defined __amd64__
|
#if !defined __amd64__
|
||||||
// 32 bit offsets here
|
// 32 bit offsets here
|
||||||
|
@ -156,20 +145,80 @@
|
||||||
#define OFFSET_HOSTAGEID 516 + EXTRAOFFSET // +29
|
#define OFFSET_HOSTAGEID 516 + EXTRAOFFSET // +29
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined __linux__
|
#if defined(__linux__)
|
||||||
#define CS_DETOURCOPYBYTES_CLIENTCOMMAND 6
|
#define CS_IDENT_USEBOTARGS "UseBotArgs"
|
||||||
#elif defined __APPLE__
|
#define CS_IDENT_BOTARGS "BotArgs"
|
||||||
#define CS_DETOURCOPYBYTES_CLIENTCOMMAND 5
|
#define CS_IDENT_HIDDEN_STATE false
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define CS_IDENT_USEBOTARGS "UseBotArgs"
|
||||||
|
#define CS_IDENT_BOTARGS "BotArgs"
|
||||||
|
#define CS_IDENT_HIDDEN_STATE true
|
||||||
#else
|
#else
|
||||||
#define CS_DETOURCOPYBYTES_CLIENTCOMMAND 6
|
#define CS_CLICMD_OFFS_USEBOTARGS 2
|
||||||
#define CS_CLICMD_OFFS_USEBOTARGS 2
|
#define CS_CLICMD_OFFS_BOTARGS 22
|
||||||
#define CS_CLICMD_OFFS_BOTARGS 22
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CS_OnBuy forward
|
||||||
|
*/
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define CS_IDENT_CANBUYTHIS "_Z10CanBuyThisP11CBasePlayeri"
|
||||||
|
#define CS_IDENT_BUYITEM "_Z7BuyItemP11CBasePlayeri"
|
||||||
|
#define CS_IDENT_BUYGUNAMMO "_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb"
|
||||||
|
#define CS_IDENT_HIDDEN_STATE false
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define CS_IDENT_CANBUYTHIS "_Z10CanBuyThisP11CBasePlayeri"
|
||||||
|
#define CS_IDENT_BUYITEM "_Z7BuyItemP11CBasePlayeri"
|
||||||
|
#define CS_IDENT_BUYGUNAMMO "_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb"
|
||||||
|
#define CS_IDENT_HIDDEN_STATE true
|
||||||
|
#elif defined(WIN32)
|
||||||
|
#define CS_IDENT_CANBUYTHIS "\\x53\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\x56\\x8B\\x2A\\x2A\\x2A\\x57"
|
||||||
|
#define CS_IDENT_BUYITEM "\\x53\\x56\\x8B\\x2A\\x2A\\x2A\\xBB\\x2A\\x2A\\x2A\\x2A\\x57\\x53"
|
||||||
|
#define CS_IDENT_BUYGUNAMMO "\\x56\\x57\\x8B\\x2A\\x2A\\x2A\\x6A\\x2A\\x8B\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x84\\x2A\\x0F"
|
||||||
|
#define CS_IDENT_HIDDEN_STATE false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CSI_P228 CSW_P228
|
||||||
|
#define CSI_SCOUT CSW_SCOUT
|
||||||
|
#define CSI_HEGRENADE CSW_HEGRENADE
|
||||||
|
#define CSI_XM1014 CSW_XM1014
|
||||||
|
#define CSI_C4 CSW_C4
|
||||||
|
#define CSI_MAC10 CSW_MAC10
|
||||||
|
#define CSI_AUG CSW_AUG
|
||||||
|
#define CSI_SMOKEGRENADE CSW_SMOKEGRENADE
|
||||||
|
#define CSI_ELITE CSW_ELITE
|
||||||
|
#define CSI_FIVESEVEN CSW_FIVESEVEN
|
||||||
|
#define CSI_UMP45 CSW_UMP45
|
||||||
|
#define CSI_SG550 CSW_SG550
|
||||||
|
#define CSI_GALI CSW_GALI
|
||||||
|
#define CSI_FAMAS CSW_FAMAS
|
||||||
|
#define CSI_USP CSW_USP
|
||||||
|
#define CSI_GLOCK18 CSW_GLOCK18
|
||||||
|
#define CSI_AWP CSW_AWP
|
||||||
|
#define CSI_MP5NAVY CSW_MP5NAVY
|
||||||
|
#define CSI_M249 CSW_M249
|
||||||
|
#define CSI_M3 CSW_M3
|
||||||
|
#define CSI_M4A1 CSW_M4A1
|
||||||
|
#define CSI_TMP CSW_TMP
|
||||||
|
#define CSI_G3SG1 CSW_G3SG1
|
||||||
|
#define CSI_FLASHBANG CSW_FLASHBANG
|
||||||
|
#define CSI_DEAGLE CSW_DEAGLE
|
||||||
|
#define CSI_SG552 CSW_SG552
|
||||||
|
#define CSI_AK47 CSW_AK47
|
||||||
|
#define CSI_KNIFE CSW_KNIFE
|
||||||
|
#define CSI_P90 CSW_P90
|
||||||
|
#define CSI_SHIELDGUN CSW_SHIELDGUN
|
||||||
|
#define CSI_VEST CSW_VEST // Custom
|
||||||
|
#define CSI_VESTHELM CSW_VESTHELM // Custom
|
||||||
|
#define CSI_DEFUSER 33 // Custom
|
||||||
|
#define CSI_NVGS 34 // Custom
|
||||||
|
#define CSI_PRIMAMMO 36 // Custom
|
||||||
|
#define CSI_SECAMMO 37 // Custom
|
||||||
|
|
||||||
|
#define BITS_PISTOLS (1<<CSI_GLOCK18 | 1<<CSI_USP | 1<<CSI_P228 | 1<<CSI_DEAGLE | 1<<CSI_ELITE | 1<<CSI_FIVESEVEN)
|
||||||
|
|
||||||
// Ids of weapons in CS
|
// Ids of weapons in CS
|
||||||
#define CSW_P228 1
|
#define CSW_P228 1
|
||||||
//#define CSW_SHIELD 2
|
|
||||||
#define CSW_SCOUT 3
|
#define CSW_SCOUT 3
|
||||||
#define CSW_HEGRENADE 4
|
#define CSW_HEGRENADE 4
|
||||||
#define CSW_XM1014 5
|
#define CSW_XM1014 5
|
||||||
|
@ -200,6 +249,7 @@
|
||||||
#define CSW_P90 30
|
#define CSW_P90 30
|
||||||
#define CSW_VEST 31 // Brand new invention!
|
#define CSW_VEST 31 // Brand new invention!
|
||||||
#define CSW_VESTHELM 32 // Brand new invention!
|
#define CSW_VESTHELM 32 // Brand new invention!
|
||||||
|
#define CSW_SHIELDGUN 99
|
||||||
|
|
||||||
// These are used with armoury_entity:s.
|
// These are used with armoury_entity:s.
|
||||||
#define CSA_MP5NAVY 0
|
#define CSA_MP5NAVY 0
|
||||||
|
@ -270,6 +320,9 @@
|
||||||
#define CS_AUGSG552_ZOOM 0x37
|
#define CS_AUGSG552_ZOOM 0x37
|
||||||
#define CS_NO_ZOOM 0x5A
|
#define CS_NO_ZOOM 0x5A
|
||||||
|
|
||||||
|
#define HAS_SHIELD (1<<24) //16777216
|
||||||
|
|
||||||
|
|
||||||
enum CS_Internal_Models {
|
enum CS_Internal_Models {
|
||||||
CS_DONTCHANGE = 0,
|
CS_DONTCHANGE = 0,
|
||||||
CS_CT_URBAN = 1,
|
CS_CT_URBAN = 1,
|
||||||
|
@ -293,57 +346,5 @@ enum
|
||||||
CS_SET_SECOND_ZOOM,
|
CS_SET_SECOND_ZOOM,
|
||||||
CS_SET_AUGSG552_ZOOM,
|
CS_SET_AUGSG552_ZOOM,
|
||||||
};
|
};
|
||||||
// cstrike-specific defines above
|
|
||||||
|
|
||||||
extern CCstrikePlayer g_players[33];
|
|
||||||
extern int g_zooming[33];
|
|
||||||
extern bool g_precachedknife;
|
|
||||||
extern bool g_noknives;
|
|
||||||
// Globals above
|
|
||||||
|
|
||||||
void InitializeHacks();
|
|
||||||
void ShutdownHacks();
|
|
||||||
|
|
||||||
#define CHECK_ENTITY(x) \
|
|
||||||
if (x < 0 || x > gpGlobals->maxEntities) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \
|
|
||||||
return 0; \
|
|
||||||
} else { \
|
|
||||||
if (x <= gpGlobals->maxClients) { \
|
|
||||||
if (!MF_IsPlayerIngame(x)) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d (not in-game)", x); \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
if (x != 0 && FNullEnt(INDEXENT(x))) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK_PLAYER(x) \
|
|
||||||
if (x < 1 || x > gpGlobals->maxClients) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Player out of range (%d)", x); \
|
|
||||||
return 0; \
|
|
||||||
} else { \
|
|
||||||
if (!MF_IsPlayerIngame(x) || FNullEnt(MF_GetPlayerEdict(x))) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", x); \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK_NONPLAYER(x) \
|
|
||||||
if (x < 1 || x <= gpGlobals->maxClients || x > gpGlobals->maxEntities) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Non-player entity %d out of range", x); \
|
|
||||||
return 0; \
|
|
||||||
} else { \
|
|
||||||
if (FNullEnt(INDEXENT(x))) { \
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid non-player entity %d", x); \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GETEDICT(n) \
|
|
||||||
((n >= 1 && n <= gpGlobals->maxClients) ? MF_GetPlayerEdict(n) : INDEXENT(n))
|
|
||||||
|
|
||||||
|
#endif // CSTRIKE_DATA_H
|
|
@ -1,237 +1,219 @@
|
||||||
#include <assert.h>
|
/* AMX Mod X
|
||||||
#include <stdlib.h>
|
* Counter-Strike Module
|
||||||
#include "cstrike.h"
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
*
|
||||||
|
* This file is part of AMX Mod X.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
#include "CstrikeDatas.h"
|
||||||
|
#include "CstrikeUtils.h"
|
||||||
|
#include "CDetour/detours.h"
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
void CtrlDetours_ClientCommand(bool set);
|
||||||
#include <sys/mman.h>
|
void CtrlDetours_BuyCommands(bool set);
|
||||||
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
|
||||||
|
|
||||||
#if defined(__linux)
|
|
||||||
#include <malloc.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
#include <mach-o/nlist.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Utils */
|
|
||||||
unsigned char *UTIL_CodeAlloc(size_t size);
|
|
||||||
void UTIL_CodeFree(unsigned char *addr);
|
|
||||||
void UTIL_MemProtect(void *addr, int length, int prot);
|
|
||||||
bool UTIL_GetLibraryOfAddress(void *memInBase, char *buffer, size_t maxlength, uintptr_t *base);
|
|
||||||
|
|
||||||
/* Detours */
|
|
||||||
void CtrlDetour_ClientCommand(bool set);
|
|
||||||
int Detour_ClientCommand(edict_t *pEdict);
|
|
||||||
|
|
||||||
int g_CSCliCmdFwd = -1;
|
int g_CSCliCmdFwd = -1;
|
||||||
|
int g_CSBuyCmdFwd = -1;
|
||||||
|
|
||||||
int *g_UseBotArgs = NULL;
|
int *g_UseBotArgs = NULL;
|
||||||
const char **g_BotArgs = NULL;
|
const char **g_BotArgs = NULL;
|
||||||
|
|
||||||
/* Called on startup */
|
CDetour *g_ClientCommandDetour = NULL;
|
||||||
|
CDetour *g_CanBuyThisDetour = NULL;
|
||||||
|
CDetour *g_BuyItemDetour = NULL;
|
||||||
|
CDetour *g_BuyGunAmmoDetour = NULL;
|
||||||
|
|
||||||
|
|
||||||
void InitializeHacks()
|
void InitializeHacks()
|
||||||
{
|
{
|
||||||
CtrlDetour_ClientCommand(true);
|
#if defined AMD64
|
||||||
}
|
#error UNSUPPORTED
|
||||||
|
#endif
|
||||||
|
|
||||||
void OnPluginsLoaded()
|
CtrlDetours_ClientCommand(true);
|
||||||
{
|
CtrlDetours_BuyCommands(true);
|
||||||
g_CSCliCmdFwd = MF_RegisterForward("CS_InternalCommand", ET_STOP, FP_CELL, FP_STRING, FP_DONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownHacks()
|
void ShutdownHacks()
|
||||||
{
|
{
|
||||||
CtrlDetour_ClientCommand(false);
|
CtrlDetours_ClientCommand(false);
|
||||||
|
CtrlDetours_BuyCommands(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CtrlDetour_ClientCommand(bool set)
|
|
||||||
{
|
|
||||||
#if defined AMD64
|
|
||||||
#error UNSUPPORTED
|
|
||||||
#endif
|
|
||||||
static unsigned char DetourOps[] =
|
|
||||||
{
|
|
||||||
0x50, /* push eax ; just for safety */
|
|
||||||
0xff, 0x74, 0x24, 0x08, /* push [esp+0x8] ; push the edict pointer */
|
|
||||||
0xe8, 0x00, 0x00, 0x00, 0x00, /* call <gate> ; call our function */
|
|
||||||
0x83, 0xc4, 0x08, /* add esp, 8 ; correct stack */
|
|
||||||
0x85, 0xc0, /* test eax, eax ; do != 0 test */
|
|
||||||
0x74, 0x01, /* je <cont> ; if == 0, jump to where old func is saved */
|
|
||||||
0xc3 /* ret ; return otherwise */
|
|
||||||
};
|
|
||||||
static unsigned char DetourJmp = '\xE9';
|
|
||||||
|
|
||||||
const unsigned int DetourBytes = 18;
|
DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity)
|
||||||
const unsigned int DetourCallPos = 6;
|
|
||||||
const unsigned int DetourJmpPos = DetourBytes + CS_DETOURCOPYBYTES_CLIENTCOMMAND;
|
|
||||||
const unsigned int DetourJmpBytes = 5;
|
|
||||||
static unsigned char *FullDetour = NULL;
|
|
||||||
|
|
||||||
void *target = (void *)MDLL_ClientCommand;
|
|
||||||
unsigned char *paddr;
|
|
||||||
|
|
||||||
if (!g_UseBotArgs)
|
|
||||||
{
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
/* Find the DLL */
|
|
||||||
char dll[256];
|
|
||||||
uintptr_t base;
|
|
||||||
if (!UTIL_GetLibraryOfAddress(target, dll, sizeof(dll), &base))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if defined(__linux__)
|
|
||||||
void *handle = dlopen(dll, RTLD_NOW);
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g_UseBotArgs = (int *)dlsym(handle, "UseBotArgs");
|
|
||||||
g_BotArgs = (const char **)dlsym(handle, "BotArgs");
|
|
||||||
dlclose(handle);
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
/* Using dlsym on OS X won't work because the symbols are hidden */
|
|
||||||
struct nlist symbols[3];
|
|
||||||
memset(symbols, 0, sizeof(symbols));
|
|
||||||
symbols[0].n_un.n_name = (char *)"_UseBotArgs";
|
|
||||||
symbols[1].n_un.n_name = (char *)"_BotArgs";
|
|
||||||
if (nlist(dll, symbols) != 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g_UseBotArgs = (int *)(base + symbols[0].n_value);
|
|
||||||
g_BotArgs = (const char **)(base + symbols[1].n_value);
|
|
||||||
#endif
|
|
||||||
#else /* Windows */
|
|
||||||
/* Find the bot args addresses */
|
|
||||||
paddr = (unsigned char *)target + CS_CLICMD_OFFS_USEBOTARGS;
|
|
||||||
g_UseBotArgs = *(int **)paddr;
|
|
||||||
paddr = (unsigned char *)target + CS_CLICMD_OFFS_BOTARGS;
|
|
||||||
g_BotArgs = (const char **)*(const char **)paddr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set)
|
|
||||||
{
|
|
||||||
assert(FullDetour == NULL);
|
|
||||||
FullDetour = UTIL_CodeAlloc(DetourBytes + CS_DETOURCOPYBYTES_CLIENTCOMMAND + DetourJmpBytes);
|
|
||||||
|
|
||||||
/* Copy the main trampoline function */
|
|
||||||
memcpy(FullDetour, DetourOps, DetourBytes);
|
|
||||||
|
|
||||||
/* Copy our detour call into the trampoline */
|
|
||||||
paddr = &FullDetour[DetourCallPos];
|
|
||||||
*(unsigned long *)paddr = (unsigned long)Detour_ClientCommand - (unsigned long)(paddr + 4);
|
|
||||||
|
|
||||||
/* Copy original bytes onto the end of the function */
|
|
||||||
memcpy(&FullDetour[DetourBytes], target, CS_DETOURCOPYBYTES_CLIENTCOMMAND);
|
|
||||||
|
|
||||||
/* Patch and copy the final jmp */
|
|
||||||
paddr = &FullDetour[DetourJmpPos];
|
|
||||||
*paddr++ = DetourJmp;
|
|
||||||
*(unsigned long *)paddr = ((unsigned long)target + CS_DETOURCOPYBYTES_CLIENTCOMMAND)
|
|
||||||
- (unsigned long)(paddr + 4);
|
|
||||||
|
|
||||||
/* Now overwrite the target function with our trampoline */
|
|
||||||
UTIL_MemProtect(target, CS_DETOURCOPYBYTES_CLIENTCOMMAND + 10, PAGE_EXECUTE_READWRITE);
|
|
||||||
paddr = (unsigned char *)target;
|
|
||||||
*paddr++ = DetourJmp;
|
|
||||||
*(unsigned long *)paddr = (unsigned long)FullDetour - (unsigned long)(paddr + 4);
|
|
||||||
} else {
|
|
||||||
assert(FullDetour != NULL);
|
|
||||||
|
|
||||||
/* Copy back the original function bytes */
|
|
||||||
memcpy(target, &FullDetour[DetourBytes], CS_DETOURCOPYBYTES_CLIENTCOMMAND);
|
|
||||||
|
|
||||||
/* Free memory used */
|
|
||||||
UTIL_CodeFree(FullDetour);
|
|
||||||
FullDetour = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Detour_ClientCommand(edict_t *pEdict)
|
|
||||||
{
|
{
|
||||||
if (*g_UseBotArgs)
|
if (*g_UseBotArgs)
|
||||||
{
|
{
|
||||||
int client = ENTINDEX(pEdict);
|
int client = ENTINDEX(pEdict);
|
||||||
const char *args = *g_BotArgs;
|
const char *args = *g_BotArgs;
|
||||||
return MF_ExecuteForward(g_CSCliCmdFwd, (cell)client, args);
|
|
||||||
|
if (MF_ExecuteForward(g_CSCliCmdFwd, static_cast<cell>(client), args) > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
DETOUR_STATIC_CALL(C_ClientCommand)(pEdict);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *UTIL_CodeAlloc(size_t size)
|
DETOUR_DECL_STATIC2(CanBuyThis, bool, void*, pvPlayer, int, weaponId) // bool CanBuyThis(CBasePlayer *pPlayer, int weaponId)
|
||||||
{
|
{
|
||||||
#if defined WIN32
|
if (weaponId != CSI_SHIELDGUN) // This will be handled before with BuyItem. Avoiding duplicated call.
|
||||||
return (unsigned char *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
{
|
||||||
#elif defined __GNUC__
|
int player = PrivateToIndex(pvPlayer);
|
||||||
#if defined __APPLE__
|
|
||||||
unsigned char *addr = (unsigned char *)valloc(size);
|
if (MF_IsPlayerAlive(player) && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(weaponId)) > 0)
|
||||||
#else
|
{
|
||||||
unsigned char *addr = (unsigned char *)memalign(sysconf(_SC_PAGESIZE), size);
|
return false;
|
||||||
#endif
|
}
|
||||||
mprotect(addr, size, PROT_READ|PROT_WRITE|PROT_EXEC);
|
}
|
||||||
return addr;
|
|
||||||
#endif
|
return DETOUR_STATIC_CALL(CanBuyThis)(pvPlayer, weaponId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UTIL_CodeFree(unsigned char *addr)
|
DETOUR_DECL_STATIC2(BuyItem, void, void*, pvPlayer, int, iSlot) // void BuyItem(CBasePlayer *pPlayer, int iSlot)
|
||||||
{
|
{
|
||||||
#if defined WIN32
|
int player = PrivateToIndex(pvPlayer);
|
||||||
VirtualFree(addr, 0, MEM_RELEASE);
|
|
||||||
#else
|
if (MF_IsPlayerAlive(player))
|
||||||
free(addr);
|
{
|
||||||
#endif
|
static const int itemSlotToWeaponId[] = {-1, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, CSI_DEFUSER, CSI_SHIELDGUN};
|
||||||
|
|
||||||
|
if (iSlot >= 1 && iSlot <= 8 && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(itemSlotToWeaponId[iSlot])) > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DETOUR_STATIC_CALL(BuyItem)(pvPlayer, iSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UTIL_MemProtect(void *addr, int length, int prot)
|
DETOUR_DECL_STATIC3(BuyGunAmmo, bool, void*, pvPlayer, void*, pvWeapon, bool, bBlinkMoney) // bool BuyGunAmmo(CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney)
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
int player = PrivateToIndex(pvPlayer);
|
||||||
#define ALIGN(ar) ((long)ar & ~(sysconf(_SC_PAGESIZE)-1))
|
|
||||||
void *addr2 = (void *)ALIGN(addr);
|
if (MF_IsPlayerAlive(player))
|
||||||
mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
|
{
|
||||||
#else
|
edict_t *pWeapon = PrivateToEdict(pvWeapon);
|
||||||
DWORD old_prot;
|
|
||||||
VirtualProtect(addr, length, prot, &old_prot);
|
if (pWeapon)
|
||||||
#endif
|
{
|
||||||
|
int weaponId = *((int *)pWeapon->pvPrivateData + OFFSET_WEAPONTYPE);
|
||||||
|
int ammoId = (1<<weaponId & BITS_PISTOLS) ? CSI_SECAMMO : CSI_PRIMAMMO;
|
||||||
|
|
||||||
|
if (MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(ammoId)) > 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DETOUR_STATIC_CALL(BuyGunAmmo)(pvPlayer, pvWeapon, bBlinkMoney);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UTIL_GetLibraryOfAddress(void *memInBase, char *buffer, size_t maxlength, uintptr_t *base)
|
|
||||||
|
void CtrlDetours_ClientCommand(bool set)
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
if (set)
|
||||||
Dl_info info;
|
|
||||||
if (!dladdr(memInBase, &info))
|
|
||||||
{
|
{
|
||||||
return false;
|
void *target = (void *)MDLL_ClientCommand;
|
||||||
}
|
|
||||||
if (!info.dli_fbase || !info.dli_fname)
|
#if defined(WIN32)
|
||||||
{
|
|
||||||
return false;
|
g_UseBotArgs = *(int **)((unsigned char *)target + CS_CLICMD_OFFS_USEBOTARGS);
|
||||||
}
|
g_BotArgs = (const char **)*(const char **)((unsigned char *)target + CS_CLICMD_OFFS_BOTARGS);
|
||||||
const char *dllpath = info.dli_fname;
|
|
||||||
snprintf(buffer, maxlength, "%s", dllpath);
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
if (base)
|
|
||||||
{
|
g_UseBotArgs = (int *)UTIL_FindAddressFromEntry(CS_IDENT_USEBOTARGS, CS_IDENT_HIDDEN_STATE);
|
||||||
*base = (uintptr_t)info.dli_fbase;
|
g_BotArgs = (const char **)UTIL_FindAddressFromEntry(CS_IDENT_BOTARGS, CS_IDENT_HIDDEN_STATE);
|
||||||
}
|
|
||||||
#else
|
|
||||||
MEMORY_BASIC_INFORMATION mem;
|
|
||||||
if (!VirtualQuery(memInBase, &mem, sizeof(mem)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mem.AllocationBase == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
HMODULE dll = (HMODULE)mem.AllocationBase;
|
|
||||||
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
|
|
||||||
if (base)
|
|
||||||
{
|
|
||||||
*base = (uintptr_t)mem.AllocationBase;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
g_ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, target);
|
||||||
|
|
||||||
|
if (g_ClientCommandDetour == NULL)
|
||||||
|
{
|
||||||
|
MF_Log("No Client Commands detour could be initialized - Disabled Client Command forward.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_ClientCommandDetour)
|
||||||
|
g_ClientCommandDetour->Destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ToggleDetour_ClientCommands(bool enable)
|
||||||
|
{
|
||||||
|
if (g_ClientCommandDetour)
|
||||||
|
(enable) ? g_ClientCommandDetour->EnableDetour() : g_ClientCommandDetour->DisableDetour();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CtrlDetours_BuyCommands(bool set)
|
||||||
|
{
|
||||||
|
if (set)
|
||||||
|
{
|
||||||
|
void *canBuyThisAddress = UTIL_FindAddressFromEntry(CS_IDENT_CANBUYTHIS, CS_IDENT_HIDDEN_STATE);
|
||||||
|
void *buyItemAddress = UTIL_FindAddressFromEntry(CS_IDENT_BUYITEM, CS_IDENT_HIDDEN_STATE);
|
||||||
|
void *buyGunAmmoAddress = UTIL_FindAddressFromEntry(CS_IDENT_BUYGUNAMMO, CS_IDENT_HIDDEN_STATE);
|
||||||
|
|
||||||
|
g_CanBuyThisDetour = DETOUR_CREATE_STATIC_FIXED(CanBuyThis, canBuyThisAddress);
|
||||||
|
g_BuyItemDetour = DETOUR_CREATE_STATIC_FIXED(BuyItem, buyItemAddress);
|
||||||
|
g_BuyGunAmmoDetour = DETOUR_CREATE_STATIC_FIXED(BuyGunAmmo, buyGunAmmoAddress);
|
||||||
|
|
||||||
|
if (g_CanBuyThisDetour == NULL || g_BuyItemDetour == NULL || g_BuyGunAmmoDetour == NULL)
|
||||||
|
{
|
||||||
|
MF_Log("No Buy Commands detours could be initialized - Disabled Buy forward.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_CanBuyThisDetour)
|
||||||
|
g_CanBuyThisDetour->Destroy();
|
||||||
|
|
||||||
|
if (g_BuyItemDetour)
|
||||||
|
g_BuyItemDetour->Destroy();
|
||||||
|
|
||||||
|
if (g_BuyGunAmmoDetour)
|
||||||
|
g_BuyGunAmmoDetour->Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleDetour_BuyCommands(bool enable)
|
||||||
|
{
|
||||||
|
if (g_CanBuyThisDetour)
|
||||||
|
(enable) ? g_CanBuyThisDetour->EnableDetour() : g_CanBuyThisDetour->DisableDetour();
|
||||||
|
|
||||||
|
if (g_BuyItemDetour)
|
||||||
|
(enable) ? g_BuyItemDetour->EnableDetour() : g_BuyItemDetour->DisableDetour();
|
||||||
|
|
||||||
|
if (g_BuyGunAmmoDetour)
|
||||||
|
(enable) ? g_BuyGunAmmoDetour->EnableDetour() : g_BuyGunAmmoDetour->DisableDetour();
|
||||||
|
}
|
126
dlls/cstrike/cstrike/cstrike.cpp → dlls/cstrike/cstrike/CstrikeNatives.cpp
Executable file → Normal file
126
dlls/cstrike/cstrike/cstrike.cpp → dlls/cstrike/cstrike/CstrikeNatives.cpp
Executable file → Normal file
|
@ -1,72 +1,44 @@
|
||||||
#include "cstrike.h"
|
/* AMX Mod X
|
||||||
|
* Counter-Strike Module
|
||||||
/* AMX Mod X
|
*
|
||||||
* Counter-Strike Module
|
* by the AMX Mod X Development Team
|
||||||
*
|
*
|
||||||
* by the AMX Mod X Development Team
|
* This file is part of AMX Mod X.
|
||||||
*
|
*
|
||||||
* This file is part of AMX Mod X.
|
*
|
||||||
*
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
*
|
* under the terms of the GNU General Public License as published by the
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
* under the terms of the GNU General Public License as published by the
|
* your option) any later version.
|
||||||
* Free Software Foundation; either version 2 of the License, or (at
|
*
|
||||||
* your option) any later version.
|
* This program is distributed in the hope that it will be useful, but
|
||||||
*
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* General Public License for more details.
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
*
|
||||||
* General Public License for more details.
|
* You should have received a copy of the GNU General Public License
|
||||||
*
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* You should have received a copy of the GNU General Public License
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
*
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* In addition, as a special exception, the author gives permission to
|
||||||
*
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
* In addition, as a special exception, the author gives permission to
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
* you do not wish to do so, delete this exception statement from your
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
* version.
|
||||||
* you do not wish to do so, delete this exception statement from your
|
*/
|
||||||
* version.
|
#include "CstrikeDatas.h"
|
||||||
*/
|
#include "CstrikePlayer.h"
|
||||||
|
#include "CstrikeUtils.h"
|
||||||
|
|
||||||
CCstrikePlayer g_players[33];
|
CCstrikePlayer g_players[33];
|
||||||
int g_zooming[33] = {0};
|
int g_zooming[33] = {0};
|
||||||
bool g_precachedknife = false;
|
bool g_precachedknife = false;
|
||||||
bool g_noknives = false;
|
bool g_noknives = false;
|
||||||
|
|
||||||
// Utils first
|
|
||||||
|
|
||||||
bool UTIL_IsPlayer(AMX* amx, edict_t* pPlayer) {
|
|
||||||
bool player = false;
|
|
||||||
|
|
||||||
if (strcmp(STRING(pPlayer->v.classname), "player") == 0)
|
|
||||||
player = true;
|
|
||||||
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UTIL_TextMsg_Generic(edict_t* pPlayer, const char* message)
|
|
||||||
{
|
|
||||||
MESSAGE_BEGIN(MSG_ONE, GET_USER_MSG_ID(PLID, "TextMsg", NULL), NULL, pPlayer);
|
|
||||||
WRITE_BYTE(HUD_PRINTCENTER); // 1 = console, 2 = console, 3 = chat, 4 = center
|
|
||||||
WRITE_STRING(message);
|
|
||||||
MESSAGE_END();
|
|
||||||
/*
|
|
||||||
The byte above seems to use these:
|
|
||||||
#define HUD_PRINTNOTIFY 1
|
|
||||||
#define HUD_PRINTCONSOLE 2
|
|
||||||
#define HUD_PRINTTALK 3
|
|
||||||
#define HUD_PRINTCENTER 4
|
|
||||||
However both 1 and 2 seems to go to console with Steam CS.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then natives
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL cs_set_user_money(AMX *amx, cell *params) // cs_set_user_money(index, money, flash = 1); = 3 arguments
|
static cell AMX_NATIVE_CALL cs_set_user_money(AMX *amx, cell *params) // cs_set_user_money(index, money, flash = 1); = 3 arguments
|
||||||
{
|
{
|
||||||
// Give money to user
|
// Give money to user
|
||||||
|
@ -1339,8 +1311,8 @@ static cell AMX_NATIVE_CALL cs_user_spawn(AMX *amx, cell *params)
|
||||||
MDLL_Think(pPlayer);
|
MDLL_Think(pPlayer);
|
||||||
|
|
||||||
const char *auth = GETPLAYERAUTHID(pPlayer);
|
const char *auth = GETPLAYERAUTHID(pPlayer);
|
||||||
if (((pPlayer->v.flags & FL_FAKECLIENT) == FL_FAKECLIENT || (auth && (strcmp(auth, "BOT") == 0))) && pPlayer->v.deadflag == DEAD_RESPAWNABLE) {
|
if (((pPlayer->v.flags & FL_FAKECLIENT) == FL_FAKECLIENT || (auth && (strcmp(auth, "BOT") == 0))) && pPlayer->v.deadflag == DEAD_RESPAWNABLE) {
|
||||||
MDLL_Spawn(pPlayer);
|
MDLL_Spawn(pPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pPlayer->v.iuser1 = 0;
|
// pPlayer->v.iuser1 = 0;
|
||||||
|
@ -1777,7 +1749,7 @@ static cell AMX_NATIVE_CALL not_on_64(AMX* amx, cell* params)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
AMX_NATIVE_INFO cstrike_Exports[] = {
|
AMX_NATIVE_INFO cstrikeNatives[] = {
|
||||||
{"cs_set_user_money", cs_set_user_money},
|
{"cs_set_user_money", cs_set_user_money},
|
||||||
{"cs_get_user_money", cs_get_user_money},
|
{"cs_get_user_money", cs_get_user_money},
|
||||||
{"cs_get_user_deaths", cs_get_user_deaths},
|
{"cs_get_user_deaths", cs_get_user_deaths},
|
||||||
|
@ -1918,24 +1890,4 @@ void PlayerPreThink(edict_t *pPlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AmxxCheckGame(const char *game)
|
|
||||||
{
|
|
||||||
if (strcasecmp(game, "cstrike") == 0 ||
|
|
||||||
strcasecmp(game, "czero") == 0)
|
|
||||||
{
|
|
||||||
return AMXX_GAME_OK;
|
|
||||||
}
|
|
||||||
return AMXX_GAME_BAD;
|
|
||||||
}
|
|
||||||
void OnAmxxAttach()
|
|
||||||
{
|
|
||||||
MF_AddNatives(cstrike_Exports);
|
|
||||||
InitializeHacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnAmxxDetach()
|
|
||||||
{
|
|
||||||
ShutdownHacks();
|
|
||||||
}
|
|
142
dlls/cstrike/cstrike/CstrikeUtils.cpp
Normal file
142
dlls/cstrike/cstrike/CstrikeUtils.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/* AMX Mod X
|
||||||
|
* Counter-Strike Module
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
*
|
||||||
|
* This file is part of AMX Mod X.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
#include "amxxmodule.h"
|
||||||
|
#include "MemoryUtils.h"
|
||||||
|
|
||||||
|
bool UTIL_IsPlayer(AMX* amx, edict_t* pPlayer)
|
||||||
|
{
|
||||||
|
bool player = false;
|
||||||
|
|
||||||
|
if (strcmp(STRING(pPlayer->v.classname), "player") == 0)
|
||||||
|
{
|
||||||
|
player = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UTIL_TextMsg_Generic(edict_t* pPlayer, const char* message)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_ONE, GET_USER_MSG_ID(PLID, "TextMsg", NULL), NULL, pPlayer);
|
||||||
|
WRITE_BYTE(HUD_PRINTCENTER); // 1 = console, 2 = console, 3 = chat, 4 = center, 5 = radio
|
||||||
|
WRITE_STRING(message);
|
||||||
|
MESSAGE_END();
|
||||||
|
/*
|
||||||
|
The byte above seems to use these:
|
||||||
|
#define HUD_PRINTNOTIFY 1
|
||||||
|
#define HUD_PRINTCONSOLE 2
|
||||||
|
#define HUD_PRINTTALK 3
|
||||||
|
#define HUD_PRINTCENTER 4
|
||||||
|
#define HUD_PRINTRADIO 5
|
||||||
|
However both 1 and 2 seems to go to console with Steam CS.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void *UTIL_FindAddressFromEntry(const char *entry, bool isHidden, const char *library)
|
||||||
|
{
|
||||||
|
void *addressInBase = NULL;
|
||||||
|
void *finalAddress;
|
||||||
|
|
||||||
|
if (strcmp(library, "mod") == 0)
|
||||||
|
{
|
||||||
|
addressInBase = (void *)MDLL_Spawn;
|
||||||
|
}
|
||||||
|
else if (strcmp(library, "engine") == 0)
|
||||||
|
{
|
||||||
|
addressInBase = (void *)gpGlobals;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalAddress = NULL;
|
||||||
|
|
||||||
|
if (*entry != '\\')
|
||||||
|
{
|
||||||
|
#if defined(WIN32)
|
||||||
|
|
||||||
|
MEMORY_BASIC_INFORMATION mem;
|
||||||
|
|
||||||
|
if (VirtualQuery(addressInBase, &mem, sizeof(mem)))
|
||||||
|
{
|
||||||
|
finalAddress = g_MemUtils.ResolveSymbol(mem.AllocationBase, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
|
|
||||||
|
Dl_info info;
|
||||||
|
void *handle = NULL;
|
||||||
|
|
||||||
|
if (dladdr(addressInBase, &info) != 0)
|
||||||
|
{
|
||||||
|
void *handle = dlopen(info.dli_fname, RTLD_NOW);
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
if (isHidden)
|
||||||
|
{
|
||||||
|
finalAddress = g_MemUtils.ResolveSymbol(handle, entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finalAddress = dlsym(handle, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
dlclose(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finalAddress = g_MemUtils.DecodeAndFindPattern(addressInBase, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalAddress != NULL ? finalAddress : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UTIL_CheckForPublic(const char *publicname)
|
||||||
|
{
|
||||||
|
AMX* amx;
|
||||||
|
int iFunctionIndex;
|
||||||
|
int i = 0;
|
||||||
|
char blah[64];
|
||||||
|
|
||||||
|
strncpy(blah, publicname, sizeof(blah)- 1);
|
||||||
|
|
||||||
|
while ((amx = MF_GetScriptAmx(i++)) != NULL)
|
||||||
|
{
|
||||||
|
if (MF_AmxFindPublic(amx, blah, &iFunctionIndex) == AMX_ERR_NONE)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
121
dlls/cstrike/cstrike/CstrikeUtils.h
Normal file
121
dlls/cstrike/cstrike/CstrikeUtils.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/* AMX Mod X
|
||||||
|
* Counter-Strike Module
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
*
|
||||||
|
* This file is part of AMX Mod X.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
#ifndef CSTRIKE_UTILS_H
|
||||||
|
#define CSTRIKE_UTILS_H
|
||||||
|
|
||||||
|
bool UTIL_IsPlayer(AMX* amx, edict_t* pPlayer);
|
||||||
|
void UTIL_TextMsg_Generic(edict_t* pPlayer, const char* message);
|
||||||
|
void *UTIL_FindAddressFromEntry(const char *entry, bool isHidden = false, const char *library = "mod");
|
||||||
|
bool UTIL_CheckForPublic(const char *publicname);
|
||||||
|
|
||||||
|
#define GETINFOKEYBUFFER (*g_engfuncs.pfnGetInfoKeyBuffer)
|
||||||
|
#define SETCLIENTKEYVALUE (*g_engfuncs.pfnSetClientKeyValue)
|
||||||
|
#define GETCLIENTKEYVALUE (*g_engfuncs.pfnInfoKeyValue)
|
||||||
|
#define CREATENAMEDENTITY (*g_engfuncs.pfnCreateNamedEntity)
|
||||||
|
|
||||||
|
#define CHECK_ENTITY(x) \
|
||||||
|
if (x < 0 || x > gpGlobals->maxEntities) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \
|
||||||
|
return 0; \
|
||||||
|
} else { \
|
||||||
|
if (x <= gpGlobals->maxClients) { \
|
||||||
|
if (!MF_IsPlayerIngame(x)) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d (not in-game)", x); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
if (x != 0 && FNullEnt(INDEXENT(x))) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_PLAYER(x) \
|
||||||
|
if (x < 1 || x > gpGlobals->maxClients) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Player out of range (%d)", x); \
|
||||||
|
return 0; \
|
||||||
|
} else { \
|
||||||
|
if (!MF_IsPlayerIngame(x) || FNullEnt(MF_GetPlayerEdict(x))) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", x); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_NONPLAYER(x) \
|
||||||
|
if (x < 1 || x <= gpGlobals->maxClients || x > gpGlobals->maxEntities) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Non-player entity %d out of range", x); \
|
||||||
|
return 0; \
|
||||||
|
} else { \
|
||||||
|
if (FNullEnt(INDEXENT(x))) { \
|
||||||
|
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid non-player entity %d", x); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GETEDICT(n) \
|
||||||
|
((n >= 1 && n <= gpGlobals->maxClients) ? MF_GetPlayerEdict(n) : INDEXENT(n))
|
||||||
|
|
||||||
|
|
||||||
|
inline edict_t *PrivateToEdict(const void *pdata)
|
||||||
|
{
|
||||||
|
if (!pdata)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ptr = (char*)pdata;
|
||||||
|
ptr += 4;
|
||||||
|
entvars_t *pev = *(entvars_t **)ptr;
|
||||||
|
|
||||||
|
if (!pev)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pev->pContainingEntity;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline int PrivateToIndex(const void *pdata)
|
||||||
|
{
|
||||||
|
edict_t *pEntity = PrivateToEdict(pdata);
|
||||||
|
|
||||||
|
if (!pEntity)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ENTINDEX(pEntity);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CSTRIKE_UTILS_H
|
|
@ -14,7 +14,10 @@ MM_ROOT = ../../../../metamod/metamod
|
||||||
|
|
||||||
PROJECT = cstrike
|
PROJECT = cstrike
|
||||||
|
|
||||||
OBJECTS = sdk/amxxmodule.cpp CstrikePlayer.cpp cstrike.cpp CstrikeHacks.cpp
|
OBJECTS = sdk/amxxmodule.cpp amxx_api.cpp CstrikePlayer.cpp CstrikeNatives.cpp CstrikeHacks.cpp CstrikeUtils.cpp \
|
||||||
|
../../../public/memtools/MemoryUtils.cpp \
|
||||||
|
../../../public/memtools/CDetour/detours.cpp \
|
||||||
|
../../../public/memtools/CDetour/asm/asm.c
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||||
|
@ -29,7 +32,7 @@ CPP_OSX = clang
|
||||||
|
|
||||||
LINK =
|
LINK =
|
||||||
|
|
||||||
INCLUDE = -I. -I$(HLSDK) -I$(HLSDK)/common -I$(HLSDK)/dlls -I$(HLSDK)/engine -I$(HLSDK)/game_shared \
|
INCLUDE = -I. -I../../../public -I../../../public/amtl -I$(HLSDK) -I$(HLSDK)/common -I$(HLSDK)/dlls -I$(HLSDK)/engine -I$(HLSDK)/game_shared \
|
||||||
-I$(HLSDK)/public -I$(MM_ROOT) -Isdk
|
-I$(HLSDK)/public -I$(MM_ROOT) -Isdk
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
|
|
75
dlls/cstrike/cstrike/amxx_api.cpp
Normal file
75
dlls/cstrike/cstrike/amxx_api.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* AMX Mod X
|
||||||
|
* Counter-Strike Module
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
*
|
||||||
|
* This file is part of AMX Mod X.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
#include "amxxmodule.h"
|
||||||
|
#include "CstrikeUtils.h"
|
||||||
|
|
||||||
|
extern AMX_NATIVE_INFO cstrikeNatives[];
|
||||||
|
|
||||||
|
extern int g_CSCliCmdFwd;
|
||||||
|
extern int g_CSBuyCmdFwd;
|
||||||
|
|
||||||
|
void InitializeHacks();
|
||||||
|
void ShutdownHacks();
|
||||||
|
void ToggleDetour_ClientCommands(bool enable);
|
||||||
|
void ToggleDetour_BuyCommands(bool enable);
|
||||||
|
|
||||||
|
|
||||||
|
int AmxxCheckGame(const char *game)
|
||||||
|
{
|
||||||
|
if (strcasecmp(game, "cstrike") == 0 ||
|
||||||
|
strcasecmp(game, "czero") == 0)
|
||||||
|
{
|
||||||
|
return AMXX_GAME_OK;
|
||||||
|
}
|
||||||
|
return AMXX_GAME_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAmxxAttach()
|
||||||
|
{
|
||||||
|
MF_AddNatives(cstrikeNatives);
|
||||||
|
InitializeHacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPluginsLoaded()
|
||||||
|
{
|
||||||
|
g_CSCliCmdFwd = MF_RegisterForward("CS_InternalCommand", ET_STOP, FP_CELL, FP_STRING, FP_DONE);
|
||||||
|
g_CSBuyCmdFwd = MF_RegisterForward("CS_OnBuy", ET_STOP, FP_CELL, FP_CELL, FP_DONE);
|
||||||
|
|
||||||
|
ToggleDetour_ClientCommands(UTIL_CheckForPublic("CS_InternalCommand"));
|
||||||
|
ToggleDetour_BuyCommands(UTIL_CheckForPublic("CS_OnBuy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAmxxDetach()
|
||||||
|
{
|
||||||
|
ShutdownHacks();
|
||||||
|
}
|
|
@ -62,7 +62,7 @@
|
||||||
</Midl>
|
</Midl>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\;..\sdk;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\;..\..\..\..\public; ..\..\..\..\public\amtl;..\..\..\..\public\memtools;..\sdk;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
<AdditionalIncludeDirectories>..\;..\sdk;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\;..\..\..\..\public; ..\..\..\..\public\amtl;..\..\..\..\public\memtools;..\sdk;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<StringPooling>true</StringPooling>
|
<StringPooling>true</StringPooling>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
@ -135,20 +135,29 @@
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\cstrike.cpp" />
|
<ClCompile Include="..\..\..\..\public\memtools\CDetour\asm\asm.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\public\memtools\CDetour\detours.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\..\public\memtools\MemoryUtils.cpp" />
|
||||||
|
<ClCompile Include="..\amxx_api.cpp" />
|
||||||
<ClCompile Include="..\CstrikeHacks.cpp" />
|
<ClCompile Include="..\CstrikeHacks.cpp" />
|
||||||
|
<ClCompile Include="..\CstrikeNatives.cpp" />
|
||||||
<ClCompile Include="..\CstrikePlayer.cpp" />
|
<ClCompile Include="..\CstrikePlayer.cpp" />
|
||||||
|
<ClCompile Include="..\CstrikeUtils.cpp" />
|
||||||
<ClCompile Include="..\sdk\amxxmodule.cpp" />
|
<ClCompile Include="..\sdk\amxxmodule.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\cstrike.h" />
|
<ClInclude Include="..\..\..\..\public\memtools\CDetour\asm\asm.h" />
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\CDetour\detourhelpers.h" />
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\CDetour\detours.h" />
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\MemoryUtils.h" />
|
||||||
|
<ClInclude Include="..\CstrikeDatas.h" />
|
||||||
<ClInclude Include="..\CstrikePlayer.h" />
|
<ClInclude Include="..\CstrikePlayer.h" />
|
||||||
<ClInclude Include="..\svn_version.h" />
|
|
||||||
<ClInclude Include="..\sdk\moduleconfig.h" />
|
<ClInclude Include="..\sdk\moduleconfig.h" />
|
||||||
<ClInclude Include="..\sdk\amxxmodule.h" />
|
<ClInclude Include="..\sdk\amxxmodule.h" />
|
||||||
|
<ClInclude Include="..\CstrikeUtils.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\..\plugins\include\cstrike.inc" />
|
<None Include="..\..\..\..\plugins\include\cstrike.inc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
@ -18,11 +18,17 @@
|
||||||
<Filter Include="Pawn Includes">
|
<Filter Include="Pawn Includes">
|
||||||
<UniqueIdentifier>{7be12e0f-47b1-4d7e-880c-83e5d1c378d1}</UniqueIdentifier>
|
<UniqueIdentifier>{7be12e0f-47b1-4d7e-880c-83e5d1c378d1}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Memtools">
|
||||||
|
<UniqueIdentifier>{bbcd1d67-4670-423d-912f-695737e76bad}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Memtools\CDetour">
|
||||||
|
<UniqueIdentifier>{074d4da1-d1be-40ba-8417-1fc388d85568}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Memtools\CDetour\asm">
|
||||||
|
<UniqueIdentifier>{4f3c4a13-065a-49b1-83a1-f646a3ec3678}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\cstrike.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\CstrikeHacks.cpp">
|
<ClCompile Include="..\CstrikeHacks.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -32,26 +38,56 @@
|
||||||
<ClCompile Include="..\sdk\amxxmodule.cpp">
|
<ClCompile Include="..\sdk\amxxmodule.cpp">
|
||||||
<Filter>Module SDK\SDK Base</Filter>
|
<Filter>Module SDK\SDK Base</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\amxx_api.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\public\memtools\MemoryUtils.cpp">
|
||||||
|
<Filter>Memtools</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\public\memtools\CDetour\detours.cpp">
|
||||||
|
<Filter>Memtools\CDetour</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\public\memtools\CDetour\asm\asm.c">
|
||||||
|
<Filter>Memtools\CDetour\asm</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\CstrikeNatives.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\CstrikeUtils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\cstrike.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\CstrikePlayer.h">
|
<ClInclude Include="..\CstrikePlayer.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\svn_version.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\sdk\moduleconfig.h">
|
<ClInclude Include="..\sdk\moduleconfig.h">
|
||||||
<Filter>Module SDK</Filter>
|
<Filter>Module SDK</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\sdk\amxxmodule.h">
|
<ClInclude Include="..\sdk\amxxmodule.h">
|
||||||
<Filter>Module SDK\SDK Base</Filter>
|
<Filter>Module SDK\SDK Base</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\CstrikeDatas.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\MemoryUtils.h">
|
||||||
|
<Filter>Memtools</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\CDetour\detourhelpers.h">
|
||||||
|
<Filter>Memtools\CDetour</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\CDetour\detours.h">
|
||||||
|
<Filter>Memtools\CDetour</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\..\public\memtools\CDetour\asm\asm.h">
|
||||||
|
<Filter>Memtools\CDetour\asm</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\CstrikeUtils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\..\plugins\include\cstrike.inc">
|
<None Include="..\..\..\..\plugins\include\cstrike.inc">
|
||||||
<Filter>Pawn Includes</Filter>
|
<Filter>Pawn Includes</Filter>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -77,38 +77,39 @@
|
||||||
|
|
||||||
|
|
||||||
/* Id of weapons in CS */
|
/* Id of weapons in CS */
|
||||||
#define CSW_P228 1
|
#define CSW_P228 1
|
||||||
#define CSW_SCOUT 3
|
#define CSW_SCOUT 3
|
||||||
#define CSW_HEGRENADE 4
|
#define CSW_HEGRENADE 4
|
||||||
#define CSW_XM1014 5
|
#define CSW_XM1014 5
|
||||||
#define CSW_C4 6
|
#define CSW_C4 6
|
||||||
#define CSW_MAC10 7
|
#define CSW_MAC10 7
|
||||||
#define CSW_AUG 8
|
#define CSW_AUG 8
|
||||||
#define CSW_SMOKEGRENADE 9
|
#define CSW_SMOKEGRENADE 9
|
||||||
#define CSW_ELITE 10
|
#define CSW_ELITE 10
|
||||||
#define CSW_FIVESEVEN 11
|
#define CSW_FIVESEVEN 11
|
||||||
#define CSW_UMP45 12
|
#define CSW_UMP45 12
|
||||||
#define CSW_SG550 13
|
#define CSW_SG550 13
|
||||||
#define CSW_GALI 14
|
#define CSW_GALI 14
|
||||||
#define CSW_GALIL 14
|
#define CSW_GALIL 14
|
||||||
#define CSW_FAMAS 15
|
#define CSW_FAMAS 15
|
||||||
#define CSW_USP 16
|
#define CSW_USP 16
|
||||||
#define CSW_GLOCK18 17
|
#define CSW_GLOCK18 17
|
||||||
#define CSW_AWP 18
|
#define CSW_AWP 18
|
||||||
#define CSW_MP5NAVY 19
|
#define CSW_MP5NAVY 19
|
||||||
#define CSW_M249 20
|
#define CSW_M249 20
|
||||||
#define CSW_M3 21
|
#define CSW_M3 21
|
||||||
#define CSW_M4A1 22
|
#define CSW_M4A1 22
|
||||||
#define CSW_TMP 23
|
#define CSW_TMP 23
|
||||||
#define CSW_G3SG1 24
|
#define CSW_G3SG1 24
|
||||||
#define CSW_FLASHBANG 25
|
#define CSW_FLASHBANG 25
|
||||||
#define CSW_DEAGLE 26
|
#define CSW_DEAGLE 26
|
||||||
#define CSW_SG552 27
|
#define CSW_SG552 27
|
||||||
#define CSW_AK47 28
|
#define CSW_AK47 28
|
||||||
#define CSW_KNIFE 29
|
#define CSW_KNIFE 29
|
||||||
#define CSW_P90 30
|
#define CSW_P90 30
|
||||||
#define CSW_VEST 31
|
#define CSW_VEST 31 // Custom
|
||||||
#define CSW_VESTHELM 32
|
#define CSW_VESTHELM 32 // Custom
|
||||||
|
#define CSW_SHIELDGUN 99
|
||||||
|
|
||||||
#define HIW_BERETTA 1
|
#define HIW_BERETTA 1
|
||||||
#define HIW_SPAS12 2
|
#define HIW_SPAS12 2
|
||||||
|
|
|
@ -343,6 +343,7 @@ native cs_set_c4_explode_time(index, Float:value);
|
||||||
native bool:cs_get_c4_defusing(c4index);
|
native bool:cs_get_c4_defusing(c4index);
|
||||||
|
|
||||||
native cs_set_c4_defusing(c4index, bool:defusing);
|
native cs_set_c4_defusing(c4index, bool:defusing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when CS internally fires a command to a player. It does this for a few
|
* Called when CS internally fires a command to a player. It does this for a few
|
||||||
* functions, most notably rebuy/autobuy functionality. This is also used to pass
|
* functions, most notably rebuy/autobuy functionality. This is also used to pass
|
||||||
|
@ -353,3 +354,52 @@ native cs_set_c4_defusing(c4index, bool:defusing);
|
||||||
* @return PLUGIN_HANDLED to block, PLUGIN_CONTINUE for normal operation.
|
* @return PLUGIN_HANDLED to block, PLUGIN_CONTINUE for normal operation.
|
||||||
*/
|
*/
|
||||||
forward CS_InternalCommand(id, const cmd[]);
|
forward CS_InternalCommand(id, const cmd[]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following constants are used with CS_OnBuy forward.
|
||||||
|
*/
|
||||||
|
#define CSI_P228 CSW_P228
|
||||||
|
#define CSI_SCOUT CSW_SCOUT
|
||||||
|
#define CSI_HEGRENADE CSW_HEGRENADE
|
||||||
|
#define CSI_XM1014 CSW_XM1014
|
||||||
|
#define CSI_C4 CSW_C4
|
||||||
|
#define CSI_MAC10 CSW_MAC10
|
||||||
|
#define CSI_AUG CSW_AUG
|
||||||
|
#define CSI_SMOKEGRENADE CSW_SMOKEGRENADE
|
||||||
|
#define CSI_ELITE CSW_ELITE
|
||||||
|
#define CSI_FIVESEVEN CSW_FIVESEVEN
|
||||||
|
#define CSI_UMP45 CSW_UMP45
|
||||||
|
#define CSI_SG550 CSW_SG550
|
||||||
|
#define CSI_GALI CSW_GALI
|
||||||
|
#define CSI_FAMAS CSW_FAMAS
|
||||||
|
#define CSI_USP CSW_USP
|
||||||
|
#define CSI_GLOCK18 CSW_GLOCK18
|
||||||
|
#define CSI_AWP CSW_AWP
|
||||||
|
#define CSI_MP5NAVY CSW_MP5NAVY
|
||||||
|
#define CSI_M249 CSW_M249
|
||||||
|
#define CSI_M3 CSW_M3
|
||||||
|
#define CSI_M4A1 CSW_M4A1
|
||||||
|
#define CSI_TMP CSW_TMP
|
||||||
|
#define CSI_G3SG1 CSW_G3SG1
|
||||||
|
#define CSI_FLASHBANG CSW_FLASHBANG
|
||||||
|
#define CSI_DEAGLE CSW_DEAGLE
|
||||||
|
#define CSI_SG552 CSW_SG552
|
||||||
|
#define CSI_AK47 CSW_AK47
|
||||||
|
#define CSI_P90 CSW_P90
|
||||||
|
#define CSI_SHIELDGUN CSW_SHIELDGUN
|
||||||
|
#define CSI_VEST CSW_VEST // Custom
|
||||||
|
#define CSI_VESTHELM CSW_VESTHELM // Custom
|
||||||
|
#define CSI_DEFUSER 33 // Custom
|
||||||
|
#define CSI_NVGS 34 // Custom
|
||||||
|
#define CSI_PRIMAMMO 36 // Custom
|
||||||
|
#define CSI_SECAMMO 37 // Custom
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player attempts to purchase an item.
|
||||||
|
* Return PLUGIN_CONTINUE to allow the purchase or return a higher action to deny.
|
||||||
|
*
|
||||||
|
* @param index Player index.
|
||||||
|
* @param item Item index, see CSI_* constants.
|
||||||
|
*/
|
||||||
|
forward CS_OnBuy(index, item);
|
||||||
|
|
419
public/memtools/CDetour/asm/asm.c
Normal file
419
public/memtools/CDetour/asm/asm.c
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define REG_EAX 0
|
||||||
|
#define REG_ECX 1
|
||||||
|
#define REG_EDX 2
|
||||||
|
#define REG_EBX 3
|
||||||
|
|
||||||
|
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a call to a fpic thunk has just been written into dest.
|
||||||
|
* If found replaces it with a direct mov that sets the required register to the value of pc.
|
||||||
|
*
|
||||||
|
* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
|
||||||
|
* @param pc The program counter value that needs to be set (usually the next address from the source).
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
void check_thunks(unsigned char *dest, unsigned char *pc)
|
||||||
|
{
|
||||||
|
#if defined WIN32
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
/* Step write address back 4 to the start of the function address */
|
||||||
|
unsigned char *writeaddr = dest - 4;
|
||||||
|
unsigned char *calloffset = *(unsigned char **)writeaddr;
|
||||||
|
unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
|
||||||
|
|
||||||
|
/* Lookup name of function being called */
|
||||||
|
if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
|
||||||
|
{
|
||||||
|
//a thunk maybe?
|
||||||
|
char movByte = IA32_MOV_REG_IMM;
|
||||||
|
|
||||||
|
/* Calculate the correct mov opcode */
|
||||||
|
switch (*(calladdr+1))
|
||||||
|
{
|
||||||
|
case 0x04:
|
||||||
|
{
|
||||||
|
movByte += REG_EAX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x1C:
|
||||||
|
{
|
||||||
|
movByte += REG_EBX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0C:
|
||||||
|
{
|
||||||
|
movByte += REG_ECX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x14:
|
||||||
|
{
|
||||||
|
movByte += REG_EDX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
//Msg("Unknown thunk: %c\n", *(calladdr+1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move our write address back one to where the call opcode was */
|
||||||
|
writeaddr--;
|
||||||
|
|
||||||
|
|
||||||
|
/* Write our mov */
|
||||||
|
*writeaddr = movByte;
|
||||||
|
writeaddr++;
|
||||||
|
|
||||||
|
/* Write the value - The provided program counter value */
|
||||||
|
*(void **)writeaddr = (void *)pc;
|
||||||
|
writeaddr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//if dest is NULL, returns minimum number of bytes needed to be copied
|
||||||
|
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
||||||
|
//http://www.devmaster.net/forums/showthread.php?t=2311
|
||||||
|
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
|
||||||
|
int bytecount = 0;
|
||||||
|
|
||||||
|
while(bytecount < required_len && *func != 0xCC)
|
||||||
|
{
|
||||||
|
// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
|
||||||
|
int operandSize = 4;
|
||||||
|
int FPU = 0;
|
||||||
|
int twoByte = 0;
|
||||||
|
unsigned char opcode = 0x90;
|
||||||
|
unsigned char modRM = 0xFF;
|
||||||
|
while(*func == 0xF0 ||
|
||||||
|
*func == 0xF2 ||
|
||||||
|
*func == 0xF3 ||
|
||||||
|
(*func & 0xFC) == 0x64 ||
|
||||||
|
(*func & 0xF8) == 0xD8 ||
|
||||||
|
(*func & 0x7E) == 0x62)
|
||||||
|
{
|
||||||
|
if(*func == 0x66)
|
||||||
|
{
|
||||||
|
operandSize = 2;
|
||||||
|
}
|
||||||
|
else if((*func & 0xF8) == 0xD8)
|
||||||
|
{
|
||||||
|
FPU = *func;
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// two-byte opcode byte
|
||||||
|
if(*func == 0x0F)
|
||||||
|
{
|
||||||
|
twoByte = 1;
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opcode byte
|
||||||
|
opcode = *func++;
|
||||||
|
if (dest) *dest++ = opcode;
|
||||||
|
bytecount++;
|
||||||
|
|
||||||
|
// mod R/M byte
|
||||||
|
modRM = 0xFF;
|
||||||
|
if(FPU)
|
||||||
|
{
|
||||||
|
if((opcode & 0xC0) != 0xC0)
|
||||||
|
{
|
||||||
|
modRM = opcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!twoByte)
|
||||||
|
{
|
||||||
|
if((opcode & 0xC4) == 0x00 ||
|
||||||
|
((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) ||
|
||||||
|
(opcode & 0xF0) == 0x80 ||
|
||||||
|
((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) ||
|
||||||
|
(opcode & 0xFC) == 0xD0 ||
|
||||||
|
(opcode & 0xF6) == 0xF6)
|
||||||
|
{
|
||||||
|
modRM = *func++;
|
||||||
|
if (dest) *dest++ = modRM;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
|
||||||
|
(opcode & 0xF0) == 0x30 ||
|
||||||
|
opcode == 0x77 ||
|
||||||
|
(opcode & 0xF0) == 0x80 ||
|
||||||
|
((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
|
||||||
|
(opcode & 0xF8) == 0xC8)
|
||||||
|
{
|
||||||
|
// No mod R/M byte
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modRM = *func++;
|
||||||
|
if (dest) *dest++ = modRM;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIB
|
||||||
|
if((modRM & 0x07) == 0x04 &&
|
||||||
|
(modRM & 0xC0) != 0xC0)
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++; //SIB
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mod R/M displacement
|
||||||
|
|
||||||
|
// Dword displacement, no base
|
||||||
|
if((modRM & 0xC5) == 0x05) {
|
||||||
|
if (dest) {
|
||||||
|
*(unsigned int*)dest = *(unsigned int*)func;
|
||||||
|
dest += 4;
|
||||||
|
}
|
||||||
|
func += 4;
|
||||||
|
bytecount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte displacement
|
||||||
|
if((modRM & 0xC0) == 0x40) {
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dword displacement
|
||||||
|
if((modRM & 0xC0) == 0x80) {
|
||||||
|
if (dest) {
|
||||||
|
*(unsigned int*)dest = *(unsigned int*)func;
|
||||||
|
dest += 4;
|
||||||
|
}
|
||||||
|
func += 4;
|
||||||
|
bytecount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// immediate
|
||||||
|
if(FPU)
|
||||||
|
{
|
||||||
|
// Can't have immediate operand
|
||||||
|
}
|
||||||
|
else if(!twoByte)
|
||||||
|
{
|
||||||
|
if((opcode & 0xC7) == 0x04 ||
|
||||||
|
(opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
|
||||||
|
(opcode & 0xF0) == 0x70 || // Jcc
|
||||||
|
opcode == 0x80 ||
|
||||||
|
opcode == 0x83 ||
|
||||||
|
(opcode & 0xFD) == 0xA0 || // MOV
|
||||||
|
opcode == 0xA8 || // TEST
|
||||||
|
(opcode & 0xF8) == 0xB0 || // MOV
|
||||||
|
(opcode & 0xFE) == 0xC0 || // RCL
|
||||||
|
opcode == 0xC6 || // MOV
|
||||||
|
opcode == 0xCD || // INT
|
||||||
|
(opcode & 0xFE) == 0xD4 || // AAD/AAM
|
||||||
|
(opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
|
||||||
|
opcode == 0xEB ||
|
||||||
|
(opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
else if((opcode & 0xF7) == 0xC2) // RET
|
||||||
|
{
|
||||||
|
if (dest) {
|
||||||
|
*(unsigned short*)dest = *(unsigned short*)func;
|
||||||
|
dest += 2;
|
||||||
|
}
|
||||||
|
func += 2;
|
||||||
|
bytecount += 2;
|
||||||
|
}
|
||||||
|
else if((opcode & 0xFC) == 0x80 ||
|
||||||
|
(opcode & 0xC7) == 0x05 ||
|
||||||
|
(opcode & 0xF8) == 0xB8 ||
|
||||||
|
(opcode & 0xFE) == 0xE8 || // CALL/Jcc
|
||||||
|
(opcode & 0xFE) == 0x68 ||
|
||||||
|
(opcode & 0xFC) == 0xA0 ||
|
||||||
|
(opcode & 0xEE) == 0xA8 ||
|
||||||
|
opcode == 0xC7 ||
|
||||||
|
(opcode == 0xF7 && (modRM & 0x30) == 0x00))
|
||||||
|
{
|
||||||
|
if (dest) {
|
||||||
|
//Fix CALL/JMP offset
|
||||||
|
if ((opcode & 0xFE) == 0xE8) {
|
||||||
|
if (operandSize == 4)
|
||||||
|
{
|
||||||
|
*(long*)dest = ((func + *(long*)func) - dest);
|
||||||
|
|
||||||
|
//pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
|
||||||
|
check_thunks(dest+4, func+4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*(short*)dest = ((func + *(short*)func) - dest);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (operandSize == 4)
|
||||||
|
*(unsigned long*)dest = *(unsigned long*)func;
|
||||||
|
else
|
||||||
|
*(unsigned short*)dest = *(unsigned short*)func;
|
||||||
|
}
|
||||||
|
dest += operandSize;
|
||||||
|
}
|
||||||
|
func += operandSize;
|
||||||
|
bytecount += operandSize;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(opcode == 0xBA || // BT
|
||||||
|
opcode == 0x0F || // 3DNow!
|
||||||
|
(opcode & 0xFC) == 0x70 || // PSLLW
|
||||||
|
(opcode & 0xF7) == 0xA4 || // SHLD
|
||||||
|
opcode == 0xC2 ||
|
||||||
|
opcode == 0xC4 ||
|
||||||
|
opcode == 0xC5 ||
|
||||||
|
opcode == 0xC6)
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
}
|
||||||
|
else if((opcode & 0xF0) == 0x80) // Jcc -i
|
||||||
|
{
|
||||||
|
if (dest) {
|
||||||
|
if (operandSize == 4)
|
||||||
|
*(unsigned long*)dest = *(unsigned long*)func;
|
||||||
|
else
|
||||||
|
*(unsigned short*)dest = *(unsigned short*)func;
|
||||||
|
|
||||||
|
dest += operandSize;
|
||||||
|
}
|
||||||
|
func += operandSize;
|
||||||
|
bytecount += operandSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytecount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//insert a specific JMP instruction at the given location
|
||||||
|
void inject_jmp(void* src, void* dest) {
|
||||||
|
*(unsigned char*)src = OP_JMP;
|
||||||
|
*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill a given block with NOPs
|
||||||
|
void fill_nop(void* src, unsigned int len) {
|
||||||
|
unsigned char* src2 = (unsigned char*)src;
|
||||||
|
while (len) {
|
||||||
|
*src2++ = OP_NOP;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* eval_jump(void* src) {
|
||||||
|
unsigned char* addr = (unsigned char*)src;
|
||||||
|
|
||||||
|
if (!addr) return 0;
|
||||||
|
|
||||||
|
//import table jump
|
||||||
|
if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
|
||||||
|
addr += 2;
|
||||||
|
addr = *(unsigned char**)addr;
|
||||||
|
//TODO: if addr points into the IAT
|
||||||
|
return *(void**)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//8bit offset
|
||||||
|
else if (addr[0] == OP_JMP_BYTE) {
|
||||||
|
addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
|
||||||
|
//mangled 32bit jump?
|
||||||
|
if (addr[0] == OP_JMP) {
|
||||||
|
addr = addr + *(int*)&addr[1];
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
//32bit offset
|
||||||
|
else if (addr[0] == OP_JMP) {
|
||||||
|
addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
from ms detours package
|
||||||
|
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
|
||||||
|
__try {
|
||||||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
|
||||||
|
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||||
|
pDosHeader->e_lfanew);
|
||||||
|
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pbAddress >= ((PBYTE)pDosHeader +
|
||||||
|
pNtHeader->OptionalHeader
|
||||||
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
|
||||||
|
pbAddress < ((PBYTE)pDosHeader +
|
||||||
|
pNtHeader->OptionalHeader
|
||||||
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
|
||||||
|
pNtHeader->OptionalHeader
|
||||||
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
40
public/memtools/CDetour/asm/asm.h
Normal file
40
public/memtools/CDetour/asm/asm.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef __ASM_H__
|
||||||
|
#define __ASM_H__
|
||||||
|
|
||||||
|
#define OP_JMP 0xE9
|
||||||
|
#define OP_JMP_SIZE 5
|
||||||
|
|
||||||
|
#define OP_NOP 0x90
|
||||||
|
#define OP_NOP_SIZE 1
|
||||||
|
|
||||||
|
#define OP_PREFIX 0xFF
|
||||||
|
#define OP_JMP_SEG 0x25
|
||||||
|
|
||||||
|
#define OP_JMP_BYTE 0xEB
|
||||||
|
#define OP_JMP_BYTE_SIZE 2
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void check_thunks(unsigned char *dest, unsigned char *pc);
|
||||||
|
|
||||||
|
//if dest is NULL, returns minimum number of bytes needed to be copied
|
||||||
|
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
||||||
|
//http://www.devmaster.net/forums/showthread.php?t=2311
|
||||||
|
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
|
||||||
|
|
||||||
|
//insert a specific JMP instruction at the given location
|
||||||
|
void inject_jmp(void* src, void* dest);
|
||||||
|
|
||||||
|
//fill a given block with NOPs
|
||||||
|
void fill_nop(void* src, unsigned int len);
|
||||||
|
|
||||||
|
//evaluate a JMP at the target
|
||||||
|
void* eval_jump(void* src);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //__ASM_H__
|
129
public/memtools/CDetour/detourhelpers.h
Normal file
129
public/memtools/CDetour/detourhelpers.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#ifndef PAGE_SIZE
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#endif
|
||||||
|
#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
|
||||||
|
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
||||||
|
#if defined(__linux)
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#elif defined(WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct patch_t
|
||||||
|
{
|
||||||
|
patch_t()
|
||||||
|
{
|
||||||
|
patch[0] = 0;
|
||||||
|
bytes = 0;
|
||||||
|
}
|
||||||
|
unsigned char patch[20];
|
||||||
|
size_t bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void ProtectMemory(void *addr, int length, int prot)
|
||||||
|
{
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
void *addr2 = (void *)ALIGN(addr);
|
||||||
|
mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
|
||||||
|
#elif defined(WIN32)
|
||||||
|
DWORD old_prot;
|
||||||
|
VirtualProtect(addr, length, prot, &old_prot);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned char *AllocatePageMemory(size_t size)
|
||||||
|
{
|
||||||
|
#if defined WIN32
|
||||||
|
return (unsigned char *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
#elif defined __GNUC__
|
||||||
|
#if defined __APPLE__
|
||||||
|
unsigned char *addr = (unsigned char *)valloc(size);
|
||||||
|
#else
|
||||||
|
unsigned char *addr = (unsigned char *)memalign(sysconf(_SC_PAGESIZE), size);
|
||||||
|
#endif
|
||||||
|
mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||||
|
return addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FreePageMemory(void *addr)
|
||||||
|
{
|
||||||
|
#if defined(WIN32)
|
||||||
|
VirtualFree(addr, 0, MEM_RELEASE);
|
||||||
|
#else
|
||||||
|
free(addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetMemPatchable(void *address, size_t size)
|
||||||
|
{
|
||||||
|
ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DoGatePatch(unsigned char *target, void *callback)
|
||||||
|
{
|
||||||
|
SetMemPatchable(target, 20);
|
||||||
|
|
||||||
|
target[0] = 0xFF; /* JMP */
|
||||||
|
target[1] = 0x25; /* MEM32 */
|
||||||
|
*(void **)(&target[2]) = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
|
||||||
|
{
|
||||||
|
ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE);
|
||||||
|
|
||||||
|
unsigned char *addr = (unsigned char *)address + offset;
|
||||||
|
if (restore)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<patch->bytes; i++)
|
||||||
|
{
|
||||||
|
restore->patch[i] = addr[i];
|
||||||
|
}
|
||||||
|
restore->bytes = patch->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i<patch->bytes; i++)
|
||||||
|
{
|
||||||
|
addr[i] = patch->patch[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
231
public/memtools/CDetour/detours.cpp
Normal file
231
public/memtools/CDetour/detours.cpp
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "detours.h"
|
||||||
|
#include "asm/asm.h"
|
||||||
|
|
||||||
|
//ISourcePawnEngine *CDetourManager::spengine = NULL;
|
||||||
|
//IGameConfig *CDetourManager::gameconf = NULL;
|
||||||
|
|
||||||
|
void CDetourManager::Init(/*ISourcePawnEngine *spengine, IGameConfig *gameconf*/)
|
||||||
|
{
|
||||||
|
//CDetourManager::spengine = spengine;
|
||||||
|
//CDetourManager::gameconf = gameconf;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
|
||||||
|
{
|
||||||
|
CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
|
||||||
|
if (detour)
|
||||||
|
{
|
||||||
|
if (!detour->Init(/*spengine, gameconf*/))
|
||||||
|
{
|
||||||
|
delete detour;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return detour;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, void *address)
|
||||||
|
{
|
||||||
|
CDetour *detour = new CDetour(callbackfunction, trampoline, address);
|
||||||
|
if (detour)
|
||||||
|
{
|
||||||
|
if (!detour->Init(/*spengine, gameconf*/))
|
||||||
|
{
|
||||||
|
delete detour;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return detour;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
detoured = false;
|
||||||
|
detour_address = NULL;
|
||||||
|
detour_trampoline = NULL;
|
||||||
|
this->signame = signame;
|
||||||
|
this->detour_callback = callbackfunction;
|
||||||
|
this->address = NULL;
|
||||||
|
//spengine = NULL;
|
||||||
|
//gameconf = NULL;
|
||||||
|
this->trampoline = trampoline;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDetour::CDetour(void *callbackfunction, void **trampoline, void *address)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
detoured = false;
|
||||||
|
detour_address = address;
|
||||||
|
detour_trampoline = NULL;
|
||||||
|
this->signame = NULL;
|
||||||
|
this->detour_callback = callbackfunction;
|
||||||
|
this->address = address;
|
||||||
|
//spengine = NULL;
|
||||||
|
//gameconf = NULL;
|
||||||
|
this->trampoline = trampoline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CDetour::Init(/*ISourcePawnEngine *spengine, IGameConfig *gameconf*/)
|
||||||
|
{
|
||||||
|
//this->spengine = spengine;
|
||||||
|
//this->gameconf = gameconf;
|
||||||
|
|
||||||
|
if (!CreateDetour())
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::Destroy()
|
||||||
|
{
|
||||||
|
DeleteDetour();
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDetour::IsEnabled()
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDetour::CreateDetour()
|
||||||
|
{
|
||||||
|
/*if (signame != NULL && !gameconf->GetMemSig(signame, &detour_address))
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (address != NULL)
|
||||||
|
{
|
||||||
|
detour_address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!detour_address)
|
||||||
|
{
|
||||||
|
//g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
|
||||||
|
|
||||||
|
/* First, save restore bits */
|
||||||
|
for (size_t i=0; i<detour_restore.bytes; i++)
|
||||||
|
{
|
||||||
|
detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
JitWriter wr;
|
||||||
|
JitWriter *jit = ≀
|
||||||
|
unsigned int CodeSize = 0;
|
||||||
|
|
||||||
|
wr.outbase = NULL;
|
||||||
|
wr.outptr = NULL;
|
||||||
|
|
||||||
|
jit_rewind:
|
||||||
|
|
||||||
|
/* Patch old bytes in */
|
||||||
|
if (wr.outbase != NULL)
|
||||||
|
{
|
||||||
|
copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes);
|
||||||
|
}
|
||||||
|
wr.outptr += detour_restore.bytes;
|
||||||
|
|
||||||
|
/* Return to the original function */
|
||||||
|
unsigned int call = IA32_Jump_Imm32(jit, 0);
|
||||||
|
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
|
||||||
|
|
||||||
|
if (wr.outbase == NULL)
|
||||||
|
{
|
||||||
|
CodeSize = wr.get_outputpos();
|
||||||
|
wr.outbase = (char *)AllocatePageMemory(CodeSize);
|
||||||
|
//spengine->SetReadWrite(wr.outbase);
|
||||||
|
wr.outptr = wr.outbase;
|
||||||
|
detour_trampoline = wr.outbase;
|
||||||
|
goto jit_rewind;
|
||||||
|
}
|
||||||
|
|
||||||
|
//spengine->SetReadExecute(wr.outbase);
|
||||||
|
|
||||||
|
*trampoline = detour_trampoline;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::DeleteDetour()
|
||||||
|
{
|
||||||
|
if (detoured)
|
||||||
|
{
|
||||||
|
DisableDetour();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detour_trampoline)
|
||||||
|
{
|
||||||
|
/* Free the allocated trampoline memory */
|
||||||
|
FreePageMemory(detour_trampoline);
|
||||||
|
detour_trampoline = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::EnableDetour()
|
||||||
|
{
|
||||||
|
if (!detoured)
|
||||||
|
{
|
||||||
|
DoGatePatch((unsigned char *)detour_address, &detour_callback);
|
||||||
|
detoured = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::DisableDetour()
|
||||||
|
{
|
||||||
|
if (detoured)
|
||||||
|
{
|
||||||
|
/* Remove the patch */
|
||||||
|
ApplyPatch(detour_address, 0, &detour_restore, NULL);
|
||||||
|
detoured = false;
|
||||||
|
}
|
||||||
|
}
|
369
public/memtools/CDetour/detours.h
Normal file
369
public/memtools/CDetour/detours.h
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||||
|
|
||||||
|
#include "amxxmodule.h"
|
||||||
|
//#include <jit/jit_helpers.h>
|
||||||
|
//#include <jit/x86/x86_macros.h>
|
||||||
|
#include "detourhelpers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CDetours class for SourceMod Extensions by pRED*
|
||||||
|
* detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
|
||||||
|
* asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly
|
||||||
|
* Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/)
|
||||||
|
* Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
|
||||||
|
#define DETOUR_STATIC_CALL(name) (name##_Actual)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_STATIC0(name, ret) \
|
||||||
|
ret (*name##_Actual)(void) = NULL; \
|
||||||
|
ret name(void)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
|
||||||
|
ret (*name##_Actual)(p1type) = NULL; \
|
||||||
|
ret name(p1type p1name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_STATIC2(name, ret, p1type, p1name, p2type, p2name) \
|
||||||
|
ret (*name##_Actual)(p1type, p2type) = NULL; \
|
||||||
|
ret name(p1type p1name, p2type p2name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_STATIC3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
|
||||||
|
ret (*name##_Actual)(p1type, p2type, p3type) = NULL; \
|
||||||
|
ret name(p1type p1name, p2type p2name, p3type p3name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
|
||||||
|
ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
|
||||||
|
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_MEMBER0(name, ret) \
|
||||||
|
class name##Class \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
ret name(); \
|
||||||
|
static ret (name##Class::* name##_Actual)(void); \
|
||||||
|
}; \
|
||||||
|
ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
|
||||||
|
ret name##Class::name()
|
||||||
|
|
||||||
|
#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
|
||||||
|
class name##Class \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
ret name(p1type p1name); \
|
||||||
|
static ret (name##Class::* name##_Actual)(p1type); \
|
||||||
|
}; \
|
||||||
|
ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
|
||||||
|
ret name##Class::name(p1type p1name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
|
||||||
|
class name##Class \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
ret name(p1type p1name, p2type p2name); \
|
||||||
|
static ret (name##Class::* name##_Actual)(p1type, p2type); \
|
||||||
|
}; \
|
||||||
|
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
|
||||||
|
ret name##Class::name(p1type p1name, p2type p2name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
|
||||||
|
class name##Class \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
ret name(p1type p1name, p2type p2name, p3type p3name); \
|
||||||
|
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
|
||||||
|
}; \
|
||||||
|
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
|
||||||
|
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
|
||||||
|
class name##Class \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
|
||||||
|
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
|
||||||
|
}; \
|
||||||
|
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
|
||||||
|
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
|
||||||
|
|
||||||
|
#define DETOUR_DECL_MEMBER8(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name) \
|
||||||
|
class name##Class \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name); \
|
||||||
|
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type); \
|
||||||
|
}; \
|
||||||
|
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \
|
||||||
|
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name)
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
|
||||||
|
#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
|
||||||
|
|
||||||
|
#define GET_STATIC_CALLBACK(name) (void *)&name
|
||||||
|
#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
|
||||||
|
|
||||||
|
#define DETOUR_CREATE_MEMBER(name, gamedata, target) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata, target);
|
||||||
|
#define DETOUR_CREATE_STATIC(name, gamedata, target) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata, target);
|
||||||
|
#define DETOUR_CREATE_STATIC_FIXED(name, address) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), address);
|
||||||
|
|
||||||
|
class GenericClass {};
|
||||||
|
typedef void (GenericClass::*VoidFunc)();
|
||||||
|
|
||||||
|
inline void *GetCodeAddr(VoidFunc mfp)
|
||||||
|
{
|
||||||
|
return *(void **)&mfp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a member function pointer to a void pointer.
|
||||||
|
* This relies on the assumption that the code address lies at mfp+0
|
||||||
|
* This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
|
||||||
|
* Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
|
||||||
|
*/
|
||||||
|
#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast<VoidFunc>(mfp))
|
||||||
|
|
||||||
|
class CDetourManager;
|
||||||
|
|
||||||
|
class CDetour
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool IsEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These would be somewhat self-explanatory I hope
|
||||||
|
*/
|
||||||
|
void EnableDetour();
|
||||||
|
void DisableDetour();
|
||||||
|
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
friend class CDetourManager;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CDetour(void *callbackfunction, void **trampoline, const char *signame);
|
||||||
|
CDetour(void *callbackfunction, void **trampoline, void *address);
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* These create/delete the allocated memory */
|
||||||
|
bool CreateDetour();
|
||||||
|
void DeleteDetour();
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
bool detoured;
|
||||||
|
|
||||||
|
patch_t detour_restore;
|
||||||
|
/* Address of the detoured function */
|
||||||
|
void *detour_address;
|
||||||
|
/* Address of the allocated trampoline function */
|
||||||
|
void *detour_trampoline;
|
||||||
|
/* Address of the callback handler */
|
||||||
|
void *detour_callback;
|
||||||
|
/* The function pointer used to call our trampoline */
|
||||||
|
void **trampoline;
|
||||||
|
|
||||||
|
const char *signame;
|
||||||
|
void *address;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDetourManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void Init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new detour
|
||||||
|
*
|
||||||
|
* @param callbackfunction Void pointer to your detour callback function.
|
||||||
|
* @param trampoline Address of the trampoline pointer
|
||||||
|
* @param signame Section name containing a signature to fetch from the gamedata file.
|
||||||
|
* @return A new CDetour pointer to control your detour.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
|
||||||
|
*
|
||||||
|
* Define a new class with the required function and a member function pointer to the same type:
|
||||||
|
*
|
||||||
|
* class CBaseServerDetour
|
||||||
|
* {
|
||||||
|
* public:
|
||||||
|
* bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
||||||
|
* static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
|
||||||
|
* void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
|
||||||
|
*
|
||||||
|
* Creation:
|
||||||
|
* CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
|
||||||
|
* {
|
||||||
|
* //pre hook code
|
||||||
|
* bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
|
||||||
|
* //post hook code
|
||||||
|
* return result;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Note we changed the netadr_s reference into a void* to avoid needing to define the type
|
||||||
|
*/
|
||||||
|
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
|
||||||
|
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, void *address);
|
||||||
|
|
||||||
|
friend class CBlocker;
|
||||||
|
friend class CDetour;
|
||||||
|
|
||||||
|
/*private:
|
||||||
|
static ISourcePawnEngine *spengine;
|
||||||
|
static IGameConfig *gameconf;*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Helpers from jit_helpers.h/x86_macros.h.
|
||||||
|
|
||||||
|
class JitWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline cell read_cell()
|
||||||
|
{
|
||||||
|
cell val = *(inptr);
|
||||||
|
inptr++;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
inline cell peek_cell()
|
||||||
|
{
|
||||||
|
return *inptr;
|
||||||
|
}
|
||||||
|
inline cell *read_cellptr()
|
||||||
|
{
|
||||||
|
cell *val = *(cell **)(inptr);
|
||||||
|
inptr++;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
inline void write_ubyte(unsigned char c)
|
||||||
|
{
|
||||||
|
if (outbase)
|
||||||
|
{
|
||||||
|
*outptr = c;
|
||||||
|
}
|
||||||
|
outptr++;
|
||||||
|
}
|
||||||
|
inline void write_ushort(unsigned short c)
|
||||||
|
{
|
||||||
|
if (outbase)
|
||||||
|
{
|
||||||
|
*(unsigned short *)outptr = c;
|
||||||
|
}
|
||||||
|
outptr += sizeof(unsigned short);
|
||||||
|
}
|
||||||
|
inline void write_byte(char c)
|
||||||
|
{
|
||||||
|
if (outbase)
|
||||||
|
{
|
||||||
|
*outptr = c;
|
||||||
|
}
|
||||||
|
outptr++;
|
||||||
|
}
|
||||||
|
inline void write_int32(int c)
|
||||||
|
{
|
||||||
|
if (outbase)
|
||||||
|
{
|
||||||
|
*(int *)outptr = c;
|
||||||
|
}
|
||||||
|
outptr += sizeof(int);
|
||||||
|
}
|
||||||
|
inline void write_uint32(unsigned int c)
|
||||||
|
{
|
||||||
|
if (outbase)
|
||||||
|
{
|
||||||
|
*(unsigned int *)outptr = c;
|
||||||
|
}
|
||||||
|
outptr += sizeof(unsigned int);
|
||||||
|
}
|
||||||
|
inline unsigned int get_outputpos()
|
||||||
|
{
|
||||||
|
return (outptr - outbase);
|
||||||
|
}
|
||||||
|
inline void set_outputpos(unsigned int offs)
|
||||||
|
{
|
||||||
|
outptr = outbase + offs;
|
||||||
|
}
|
||||||
|
inline unsigned int get_inputpos()
|
||||||
|
{
|
||||||
|
return (unsigned int)((char *)inptr - (char *)inbase);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
cell *inptr; /* input pointer */
|
||||||
|
cell *inbase; /* input base */
|
||||||
|
char *outbase; /* output pointer */
|
||||||
|
char *outptr; /* output base */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IA32_JMP_IMM32 0xE9 // encoding is imm32
|
||||||
|
|
||||||
|
inline unsigned int IA32_Jump_Imm32(JitWriter *jit, int disp)
|
||||||
|
{
|
||||||
|
unsigned int ptr;
|
||||||
|
jit->write_ubyte(IA32_JMP_IMM32);
|
||||||
|
ptr = jit->get_outputpos();
|
||||||
|
jit->write_int32(disp);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Corrects a jump using an absolute offset, not a relative one.
|
||||||
|
*/
|
||||||
|
inline void IA32_Write_Jump32_Abs(JitWriter *jit, unsigned int jmp, void *target)
|
||||||
|
{
|
||||||
|
//save old ptr
|
||||||
|
char *oldptr = jit->outptr;
|
||||||
|
//get relative difference
|
||||||
|
long diff = ((long)target - ((long)jit->outbase + jmp + 4));
|
||||||
|
//overwrite old value
|
||||||
|
jit->outptr = jit->outbase + jmp;
|
||||||
|
jit->write_int32(diff);
|
||||||
|
//restore old ptr
|
||||||
|
jit->outptr = oldptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
|
705
public/memtools/MemoryUtils.cpp
Normal file
705
public/memtools/MemoryUtils.cpp
Normal file
|
@ -0,0 +1,705 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MemoryUtils.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
#include <mach/task.h>
|
||||||
|
#include <mach-o/dyld_images.h>
|
||||||
|
#include <mach-o/loader.h>
|
||||||
|
#include <mach-o/nlist.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
/* Define things from 10.6 SDK for older SDKs */
|
||||||
|
#ifndef MAC_OS_X_VERSION_10_6
|
||||||
|
struct task_dyld_info
|
||||||
|
{
|
||||||
|
mach_vm_address_t all_image_info_addr;
|
||||||
|
mach_vm_size_t all_image_info_size;
|
||||||
|
};
|
||||||
|
typedef struct task_dyld_info task_dyld_info_data_t;
|
||||||
|
#define TASK_DYLD_INFO 17
|
||||||
|
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
|
||||||
|
#endif // MAC_OS_X_VERSION_10_6
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
MemoryUtils g_MemUtils;
|
||||||
|
|
||||||
|
MemoryUtils::MemoryUtils()
|
||||||
|
{
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
|
||||||
|
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
|
||||||
|
|
||||||
|
/* Get pointer to struct that describes all loaded mach-o images in process */
|
||||||
|
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
|
||||||
|
{
|
||||||
|
task_dyld_info_data_t dyld_info;
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
|
||||||
|
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct nlist list[2];
|
||||||
|
memset(list, 0, sizeof(list));
|
||||||
|
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
|
||||||
|
nlist("/usr/lib/dyld", list);
|
||||||
|
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryUtils::~MemoryUtils()
|
||||||
|
{
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
for (size_t i = 0; i < m_SymTables.length(); i++)
|
||||||
|
{
|
||||||
|
delete m_SymTables[i];
|
||||||
|
}
|
||||||
|
m_SymTables.clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryUtils::DecodeAndFindPattern(const void *libPtr, const char *pattern)
|
||||||
|
{
|
||||||
|
unsigned char real_sig[511];
|
||||||
|
size_t real_bytes = DecodeHexString(real_sig, sizeof(real_sig), pattern);
|
||||||
|
|
||||||
|
if (real_bytes >= 1)
|
||||||
|
{
|
||||||
|
return FindPattern(libPtr, (char*)real_sig, real_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||||
|
{
|
||||||
|
DynLibInfo lib;
|
||||||
|
bool found;
|
||||||
|
char *ptr, *end;
|
||||||
|
|
||||||
|
memset(&lib, 0, sizeof(DynLibInfo));
|
||||||
|
|
||||||
|
if (!GetLibraryInfo(libPtr, lib))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
||||||
|
end = ptr + lib.memorySize - len;
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
for (register size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||||
|
{
|
||||||
|
#if defined(WIN32)
|
||||||
|
|
||||||
|
return GetProcAddress((HMODULE)handle, symbol);
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
|
||||||
|
struct link_map *dlmap;
|
||||||
|
struct stat dlstat;
|
||||||
|
int dlfile;
|
||||||
|
uintptr_t map_base;
|
||||||
|
Elf32_Ehdr *file_hdr;
|
||||||
|
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
|
||||||
|
Elf32_Sym *symtab;
|
||||||
|
const char *shstrtab, *strtab;
|
||||||
|
uint16_t section_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlmap = (struct link_map *)handle;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
strtab_hdr = NULL;
|
||||||
|
table = NULL;
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.length(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlmap->l_addr)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlmap->l_addr;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.append(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have open the actual library */
|
||||||
|
dlfile = open(dlmap->l_name, O_RDONLY);
|
||||||
|
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
|
||||||
|
{
|
||||||
|
close(dlfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map library file into memory */
|
||||||
|
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
|
||||||
|
map_base = (uintptr_t)file_hdr;
|
||||||
|
if (file_hdr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
close(dlfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
close(dlfile);
|
||||||
|
|
||||||
|
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
|
||||||
|
{
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
|
||||||
|
section_count = file_hdr->e_shnum;
|
||||||
|
/* Get ELF section header string table */
|
||||||
|
shstrtab_hdr = §ions[file_hdr->e_shstrndx];
|
||||||
|
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
|
||||||
|
|
||||||
|
/* Iterate sections while looking for ELF symbol table and string table */
|
||||||
|
for (uint16_t i = 0; i < section_count; i++)
|
||||||
|
{
|
||||||
|
Elf32_Shdr &hdr = sections[i];
|
||||||
|
const char *section_name = shstrtab + hdr.sh_name;
|
||||||
|
|
||||||
|
if (strcmp(section_name, ".symtab") == 0)
|
||||||
|
{
|
||||||
|
symtab_hdr = &hdr;
|
||||||
|
}
|
||||||
|
else if (strcmp(section_name, ".strtab") == 0)
|
||||||
|
{
|
||||||
|
strtab_hdr = &hdr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Uh oh, we don't have a symbol table or a string table */
|
||||||
|
if (symtab_hdr == NULL || strtab_hdr == NULL)
|
||||||
|
{
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
|
||||||
|
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
|
||||||
|
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
Elf32_Sym &sym = symtab[i];
|
||||||
|
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
|
||||||
|
const char *sym_name = strtab + sym.st_name;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined or do not refer to functions or objects */
|
||||||
|
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
|
||||||
|
uintptr_t dlbase, linkedit_addr;
|
||||||
|
uint32_t image_count;
|
||||||
|
struct mach_header *file_hdr;
|
||||||
|
struct load_command *loadcmds;
|
||||||
|
struct segment_command *linkedit_hdr;
|
||||||
|
struct symtab_command *symtab_hdr;
|
||||||
|
struct nlist *symtab;
|
||||||
|
const char *strtab;
|
||||||
|
uint32_t loadcmd_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlbase = 0;
|
||||||
|
image_count = m_ImageList->infoArrayCount;
|
||||||
|
linkedit_hdr = NULL;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
table = NULL;
|
||||||
|
|
||||||
|
/* Loop through mach-o images in process.
|
||||||
|
* We can skip index 0 since that is just the executable.
|
||||||
|
*/
|
||||||
|
for (uint32_t i = 1; i < image_count; i++)
|
||||||
|
{
|
||||||
|
const struct dyld_image_info &info = m_ImageList->infoArray[i];
|
||||||
|
|
||||||
|
/* "Load" each one until we get a matching handle */
|
||||||
|
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
|
||||||
|
if (h == handle)
|
||||||
|
{
|
||||||
|
dlbase = (uintptr_t)info.imageLoadAddress;
|
||||||
|
dlclose(h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlclose(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dlbase)
|
||||||
|
{
|
||||||
|
/* Uh oh, we couldn't find a matching handle */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.length(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlbase)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlbase;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.append(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have to locate it in memory */
|
||||||
|
|
||||||
|
file_hdr = (struct mach_header *)dlbase;
|
||||||
|
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
|
||||||
|
loadcmd_count = file_hdr->ncmds;
|
||||||
|
|
||||||
|
/* Loop through load commands until we find the ones for the symbol table */
|
||||||
|
for (uint32_t i = 0; i < loadcmd_count; i++)
|
||||||
|
{
|
||||||
|
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
|
||||||
|
{
|
||||||
|
struct segment_command *seg = (struct segment_command *)loadcmds;
|
||||||
|
if (strcmp(seg->segname, "__LINKEDIT") == 0)
|
||||||
|
{
|
||||||
|
linkedit_hdr = seg;
|
||||||
|
if (symtab_hdr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (loadcmds->cmd == LC_SYMTAB)
|
||||||
|
{
|
||||||
|
symtab_hdr = (struct symtab_command *)loadcmds;
|
||||||
|
if (linkedit_hdr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load commands are not of a fixed size which is why we add the size */
|
||||||
|
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
|
||||||
|
{
|
||||||
|
/* Uh oh, no symbol table */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
|
||||||
|
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
|
||||||
|
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
|
||||||
|
symbol_count = symtab_hdr->nsyms;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
struct nlist &sym = symtab[i];
|
||||||
|
/* Ignore the prepended underscore on all symbols, so +1 here */
|
||||||
|
const char *sym_name = strtab + sym.n_un.n_strx + 1;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined */
|
||||||
|
if (sym.n_sect == NO_SECT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||||
|
{
|
||||||
|
uintptr_t baseAddr;
|
||||||
|
|
||||||
|
if (libPtr == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
|
||||||
|
MEMORY_BASIC_INFORMATION info;
|
||||||
|
IMAGE_DOS_HEADER *dos;
|
||||||
|
IMAGE_NT_HEADERS *pe;
|
||||||
|
IMAGE_FILE_HEADER *file;
|
||||||
|
IMAGE_OPTIONAL_HEADER *opt;
|
||||||
|
|
||||||
|
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
||||||
|
|
||||||
|
/* All this is for our insane sanity checks :o */
|
||||||
|
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
|
||||||
|
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
|
||||||
|
file = &pe->FileHeader;
|
||||||
|
opt = &pe->OptionalHeader;
|
||||||
|
|
||||||
|
/* Check PE magic and signature */
|
||||||
|
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check architecture, which is 32-bit/x86 right now
|
||||||
|
* Should change this for 64-bit if Valve gets their act together
|
||||||
|
*/
|
||||||
|
if (file->Machine != IMAGE_FILE_MACHINE_I386)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For our purposes, this must be a dynamic library */
|
||||||
|
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, we can do this */
|
||||||
|
lib.memorySize = opt->SizeOfImage;
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
|
||||||
|
Dl_info info;
|
||||||
|
Elf32_Ehdr *file;
|
||||||
|
Elf32_Phdr *phdr;
|
||||||
|
uint16_t phdrCount;
|
||||||
|
|
||||||
|
if (!dladdr(libPtr, &info))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is for our insane sanity checks :o */
|
||||||
|
baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
|
||||||
|
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
|
||||||
|
|
||||||
|
/* Check ELF magic */
|
||||||
|
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check ELF version */
|
||||||
|
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check ELF architecture, which is 32-bit/x86 right now
|
||||||
|
* Should change this for 64-bit if Valve gets their act together
|
||||||
|
*/
|
||||||
|
if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For our purposes, this must be a dynamic library/shared object */
|
||||||
|
if (file->e_type != ET_DYN)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
phdrCount = file->e_phnum;
|
||||||
|
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < phdrCount; i++)
|
||||||
|
{
|
||||||
|
Elf32_Phdr &hdr = phdr[i];
|
||||||
|
|
||||||
|
/* We only really care about the segment with executable code */
|
||||||
|
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
|
||||||
|
{
|
||||||
|
/* From glibc, elf/dl-load.c:
|
||||||
|
* c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
|
||||||
|
* & ~(GLRO(dl_pagesize) - 1));
|
||||||
|
*
|
||||||
|
* In glibc, the segment file size is aligned up to the nearest page size and
|
||||||
|
* added to the virtual address of the segment. We just want the size here.
|
||||||
|
*/
|
||||||
|
lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
|
||||||
|
Dl_info info;
|
||||||
|
struct mach_header *file;
|
||||||
|
struct segment_command *seg;
|
||||||
|
uint32_t cmd_count;
|
||||||
|
|
||||||
|
if (!dladdr(libPtr, &info))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is for our insane sanity checks :o */
|
||||||
|
baseAddr = (uintptr_t)info.dli_fbase;
|
||||||
|
file = (struct mach_header *)baseAddr;
|
||||||
|
|
||||||
|
/* Check Mach-O magic */
|
||||||
|
if (file->magic != MH_MAGIC)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check architecture (32-bit/x86) */
|
||||||
|
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For our purposes, this must be a dynamic library */
|
||||||
|
if (file->filetype != MH_DYLIB)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_count = file->ncmds;
|
||||||
|
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
|
||||||
|
|
||||||
|
/* Add up memory sizes of mapped segments */
|
||||||
|
for (uint32_t i = 0; i < cmd_count; i++)
|
||||||
|
{
|
||||||
|
if (seg->cmd == LC_SEGMENT)
|
||||||
|
{
|
||||||
|
lib.memorySize += seg->vmsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryUtils::GetLibraryOfAddress(const void *libPtr, char *buffer, size_t maxlength, uintptr_t *base)
|
||||||
|
{
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
|
||||||
|
Dl_info info;
|
||||||
|
if (!dladdr(libPtr, &info))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char *dllpath = info.dli_fname;
|
||||||
|
snprintf(buffer, maxlength, "%s", dllpath);
|
||||||
|
if (base)
|
||||||
|
{
|
||||||
|
*base = (uintptr_t)info.dli_fbase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
MEMORY_BASIC_INFORMATION mem;
|
||||||
|
if (!VirtualQuery(libPtr, &mem, sizeof(mem)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mem.AllocationBase == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
HMODULE dll = (HMODULE)mem.AllocationBase;
|
||||||
|
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
|
||||||
|
if (base)
|
||||||
|
{
|
||||||
|
*base = (uintptr_t)mem.AllocationBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryUtils::DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr)
|
||||||
|
{
|
||||||
|
size_t written = 0;
|
||||||
|
size_t length = strlen(hexstr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (written >= maxlength)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buffer[written++] = hexstr[i];
|
||||||
|
if (hexstr[i] == '\\' && hexstr[i + 1] == 'x')
|
||||||
|
{
|
||||||
|
if (i + 3 >= length)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Get the hex part. */
|
||||||
|
char s_byte[3];
|
||||||
|
int r_byte;
|
||||||
|
s_byte[0] = hexstr[i + 2];
|
||||||
|
s_byte[1] = hexstr[i + 3];
|
||||||
|
s_byte[2] = '\0';
|
||||||
|
|
||||||
|
/* Read it as an integer */
|
||||||
|
sscanf(s_byte, "%x", &r_byte);
|
||||||
|
|
||||||
|
/* Save the value */
|
||||||
|
buffer[written - 1] = r_byte;
|
||||||
|
|
||||||
|
/* Adjust index */
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
97
public/memtools/MemoryUtils.h
Normal file
97
public/memtools/MemoryUtils.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <am-vector.h>
|
||||||
|
#include <sm_symtable.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined _MSC_VER && _MSC_VER >= 1400
|
||||||
|
#pragma warning (disable:4996) /* Disable deprecation warnings */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct DynLibInfo
|
||||||
|
{
|
||||||
|
void *baseAddress;
|
||||||
|
size_t memorySize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
struct LibSymbolTable
|
||||||
|
{
|
||||||
|
SymbolTable table;
|
||||||
|
uintptr_t lib_base;
|
||||||
|
uint32_t last_pos;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class MemoryUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemoryUtils();
|
||||||
|
~MemoryUtils();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void *DecodeAndFindPattern(const void *libPtr, const char *pattern);
|
||||||
|
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||||
|
void *ResolveSymbol(void *handle, const char *symbol);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||||
|
bool GetLibraryOfAddress(const void *libPtr, char *buffer, size_t maxlength, uintptr_t *base);
|
||||||
|
|
||||||
|
public:
|
||||||
|
size_t DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr);
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
private:
|
||||||
|
ke::Vector<LibSymbolTable *> m_SymTables;
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
struct dyld_all_image_infos *m_ImageList;
|
||||||
|
SInt32 m_OSXMajor;
|
||||||
|
SInt32 m_OSXMinor;
|
||||||
|
#endif // __APPLE__
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
extern MemoryUtils g_MemUtils;
|
||||||
|
|
||||||
|
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
170
public/sm_memtable.h
Normal file
170
public/sm_memtable.h
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
class BaseMemTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseMemTable(unsigned int init_size)
|
||||||
|
{
|
||||||
|
membase = (unsigned char *)malloc(init_size);
|
||||||
|
size = init_size;
|
||||||
|
tail = 0;
|
||||||
|
}
|
||||||
|
~BaseMemTable()
|
||||||
|
{
|
||||||
|
free(membase);
|
||||||
|
membase = NULL;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Allocates 'size' bytes of memory.
|
||||||
|
* Optionally outputs the address through 'addr'.
|
||||||
|
* Returns an index >= 0 on success, < 0 on failure.
|
||||||
|
*/
|
||||||
|
int CreateMem(unsigned int addsize, void **addr)
|
||||||
|
{
|
||||||
|
int idx = (int)tail;
|
||||||
|
|
||||||
|
while (tail + addsize >= size) {
|
||||||
|
size *= 2;
|
||||||
|
membase = (unsigned char *)realloc(membase, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
tail += addsize;
|
||||||
|
if (addr)
|
||||||
|
*addr = (void *)&membase[idx];
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an index into the memory table, returns its address.
|
||||||
|
* Returns NULL if invalid.
|
||||||
|
*/
|
||||||
|
void *GetAddress(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || (unsigned int)index >= tail)
|
||||||
|
return NULL;
|
||||||
|
return &membase[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scraps the memory table. For caching purposes, the memory
|
||||||
|
* is not freed, however subsequent calls to CreateMem() will
|
||||||
|
* begin at the first index again.
|
||||||
|
*/
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetMemUsage()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int GetActualMemUsed()
|
||||||
|
{
|
||||||
|
return tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char *membase;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseStringTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseStringTable(unsigned int init_size) : m_table(init_size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Adds a string to the string table and returns its index.
|
||||||
|
*/
|
||||||
|
int AddString(const char *string)
|
||||||
|
{
|
||||||
|
return AddString(string, strlen(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a string to the string table and returns its index.
|
||||||
|
*/
|
||||||
|
int AddString(const char *string, size_t length)
|
||||||
|
{
|
||||||
|
size_t len = length + 1;
|
||||||
|
int idx;
|
||||||
|
char *addr;
|
||||||
|
|
||||||
|
idx = m_table.CreateMem(len, (void **)&addr);
|
||||||
|
memcpy(addr, string, length + 1);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an index into the string table, returns the associated string.
|
||||||
|
*/
|
||||||
|
inline const char *GetString(int str)
|
||||||
|
{
|
||||||
|
return (const char *)m_table.GetAddress(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scraps the string table. For caching purposes, the memory
|
||||||
|
* is not freed, however subsequent calls to AddString() will
|
||||||
|
* begin at the first index again.
|
||||||
|
*/
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
m_table.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parent BaseMemTable that this string table uses.
|
||||||
|
*/
|
||||||
|
inline BaseMemTable *GetMemTable()
|
||||||
|
{
|
||||||
|
return &m_table;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
BaseMemTable m_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
|
||||||
|
|
231
public/sm_symtable.h
Normal file
231
public/sm_symtable.h
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define KESTRING_TABLE_START_SIZE 65536
|
||||||
|
|
||||||
|
struct Symbol
|
||||||
|
{
|
||||||
|
size_t length;
|
||||||
|
uint32_t hash;
|
||||||
|
void *address;
|
||||||
|
Symbol *tbl_next;
|
||||||
|
|
||||||
|
inline char *buffer()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<char *>(this + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymbolTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~SymbolTable()
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < nbuckets; i++)
|
||||||
|
{
|
||||||
|
Symbol *sym = buckets[i];
|
||||||
|
while (sym != NULL)
|
||||||
|
{
|
||||||
|
Symbol *next = sym->tbl_next;
|
||||||
|
free(sym);
|
||||||
|
sym = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Initialize()
|
||||||
|
{
|
||||||
|
buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
|
||||||
|
if (buckets == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
|
||||||
|
|
||||||
|
nbuckets = KESTRING_TABLE_START_SIZE;
|
||||||
|
nused = 0;
|
||||||
|
bucketmask = KESTRING_TABLE_START_SIZE - 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t HashString(const char *data, size_t len)
|
||||||
|
{
|
||||||
|
#undef get16bits
|
||||||
|
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||||
|
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||||
|
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||||
|
#endif
|
||||||
|
#if !defined (get16bits)
|
||||||
|
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||||
|
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||||
|
#endif
|
||||||
|
uint32_t hash = len, tmp;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
if (len <= 0 || data == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rem = len & 3;
|
||||||
|
len >>= 2;
|
||||||
|
|
||||||
|
/* Main loop */
|
||||||
|
for (;len > 0; len--) {
|
||||||
|
hash += get16bits (data);
|
||||||
|
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||||
|
hash = (hash << 16) ^ tmp;
|
||||||
|
data += 2 * sizeof (uint16_t);
|
||||||
|
hash += hash >> 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle end cases */
|
||||||
|
switch (rem) {
|
||||||
|
case 3: hash += get16bits (data);
|
||||||
|
hash ^= hash << 16;
|
||||||
|
hash ^= data[sizeof (uint16_t)] << 18;
|
||||||
|
hash += hash >> 11;
|
||||||
|
break;
|
||||||
|
case 2: hash += get16bits (data);
|
||||||
|
hash ^= hash << 11;
|
||||||
|
hash += hash >> 17;
|
||||||
|
break;
|
||||||
|
case 1: hash += *data;
|
||||||
|
hash ^= hash << 10;
|
||||||
|
hash += hash >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force "avalanching" of final 127 bits */
|
||||||
|
hash ^= hash << 3;
|
||||||
|
hash += hash >> 5;
|
||||||
|
hash ^= hash << 4;
|
||||||
|
hash += hash >> 17;
|
||||||
|
hash ^= hash << 25;
|
||||||
|
hash += hash >> 6;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
#undef get16bits
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
|
||||||
|
{
|
||||||
|
uint32_t bucket = hash & bucketmask;
|
||||||
|
Symbol **pkvs = &buckets[bucket];
|
||||||
|
|
||||||
|
Symbol *kvs = *pkvs;
|
||||||
|
while (kvs != NULL)
|
||||||
|
{
|
||||||
|
if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
|
||||||
|
{
|
||||||
|
return pkvs;
|
||||||
|
}
|
||||||
|
pkvs = &kvs->tbl_next;
|
||||||
|
kvs = *pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResizeSymbolTable()
|
||||||
|
{
|
||||||
|
uint32_t xnbuckets = nbuckets * 2;
|
||||||
|
Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
|
||||||
|
if (xbuckets == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
|
||||||
|
uint32_t xbucketmask = xnbuckets - 1;
|
||||||
|
for (uint32_t i = 0; i < nbuckets; i++)
|
||||||
|
{
|
||||||
|
Symbol *sym = buckets[i];
|
||||||
|
while (sym != NULL)
|
||||||
|
{
|
||||||
|
Symbol *next = sym->tbl_next;
|
||||||
|
uint32_t bucket = sym->hash & xbucketmask;
|
||||||
|
sym->tbl_next = xbuckets[bucket];
|
||||||
|
xbuckets[bucket] = sym;
|
||||||
|
sym = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buckets);
|
||||||
|
buckets = xbuckets;
|
||||||
|
nbuckets = xnbuckets;
|
||||||
|
bucketmask = xbucketmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *FindSymbol(const char *str, size_t len)
|
||||||
|
{
|
||||||
|
uint32_t hash = HashString(str, len);
|
||||||
|
Symbol **pkvs = FindSymbolBucket(str, len, hash);
|
||||||
|
return *pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *InternSymbol(const char* str, size_t len, void *address)
|
||||||
|
{
|
||||||
|
uint32_t hash = HashString(str, len);
|
||||||
|
Symbol **pkvs = FindSymbolBucket(str, len, hash);
|
||||||
|
if (*pkvs != NULL)
|
||||||
|
{
|
||||||
|
return *pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
|
||||||
|
kvs->length = len;
|
||||||
|
kvs->hash = hash;
|
||||||
|
kvs->address = address;
|
||||||
|
kvs->tbl_next = NULL;
|
||||||
|
memcpy(kvs + 1, str, sizeof(char) * (len + 1));
|
||||||
|
*pkvs = kvs;
|
||||||
|
nused++;
|
||||||
|
|
||||||
|
if (nused > nbuckets && nbuckets <= INT_MAX / 2)
|
||||||
|
{
|
||||||
|
ResizeSymbolTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return kvs;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
uint32_t nbuckets;
|
||||||
|
uint32_t nused;
|
||||||
|
uint32_t bucketmask;
|
||||||
|
Symbol **buckets;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
Loading…
Reference in New Issue
Block a user