diff --git a/core/Makefile b/core/Makefile index 650c5912..26ca408b 100644 --- a/core/Makefile +++ b/core/Makefile @@ -21,7 +21,7 @@ HL2LIB = $(HL2SDK)/linux_sdk OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \ Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \ - PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ + MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \ sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \ sourcemm_api.cpp sourcemod.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ diff --git a/core/MemoryUtils.cpp b/core/MemoryUtils.cpp new file mode 100644 index 00000000..a34c0e4e --- /dev/null +++ b/core/MemoryUtils.cpp @@ -0,0 +1,199 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "MemoryUtils.h" +#include "sm_platform.h" +#ifdef PLATFORM_LINUX +#include +#include +#endif + +MemoryUtils g_MemUtils; + +MemoryUtils::MemoryUtils() +{ +#ifdef PLATFORM_WINDOWS + + /* This might be used in the future? */ + #if 0 + SYSTEM_INFO info; + GetSystemInfo(&info); + + m_PageSize = info.dwPageSize; + #endif + +#elif defined PLATFORM_POSIX + + m_PageSize = sysconf(_SC_PAGE_SIZE); + +#endif +} + +void *MemoryUtils::FindPattern(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(lib.baseAddress); + end = ptr + lib.memorySize; + + 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; +} + +bool MemoryUtils::GetLibraryInfo(void *libPtr, DynLibInfo &lib) +{ + unsigned long baseAddr; + + if (libPtr == NULL) + { + return false; + } + +#ifdef PLATFORM_WINDOWS + + 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(info.AllocationBase); + + /* All this is for our insane sanity checks :o */ + dos = reinterpret_cast(baseAddr); + pe = reinterpret_cast(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 PLATFORM_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(info.dli_fbase); + file = reinterpret_cast(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(baseAddr + file->e_phoff); + + /* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */ + for (uint16_t i = 0; i < phdrCount; i++) + { + Elf32_Phdr &hdr = phdr[i]; + + if (hdr.p_type == PT_LOAD) + { + lib.memorySize += hdr.p_memsz; + } + } + +#endif + + lib.baseAddress = reinterpret_cast(baseAddr); + + return true; +} diff --git a/core/MemoryUtils.h b/core/MemoryUtils.h new file mode 100644 index 00000000..ecb9e278 --- /dev/null +++ b/core/MemoryUtils.h @@ -0,0 +1,42 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ +#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ + +#include + +using namespace SourceMod; + +struct DynLibInfo +{ + void *baseAddress; + size_t memorySize; +}; + +class MemoryUtils : public IMemoryUtils +{ +public: + MemoryUtils(); +public: + void *FindPattern(void *libPtr, const char *pattern, size_t len); +private: + bool GetLibraryInfo(void *libPtr, DynLibInfo &lib); +private: + size_t m_PageSize; +}; + +extern MemoryUtils g_MemUtils; + +#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 78cab260..dc0f2b06 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -325,6 +329,10 @@ RelativePath="..\Logger.h" > + + @@ -425,6 +433,10 @@ RelativePath="..\..\public\ILibrarySys.h" > + + diff --git a/public/IMemoryUtils.h b/public/IMemoryUtils.h new file mode 100644 index 00000000..29e1d9fb --- /dev/null +++ b/public/IMemoryUtils.h @@ -0,0 +1,53 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_INTERFACE_BINARYUTILS_H_ +#define _INCLUDE_SOURCEMOD_INTERFACE_BINARYUTILS_H_ + +#include + +#define SMINTERFACE_MEMORYUTILS_NAME "IMemoryUtils" +#define SMINTERFACE_MEMORYUTILS_VERSION 1 + +namespace SourceMod +{ + class IMemoryUtils : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_MEMORYUTILS_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_MEMORYUTILS_VERSION; + } + public: + /** + * @brief Searches for a pattern of bytes within the memory of a dynamic library. + * + * @param libPtr Pointer to any chunk of memory that resides in the dynamic library. + * @param pattern Pattern of bytes to search for. 0x2A can be used as a wildcard. + * @param len Size of the pattern in bytes. + * @return Pointer to pattern found in memory, NULL if not found. + */ + virtual void *FindPattern(void *libPtr, const char *pattern, size_t len) =0; + }; +} + +#endif // _INCLUDE_SOURCEMOD_INTERFACE_MEMORYUTILS_H_ diff --git a/public/IShareSys.h b/public/IShareSys.h index 99cbf7a7..c70912b2 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -58,7 +58,7 @@ namespace SourceMod virtual const char *GetInterfaceName() =0; /** - * @brief Must return whether the requested version number is backwards comaptible. + * @brief Must return whether the requested version number is backwards compatible. * Note: This can be overridden for breaking changes or custom versioning. * * @param version Version number to compare against.