Cstrike: Implement CS_OnBuy forward.

This commit is contained in:
Arkshine 2014-05-30 00:13:03 +02:00
parent 38e2e3e393
commit f130a8ea89
8 changed files with 404 additions and 39 deletions

View File

@ -1,3 +1,35 @@
/* 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_DATA_H
#define CSTRIKE_DATA_H
@ -123,10 +155,64 @@
#define CS_CLICMD_OFFS_BOTARGS 22
#endif
/**
* CS_OnBuy forward
*/
#if defined(__linux__)
#define CS_SYM_CANBUYTHIS "_Z10CanBuyThisP11CBasePlayeri"
#define CS_SYM_BUYITEM "_Z7BuyItemP11CBasePlayeri"
#define CS_SYM_BUYGUNAMMO "_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb"
#elif defined(__APPLE__)
#define CS_SYM_CANBUYTHIS "__Z10CanBuyThisP11CBasePlayeri"
#define CS_SYM_BUYITEM "__Z7BuyItemP11CBasePlayeri"
#define CS_SYM_BUYGUNAMMO "__Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb"
#elif defined(WIN32)
#define CS_SIG_CANBUYTHIS "\x53\x8B\x2A\x2A\x2A\x2A\x2A\x56\x8B\x2A\x2A\x2A\x57"
#define CS_SIG_BUYITEM "\x53\x56\x8B\x2A\x2A\x2A\xBB\x2A\x2A\x2A\x2A\x57\x53"
#define CS_SIG_BUYGUNAMMO "\x56\x57\x8B\x2A\x2A\x2A\x6A\x2A\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x84\x2A\x0F"
#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
#define CSW_P228 1
//#define CSW_SHIELD 2
#define CSW_SCOUT 3
#define CSW_HEGRENADE 4
#define CSW_XM1014 5
@ -157,6 +243,7 @@
#define CSW_P90 30
#define CSW_VEST 31 // Brand new invention!
#define CSW_VESTHELM 32 // Brand new invention!
#define CSW_SHIELDGUN 99
// These are used with armoury_entity:s.
#define CSA_MP5NAVY 0

View File

@ -1,4 +1,37 @@
/* 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 "CstrikeDatas.h"
#include "CstrikeUtils.h"
#include <MemoryUtils.h>
#include "CDetour/detours.h"
@ -6,24 +39,32 @@
#include <mach-o/nlist.h>
#endif
void CtrlDetour_ClientCommand(bool set);
void CtrlDetours(bool set);
int g_CSCliCmdFwd = -1;
int g_CSBuyCmdFwd = -1;
int *g_UseBotArgs = NULL;
const char **g_BotArgs = NULL;
CDetour *g_ClientCommandDetour = NULL;
CDetour *g_CanBuyThisDetour = NULL;
CDetour *g_BuyItemDetour = NULL;
CDetour *g_BuyGunAmmoDetour = NULL;
void InitializeHacks()
{
CtrlDetour_ClientCommand(true);
CtrlDetours(true);
}
void ShutdownHacks()
{
CtrlDetour_ClientCommand(false);
CtrlDetours(false);
}
DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict)
DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity)
{
if (*g_UseBotArgs)
{
@ -39,58 +80,146 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict)
DETOUR_STATIC_CALL(C_ClientCommand)(pEdict);
}
void CtrlDetour_ClientCommand(bool set)
DETOUR_DECL_STATIC2(CanBuyThis, bool, void*, pvPlayer, int, weaponId) // bool CanBuyThis(CBasePlayer *pPlayer, int weaponId)
{
if (weaponId != CSI_SHIELDGUN) // This will be handled before with BuyItem. Avoiding duplicated call.
{
int player = PrivateToIndex(pvPlayer);
if (MF_IsPlayerAlive(player) && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(weaponId)) > 0)
{
return false;
}
}
return DETOUR_STATIC_CALL(CanBuyThis)(pvPlayer, weaponId);
}
DETOUR_DECL_STATIC2(BuyItem, void, void*, pvPlayer, int, iSlot) // void BuyItem(CBasePlayer *pPlayer, int iSlot)
{
int player = PrivateToIndex(pvPlayer);
if (MF_IsPlayerAlive(player))
{
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);
}
DETOUR_DECL_STATIC3(BuyGunAmmo, bool, void*, pvPlayer, void*, pvWeapon, bool, bBlinkMoney) // bool BuyGunAmmo(CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney)
{
int player = PrivateToIndex(pvPlayer);
if (MF_IsPlayerAlive(player))
{
edict_t *pWeapon = PrivateToEdict(pvWeapon);
if (pWeapon)
{
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);
}
void CtrlDetours(bool set)
{
#if defined AMD64
#error UNSUPPORTED
#endif
void *target = (void *)MDLL_ClientCommand;
if (!g_UseBotArgs)
if (set)
{
#if defined(__linux__)
char libName[256];
uintptr_t base;
void *target = (void *)MDLL_ClientCommand;
if (!g_MemUtils.GetLibraryOfAddress(target, libName, sizeof(libName), &base))
{
return;
}
#if defined(WIN32)
void *canBuyThisAddress = g_MemUtils.DecodeAndFindPattern(target, CS_SIG_CANBUYTHIS);
void *buyItemAddress = g_MemUtils.DecodeAndFindPattern(target, CS_SIG_BUYITEM);
void *buyGunAmmoAddress = g_MemUtils.DecodeAndFindPattern(target, CS_SIG_BUYGUNAMMO);
g_UseBotArgs = *(int **)((unsigned char *)target + CS_CLICMD_OFFS_USEBOTARGS);
g_BotArgs = (const char **)*(const char **)((unsigned char *)target + CS_CLICMD_OFFS_BOTARGS);
#elif defined(__linux__)
void *canBuyThisAddress = g_MemUtils.ResolveSymbol(target, CS_SYM_CANBUYTHIS);
void *buyItemAddress = g_MemUtils.ResolveSymbol(target, CS_SYM_BUYITEM);
void *buyGunAmmoAddress = g_MemUtils.ResolveSymbol(target, CS_SYM_BUYGUNAMMO);
g_UseBotArgs = (int *)g_MemUtils.ResolveSymbol(target, "UseBotArgs");
g_BotArgs = (const char **)g_MemUtils.ResolveSymbol(target, "BotArgs");
#elif defined(__APPLE__)
/* Using dlsym on OS X won't work because the symbols are hidden */
char dll[256];
uintptr_t base;
g_MemUtils.GetLibraryOfAddress(target, dll, sizeof(dll), &base);
struct nlist symbols[3];
struct nlist symbols[6];
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);
#elif defined(WIN32)
symbols[0].n_un.n_name = (char *)CS_SYM_CANBUYTHIS;
symbols[1].n_un.n_name = (char *)CS_SYM_BUYITEM;
symbols[2].n_un.n_name = (char *)CS_SYM_BUYGUNAMMO;
symbols[3].n_un.n_name = (char *)"_UseBotArgs";
symbols[4].n_un.n_name = (char *)"_BotArgs";
g_UseBotArgs = *(int **)((unsigned char *)target + CS_CLICMD_OFFS_USEBOTARGS);
g_BotArgs = (const char **)*(const char **)((unsigned char *)target + CS_CLICMD_OFFS_BOTARGS);
if (nlist(libName, symbols) != 0) { return; }
void *canBuyThisAddress = (void *)(base + symbols[0].n_value);
void *buyItemAddress = (void *)(base + symbols[1].n_value);
void *buyGunAmmoAddress = (void *)(base + symbols[2].n_value);
void *g_UseBotArgs = (void *)(base + symbols[3].n_value);
void *g_BotArgs = (void *)(base + symbols[4].n_value);
#endif
}
if (set)
{
g_ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, target);
g_ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, target);
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_ClientCommandDetour != NULL)
{
g_ClientCommandDetour->EnableDetour();
else
{
MF_Log("No Client Commands detours could be initialized - Disabled Client Command forward.");
}
if (g_CanBuyThisDetour != NULL && g_BuyItemDetour != NULL && g_BuyGunAmmoDetour != NULL)
{
g_CanBuyThisDetour->EnableDetour();
g_BuyItemDetour->EnableDetour();
g_BuyGunAmmoDetour->EnableDetour();
}
else
{
MF_Log("No Buy Commands detours could be initialized - Disabled Buy forward.");
}
}
else
{
g_CanBuyThisDetour->Destroy();
g_BuyItemDetour->Destroy();
g_BuyGunAmmoDetour->Destroy();
g_ClientCommandDetour->Destroy();
}
}

View File

@ -84,4 +84,36 @@ void UTIL_TextMsg_Generic(edict_t* pPlayer, const char* message);
#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

View File

@ -33,7 +33,9 @@
#include "amxxmodule.h"
extern AMX_NATIVE_INFO cstrikeNatives[];
extern int g_CSCliCmdFwd;
extern int g_CSBuyCmdFwd;
void InitializeHacks();
void ShutdownHacks();
@ -57,6 +59,7 @@ void OnAmxxAttach()
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);
}
void OnAmxxDetach()

View File

@ -343,6 +343,7 @@ native cs_set_c4_explode_time(index, Float:value);
native bool:cs_get_c4_defusing(c4index);
native cs_set_c4_defusing(c4index, bool:defusing);
/**
* 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
@ -353,3 +354,52 @@ native cs_set_c4_defusing(c4index, bool:defusing);
* @return PLUGIN_HANDLED to block, PLUGIN_CONTINUE for normal operation.
*/
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 id Player index.
* @param item Item index, see CSI_* constants.
*/
forward CS_OnBuy(index, item);

View File

@ -56,6 +56,14 @@ ret name(void)
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)
@ -127,9 +135,9 @@ ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name
#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);
#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)();

View File

@ -29,6 +29,7 @@
#include "MemoryUtils.h"
#include <string.h>
#include <stdio.h>
#if defined(__linux__)
#include <fcntl.h>
@ -63,8 +64,6 @@
#endif // MAC_OS_X_VERSION_10_6
#endif // __APPLE__
MemoryUtils g_MemUtils;
MemoryUtils::MemoryUtils()
@ -103,6 +102,19 @@ MemoryUtils::~MemoryUtils()
#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;
@ -655,3 +667,39 @@ bool MemoryUtils::GetLibraryOfAddress(const void *libPtr, char *buffer, size_t m
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;
}

View File

@ -44,6 +44,10 @@
#include <windows.h>
#endif
#if defined _MSC_VER && _MSC_VER >= 1400
#pragma warning (disable:4996) /* Disable deprecation warnings */
#endif
struct DynLibInfo
{
void *baseAddress;
@ -66,6 +70,7 @@ class 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);
@ -73,6 +78,9 @@ class MemoryUtils
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;