From edc56b1c98beac5f19a273695f66b8bc58722938 Mon Sep 17 00:00:00 2001 From: manuel Date: Sat, 9 Mar 2013 15:28:20 +0100 Subject: add signature scanner --- ModuleScanner.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++ ModuleScanner.h | 18 ++++++++ sigscan.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sigscan.h | 64 ++++++++++++++++++++++++++++ 4 files changed, 305 insertions(+) create mode 100644 ModuleScanner.cpp create mode 100644 ModuleScanner.h create mode 100644 sigscan.cpp create mode 100644 sigscan.h diff --git a/ModuleScanner.cpp b/ModuleScanner.cpp new file mode 100644 index 0000000..831f87a --- /dev/null +++ b/ModuleScanner.cpp @@ -0,0 +1,99 @@ +#include "ModuleScanner.h" +#include +#include +#include +#include + +CModuleScanner::CModuleScanner(void *addr) + : m_addr(addr) +{} + +void *CModuleScanner::FindSignature(const char *sig, const char *pattern) +{ + DynLibInfo lib; + bool found; + char *ptr, *end; + size_t len = strlen(pattern); + + memset(&lib, 0, sizeof(DynLibInfo)); + + if (!GetLibraryInfo(m_addr, 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] != '?' && sig[i] != ptr[i]) + { + found = false; + break; + } + } + + if (found) + return ptr; + + ptr++; + } + + return NULL; +} + +bool CModuleScanner::GetLibraryInfo(const void *libPtr, DynLibInfo &lib) +{ + unsigned long baseAddr; + Dl_info info; + Elf32_Ehdr *file; + Elf32_Phdr *phdr; + uint16_t phdrCount; + + if (libPtr == NULL) + return false; + + 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; + } + + lib.baseAddress = reinterpret_cast(baseAddr); + return true; +} diff --git a/ModuleScanner.h b/ModuleScanner.h new file mode 100644 index 0000000..7fe2fdb --- /dev/null +++ b/ModuleScanner.h @@ -0,0 +1,18 @@ +#include + +struct DynLibInfo +{ + void *baseAddress; + size_t memorySize; +}; + +class CModuleScanner +{ + public: + CModuleScanner(void *addr); + void *FindSignature(const char *sig, const char *pattern); + + private: + bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib); + void *m_addr; +}; diff --git a/sigscan.cpp b/sigscan.cpp new file mode 100644 index 0000000..f8ab0e3 --- /dev/null +++ b/sigscan.cpp @@ -0,0 +1,124 @@ +#include +#include "sigscan.h" + +/* There is no ANSI ustrncpy */ +unsigned char* ustrncpy(unsigned char *dest, const unsigned char *src, int len) { + while(len--) + dest[len] = src[len]; + + return dest; +} + +/* ////////////////////////////////////// + CSigScan Class + ////////////////////////////////////// */ +unsigned char* CSigScan::base_addr; +size_t CSigScan::base_len; +void *(*CSigScan::sigscan_dllfunc)(const char *pName, int *pReturnCode); + +/* Initialize the Signature Object */ +int CSigScan::Init(const unsigned char *sig, const char *mask, size_t len) { + is_set = 0; + + sig_len = len; + + if ( sig_str ) + delete[] sig_str; + + sig_str = new unsigned char[sig_len]; + ustrncpy(sig_str, sig, sig_len); + + if ( sig_mask ) + delete[] sig_mask; + + sig_mask = new char[sig_len/*+1*/]; + strncpy(sig_mask, mask, sig_len); + //sig_mask[sig_len+1] = 0; + + if(!base_addr) + return 2; // GetDllMemInfo() Failed + + if((sig_addr = FindSignature()) == NULL) + return 1; // FindSignature() Failed + + is_set = 1; + // SigScan Successful! + + return 0; +} + +/* Destructor frees sig-string allocated memory */ +CSigScan::~CSigScan(void) { + delete[] sig_str; + delete[] sig_mask; +} + +/* Get base address of the server module (base_addr) and get its ending offset (base_len) */ +bool CSigScan::GetDllMemInfo(void) { + void *pAddr = (void*)sigscan_dllfunc; + base_addr = 0; + base_len = 0; + + #ifdef WIN32 + MEMORY_BASIC_INFORMATION mem; + + if(!pAddr) + return false; // GetDllMemInfo failed!pAddr + + if(!VirtualQuery(pAddr, &mem, sizeof(mem))) + return false; + + base_addr = (unsigned char*)mem.AllocationBase; + + IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER*)mem.AllocationBase; + IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS*)((unsigned long)dos+(unsigned long)dos->e_lfanew); + + if(pe->Signature != IMAGE_NT_SIGNATURE) { + base_addr = 0; + return false; // GetDllMemInfo failedpe points to a bad location + } + + base_len = (size_t)pe->OptionalHeader.SizeOfImage; + + #else + + Dl_info info; + struct stat buf; + + if(!dladdr(pAddr, &info)) + return false; + + if(!info.dli_fbase || !info.dli_fname) + return false; + + if(stat(info.dli_fname, &buf) != 0) + return false; + + base_addr = (unsigned char*)info.dli_fbase; + base_len = buf.st_size; + #endif + + return true; +} + +/* Scan for the signature in memory then return the starting position's address */ +void* CSigScan::FindSignature(void) { + unsigned char *pBasePtr = base_addr; + unsigned char *pEndPtr = base_addr+base_len; + size_t i; + + while(pBasePtr < pEndPtr) { + for(i = 0;i < sig_len;i++) { + if((sig_mask[i] != '?') && (sig_str[i] != pBasePtr[i])) + break; + } + + // If 'i' reached the end, we know we have a match! + if(i == sig_len) + return (void*)pBasePtr; + + pBasePtr++; + } + + return NULL; +} diff --git a/sigscan.h b/sigscan.h new file mode 100644 index 0000000..f6727a9 --- /dev/null +++ b/sigscan.h @@ -0,0 +1,64 @@ +#ifndef SIGSCAN_H +#define SIGSCAN_H + +#include + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include +#else + #include + #include + #include +#endif + +class CSigScan { +private: + /* Private Variables */ + /* Base Address of the server module in memory */ + static unsigned char *base_addr; + /* The length to the module's ending address */ + static size_t base_len; + + /* The signature to scan for */ + unsigned char *sig_str; + /* A mask to ignore certain bytes in the signature such as addresses + The mask should be as long as all the bytes in the signature string + Use '?' to ignore a byte and 'x' to check it + Example: "xxx????xx" - The first 3 bytes are checked, then the next 4 are + ignored, then the last 2 are checked */ + char *sig_mask; + /* The length of sig_str and sig_mask (not including a terminating null for sig_mask) */ + size_t sig_len; + + /* Private Functions */ + void* FindSignature(void); + +public: + /* Public Variables */ + + /* sigscan_dllfunc is a pointer of something that resides inside the gamedll so we can get + the base address of it. From a SourceMM plugin, just set this to ismm->serverFactory(0) + in Load(). From a Valve Server Plugin, you must set this to an actual factory returned + from gameServerFactory and hope that a SourceMM plugin did not override it. */ + static void *(*sigscan_dllfunc)(const char *pName, int *pReturnCode); + + /* If the scan was successful or not */ + char is_set; + /* Starting address of the found function */ + void *sig_addr; + + CSigScan(void): sig_str(NULL), sig_mask(NULL), sig_len(0), sig_addr(NULL) {} + ~CSigScan(void); + + static bool GetDllMemInfo(void); + int Init(const unsigned char *sig, const char *mask, size_t len); +}; + +/* Sigscanned member functions are casted to member function pointers of this class + and called with member function pointer syntax */ +class EmptyClass { }; + +void InitSigs(void); + +#endif -- cgit v1.2.3