core/MemoryUtils.cpp
author Scott Ehlert <ds@alliedmods.net>
Fri Apr 20 18:32:33 2007 +0000 (2007-04-20)
changeset 700 2b715374ce25
child 701 85c77b23ae47
permissions -rw-r--r--
Basic signature scanning has arrived!
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "MemoryUtils.h"
    16 #include "sm_platform.h"
    17 #ifdef PLATFORM_LINUX
    18 #include <string.h>
    19 #include <elf.h>
    20 #endif
    21 
    22 MemoryUtils g_MemUtils;
    23 
    24 MemoryUtils::MemoryUtils()
    25 {
    26 #ifdef PLATFORM_WINDOWS
    27 
    28 	/* This might be used in the future? */
    29 	#if 0
    30 	SYSTEM_INFO info;
    31 	GetSystemInfo(&info);
    32 
    33 	m_PageSize = info.dwPageSize;
    34 	#endif
    35 
    36 #elif defined PLATFORM_POSIX
    37 
    38 	m_PageSize = sysconf(_SC_PAGE_SIZE);
    39 
    40 #endif
    41 }
    42 
    43 void *MemoryUtils::FindPattern(void *libPtr, const char *pattern, size_t len)
    44 {
    45 	DynLibInfo lib;
    46 	bool found;
    47 	char *ptr, *end;
    48 
    49 	memset(&lib, 0, sizeof(DynLibInfo));
    50 
    51 	if (!GetLibraryInfo(libPtr, lib))
    52 	{
    53 		return NULL;
    54 	}
    55 
    56 	ptr = reinterpret_cast<char *>(lib.baseAddress);
    57 	end = ptr + lib.memorySize;
    58 
    59 	while (ptr < end)
    60 	{
    61 		found = true;
    62 		for (register size_t i = 0; i < len; i++)
    63 		{
    64 			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
    65 			{
    66 				found = false;
    67 				break;
    68 			}
    69 		}
    70 
    71 		if (found)
    72 			return ptr;
    73 
    74 		ptr++;
    75 	}
    76 
    77 	return NULL;
    78 }
    79 
    80 bool MemoryUtils::GetLibraryInfo(void *libPtr, DynLibInfo &lib)
    81 {
    82 	unsigned long baseAddr;
    83 
    84 	if (libPtr == NULL)
    85 	{
    86 		return false;
    87 	}
    88 
    89 #ifdef PLATFORM_WINDOWS
    90 
    91 	MEMORY_BASIC_INFORMATION info;
    92 	IMAGE_DOS_HEADER *dos;
    93 	IMAGE_NT_HEADERS *pe;
    94 	IMAGE_FILE_HEADER *file;
    95 	IMAGE_OPTIONAL_HEADER *opt;
    96 
    97 	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
    98 	{
    99 		return false;
   100 	}
   101 
   102 	baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
   103 
   104 	/* All this is for our insane sanity checks :o */
   105 	dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
   106 	pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
   107 	file = &pe->FileHeader;
   108 	opt = &pe->OptionalHeader;
   109 
   110 	/* Check PE magic and signature */
   111 	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
   112 	{
   113 		return false;
   114 	}
   115 
   116 	/* Check architecture, which is 32-bit/x86 right now
   117 	 * Should change this for 64-bit if Valve gets their act together
   118 	 */
   119 	if (file->Machine != IMAGE_FILE_MACHINE_I386)
   120 	{
   121 		return false;
   122 	}
   123 
   124 	/* For our purposes, this must be a dynamic library */
   125 	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
   126 	{
   127 		return false;
   128 	}
   129 
   130 	/* Finally, we can do this */
   131 	lib.memorySize = opt->SizeOfImage;
   132 
   133 #elif defined PLATFORM_LINUX
   134 
   135 	Dl_info info;
   136 	Elf32_Ehdr *file;
   137 	Elf32_Phdr *phdr;
   138 	uint16_t phdrCount;
   139 
   140 	if (!dladdr(libPtr, &info))
   141 	{
   142 		return false;
   143 	}
   144 
   145 	if (!info.dli_fbase || !info.dli_fname)
   146 	{
   147 		return false;
   148 	}
   149 
   150 	/* This is for our insane sanity checks :o */
   151 	baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
   152 	file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
   153 
   154 	/* Check ELF magic */
   155 	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
   156 	{
   157 		return false;
   158 	}
   159 
   160 	/* Check ELF version */
   161 	if (file->e_ident[EI_VERSION] != EV_CURRENT)
   162 	{
   163 		return false;
   164 	}
   165 
   166 	/* Check ELF architecture, which is 32-bit/x86 right now
   167 	 * Should change this for 64-bit if Valve gets their act together
   168 	 */
   169 	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
   170 	{
   171 		return false;
   172 	}
   173 
   174 	/* For our purposes, this must be a dynamic library/shared object */
   175 	if (file->e_type != ET_DYN)
   176 	{
   177 		return false;
   178 	}
   179 
   180 	phdrCount = file->e_phnum;
   181 	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
   182 	
   183 	/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
   184 	for (uint16_t i = 0; i < phdrCount; i++)
   185 	{
   186 		Elf32_Phdr &hdr = phdr[i];
   187 
   188 		if (hdr.p_type == PT_LOAD)
   189 		{
   190 			lib.memorySize += hdr.p_memsz;
   191 		}
   192 	}
   193 
   194 #endif
   195 
   196 	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
   197 
   198 	return true;
   199 }