From f130a8ea89b846741267db0e6cef4224447497f6 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Fri, 30 May 2014 00:13:03 +0200 Subject: [PATCH] Cstrike: Implement CS_OnBuy forward. --- dlls/cstrike/cstrike/CstrikeDatas.h | 89 +++++++++++- dlls/cstrike/cstrike/CstrikeHacks.cpp | 195 +++++++++++++++++++++----- dlls/cstrike/cstrike/CstrikeUtils.h | 32 +++++ dlls/cstrike/cstrike/amxx_api.cpp | 3 + plugins/include/cstrike.inc | 50 +++++++ public/memtools/CDetour/detours.h | 14 +- public/memtools/MemoryUtils.cpp | 52 ++++++- public/memtools/MemoryUtils.h | 8 ++ 8 files changed, 404 insertions(+), 39 deletions(-) diff --git a/dlls/cstrike/cstrike/CstrikeDatas.h b/dlls/cstrike/cstrike/CstrikeDatas.h index b237b34e..b4af6ceb 100644 --- a/dlls/cstrike/cstrike/CstrikeDatas.h +++ b/dlls/cstrike/cstrike/CstrikeDatas.h @@ -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< #include "CDetour/detours.h" @@ -6,24 +39,32 @@ #include #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(player), static_cast(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(player), static_cast(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<(player), static_cast(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(); } } diff --git a/dlls/cstrike/cstrike/CstrikeUtils.h b/dlls/cstrike/cstrike/CstrikeUtils.h index 0cdd0f95..6e60842b 100644 --- a/dlls/cstrike/cstrike/CstrikeUtils.h +++ b/dlls/cstrike/cstrike/CstrikeUtils.h @@ -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 \ No newline at end of file diff --git a/dlls/cstrike/cstrike/amxx_api.cpp b/dlls/cstrike/cstrike/amxx_api.cpp index 730ce81a..e190e4a5 100644 --- a/dlls/cstrike/cstrike/amxx_api.cpp +++ b/dlls/cstrike/cstrike/amxx_api.cpp @@ -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() diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index 2c0e85a8..f8139107 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -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); diff --git a/public/memtools/CDetour/detours.h b/public/memtools/CDetour/detours.h index 797cb1c8..dea92c42 100644 --- a/public/memtools/CDetour/detours.h +++ b/public/memtools/CDetour/detours.h @@ -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)(); diff --git a/public/memtools/MemoryUtils.cpp b/public/memtools/MemoryUtils.cpp index 843d0f6f..5226c3c3 100644 --- a/public/memtools/MemoryUtils.cpp +++ b/public/memtools/MemoryUtils.cpp @@ -29,6 +29,7 @@ #include "MemoryUtils.h" #include +#include #if defined(__linux__) #include @@ -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; +} \ No newline at end of file diff --git a/public/memtools/MemoryUtils.h b/public/memtools/MemoryUtils.h index 1e7a5fdc..b7b49662 100644 --- a/public/memtools/MemoryUtils.h +++ b/public/memtools/MemoryUtils.h @@ -44,6 +44,10 @@ #include #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 m_SymTables;