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