Improve game detection further for some engines when -game missing

This commit is contained in:
Nicholas Hastings 2014-08-06 11:42:05 -07:00
parent 80c48e9eec
commit 6b370180f4
3 changed files with 633 additions and 377 deletions

View File

@ -1,384 +1,405 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 sw=4 tw=99 noet :
* ====================================================== * ======================================================
* Metamod:Source * Metamod:Source
* Copyright (C) 2004-2010 AlliedModders LLC and authors. * Copyright (C) 2004-2010 AlliedModders LLC and authors.
* All rights reserved. * All rights reserved.
* ====================================================== * ======================================================
* *
* This software is provided 'as-is', without any express or implied warranty. * This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from * In no event will the authors be held liable for any damages arising from
* the use of this software. * the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, * Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it * including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions: * freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not * 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a * claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be * product, an acknowledgment in the product documentation would be
* appreciated but is not required. * appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be * 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software. * misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
*/ */
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "loader.h" #include "loader.h"
#include "serverplugin.h" #include "serverplugin.h"
#include "gamedll.h" #include "gamedll.h"
#include "utility.h" #include "utility.h"
#if defined __APPLE__ #if defined __APPLE__
#include <crt_externs.h> #include <crt_externs.h>
#endif #endif
static HMODULE mm_library = NULL; static HMODULE mm_library = NULL;
static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log"; static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log";
MetamodBackend mm_backend = MMBackend_UNKNOWN; MetamodBackend mm_backend = MMBackend_UNKNOWN;
extern void extern void
mm_LogFatal(const char *message, ...) mm_LogFatal(const char *message, ...)
{ {
FILE *fp; FILE *fp;
time_t t; time_t t;
va_list ap; va_list ap;
char header[256]; char header[256];
fp = fopen(mm_fatal_logfile, "at"); fp = fopen(mm_fatal_logfile, "at");
if (!fp && (fp = fopen("metamod-fatal.log", "at")) == NULL) if (!fp && (fp = fopen("metamod-fatal.log", "at")) == NULL)
return; return;
t = time(NULL); t = time(NULL);
strftime(header, sizeof(header), "%m/%d/%Y - %H:%M:%S", localtime(&t)); strftime(header, sizeof(header), "%m/%d/%Y - %H:%M:%S", localtime(&t));
fprintf(fp, "L %s: ", header); fprintf(fp, "L %s: ", header);
va_start(ap, message); va_start(ap, message);
vfprintf(fp, message, ap); vfprintf(fp, message, ap);
va_end(ap); va_end(ap);
fprintf(fp, "\n"); fprintf(fp, "\n");
fclose(fp); fclose(fp);
} }
static const char *backend_names[] = static const char *backend_names[] =
{ {
"1.ep1", "1.ep1",
"2.darkm", "2.darkm",
"2.ep2", "2.ep2",
"2.bgt", "2.bgt",
"2.eye", "2.eye",
"2.css", "2.css",
"2.ep2v", "2.ep2v",
"2.l4d", "2.l4d",
"2.l4d2", "2.l4d2",
"2.swarm", "2.swarm",
"2.portal2", "2.portal2",
"2.csgo", "2.csgo",
"2.dota", "2.dota",
"2.hl2dm", "2.hl2dm",
"2.dods", "2.dods",
"2.tf2", "2.tf2",
"2.nd", "2.nd",
"2.sdk2013", "2.sdk2013",
"2.blade", "2.blade",
"2.insurgency", "2.insurgency",
"2.contagion", "2.contagion",
}; };
#if defined _WIN32 #if defined _WIN32
#define LIBRARY_EXT ".dll" #define LIBRARY_EXT ".dll"
#define LIBRARY_MINEXT ".dll" #define LIBRARY_MINEXT ".dll"
#elif defined __APPLE__ #elif defined __APPLE__
#define LIBRARY_EXT ".dylib" #define LIBRARY_EXT ".dylib"
#define LIBRARY_MINEXT ".dylib" #define LIBRARY_MINEXT ".dylib"
#elif defined __linux__ #elif defined __linux__
#define LIBRARY_EXT LIB_SUFFIX #define LIBRARY_EXT LIB_SUFFIX
#define LIBRARY_MINEXT ".so" #define LIBRARY_MINEXT ".so"
#endif #endif
bool bool
mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength) mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength)
{ {
size_t len, temp_len; size_t len, temp_len;
char mm_path[PLATFORM_MAX_PATH * 2]; char mm_path[PLATFORM_MAX_PATH * 2];
/* Get our path */ /* Get our path */
if (!mm_GetFileOfAddress((void*)mm_GetFileOfAddress, mm_path, sizeof(mm_path))) if (!mm_GetFileOfAddress((void*)mm_GetFileOfAddress, mm_path, sizeof(mm_path)))
return false; return false;
len = strlen(mm_path); len = strlen(mm_path);
temp_len = strlen("server" LIBRARY_EXT); temp_len = strlen("server" LIBRARY_EXT);
if (len < temp_len) if (len < temp_len)
return false; return false;
/* Build log file name */ /* Build log file name */
mm_path[len - temp_len] = '\0'; mm_path[len - temp_len] = '\0';
mm_Format(mm_fatal_logfile, mm_Format(mm_fatal_logfile,
sizeof(mm_fatal_logfile), sizeof(mm_fatal_logfile),
"%smetamod-fatal.log", "%smetamod-fatal.log",
mm_path); mm_path);
/* Replace server.dll with the new binary we want */ /* Replace server.dll with the new binary we want */
mm_Format(&mm_path[len - temp_len], mm_Format(&mm_path[len - temp_len],
sizeof(mm_path) - (len - temp_len), sizeof(mm_path) - (len - temp_len),
"metamod.%s" LIBRARY_MINEXT, "metamod.%s" LIBRARY_MINEXT,
backend_names[backend]); backend_names[backend]);
mm_library = (HMODULE)mm_LoadLibrary(mm_path, buffer, maxlength); mm_library = (HMODULE)mm_LoadLibrary(mm_path, buffer, maxlength);
return (mm_library != NULL); return (mm_library != NULL);
} }
void void
mm_UnloadMetamodLibrary() mm_UnloadMetamodLibrary()
{ {
mm_UnloadLibrary(mm_library); mm_UnloadLibrary(mm_library);
mm_library = NULL; mm_library = NULL;
} }
#if defined _WIN32 #if defined _WIN32
#define EXPORT extern "C" __declspec(dllexport) #define EXPORT extern "C" __declspec(dllexport)
#elif defined __GNUC__ #elif defined __GNUC__
#if __GNUC__ == 4 #if __GNUC__ == 4
#define EXPORT extern "C" __attribute__ ((visibility("default"))) #define EXPORT extern "C" __attribute__ ((visibility("default")))
#else #else
#define EXPORT extern "C" #define EXPORT extern "C"
#endif #endif
#endif #endif
EXPORT void * EXPORT void *
CreateInterface(const char *name, int *ret) CreateInterface(const char *name, int *ret)
{ {
/* If we've got a VSP bridge, do nothing. */ /* If we've got a VSP bridge, do nothing. */
if (vsp_bridge != NULL) if (vsp_bridge != NULL)
{ {
if (ret != NULL) if (ret != NULL)
*ret = 1; *ret = 1;
return NULL; return NULL;
} }
void *ptr; void *ptr;
if (strncmp(name, "ISERVERPLUGINCALLBACKS", 22) == 0) if (strncmp(name, "ISERVERPLUGINCALLBACKS", 22) == 0)
{ {
/* Either load as VSP or start VSP listener */ /* Either load as VSP or start VSP listener */
ptr = mm_GetVspCallbacks(atoi(&name[22])); ptr = mm_GetVspCallbacks(atoi(&name[22]));
} }
else if (gamedll_bridge == NULL) else if (gamedll_bridge == NULL)
{ {
/* Load as gamedll */ /* Load as gamedll */
ptr = mm_GameDllRequest(name, ret); ptr = mm_GameDllRequest(name, ret);
} }
else else
{ {
/* If we've got a gamedll bridge, forward the request. */ /* If we've got a gamedll bridge, forward the request. */
return gamedll_bridge->QueryInterface(name, ret); return gamedll_bridge->QueryInterface(name, ret);
} }
if (ret != NULL) if (ret != NULL)
*ret = (ptr != NULL) ? 0 : 1; *ret = (ptr != NULL) ? 0 : 1;
return ptr; return ptr;
} }
void * void *
mm_GetProcAddress(const char *name) mm_GetProcAddress(const char *name)
{ {
return mm_GetLibAddress(mm_library, name); return mm_GetLibAddress(mm_library, name);
} }
void void
mm_GetGameName(char *buffer, size_t size) mm_GetGameName(char *buffer, size_t size)
{ {
buffer[0] = '\0'; buffer[0] = '\0';
#if defined _WIN32 #if defined _WIN32
static char game[128]; static char game[128];
LPWSTR pCmdLine = GetCommandLineW(); LPWSTR pCmdLine = GetCommandLineW();
int argc; int argc;
LPWSTR *wargv = CommandLineToArgvW(pCmdLine, &argc); LPWSTR *wargv = CommandLineToArgvW(pCmdLine, &argc);
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
{ {
if (wcscmp(wargv[i], L"-game") != 0) if (wcscmp(wargv[i], L"-game") != 0)
continue; continue;
if (++i >= argc) if (++i >= argc)
break; break;
wcstombs(buffer, wargv[i], size); wcstombs(buffer, wargv[i], size);
buffer[size-1] = '\0'; buffer[size-1] = '\0';
break; break;
} }
LocalFree(wargv); LocalFree(wargv);
#elif defined __APPLE__ #elif defined __APPLE__
int argc = *_NSGetArgc(); int argc = *_NSGetArgc();
char **argv = *_NSGetArgv(); char **argv = *_NSGetArgv();
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
{ {
if (strcmp(argv[i], "-game") != 0) if (strcmp(argv[i], "-game") != 0)
continue; continue;
if (++i >= argc) if (++i >= argc)
break; break;
strncpy(buffer, argv[i], size); strncpy(buffer, argv[i], size);
buffer[size-1] = '\0'; buffer[size-1] = '\0';
break; break;
} }
#elif defined __linux__ #elif defined __linux__
FILE *pFile = fopen("/proc/self/cmdline", "rb"); FILE *pFile = fopen("/proc/self/cmdline", "rb");
if (pFile) if (pFile)
{ {
char *arg = NULL; char *arg = NULL;
size_t argsize = 0; size_t argsize = 0;
bool bNextIsGame = false; bool bNextIsGame = false;
while (getdelim(&arg, &argsize, 0, pFile) != -1) while (getdelim(&arg, &argsize, 0, pFile) != -1)
{ {
if (bNextIsGame) if (bNextIsGame)
{ {
strncpy(buffer, arg, size); strncpy(buffer, arg, size);
buffer[size-1] = '\0'; buffer[size-1] = '\0';
break; break;
} }
if (strcmp(arg, "-game") == 0) if (strcmp(arg, "-game") == 0)
{ {
bNextIsGame = true; bNextIsGame = true;
} }
} }
free(arg); free(arg);
fclose(pFile); fclose(pFile);
} }
#else #else
#error unsupported platform #error unsupported platform
#endif #endif
if (buffer[0] == 0) if (buffer[0] == 0)
{ {
strncpy(buffer, ".", size); strncpy(buffer, ".", size);
} }
} }
MetamodBackend MetamodBackend
mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serverFactory, const char *game_name) mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serverFactory, const char *game_name)
{ {
if (engineFactory("VEngineServer024", NULL) != NULL) if (engineFactory("VEngineServer024", NULL) != NULL)
{ {
return MMBackend_DOTA; return MMBackend_DOTA;
} }
else if (engineFactory("VEngineServer023", NULL) != NULL) else if (engineFactory("VEngineServer023", NULL) != NULL)
{ {
if (engineFactory("IEngineSoundServer004", NULL) != NULL) if (engineFactory("IEngineSoundServer004", NULL) != NULL)
{ {
return MMBackend_Insurgency; return MMBackend_Insurgency;
} }
return MMBackend_CSGO; return MMBackend_CSGO;
} }
else if (engineFactory("VEngineServer022", NULL) != NULL && else if (engineFactory("VEngineServer022", NULL) != NULL &&
engineFactory("VEngineCvar007", NULL) != NULL) engineFactory("VEngineCvar007", NULL) != NULL)
{ {
if (engineFactory("EngineTraceServer004", NULL) != NULL) if (engineFactory("EngineTraceServer004", NULL) != NULL)
{ {
if (engineFactory("XboxSystemInterface001", NULL) != NULL) if (engineFactory("XboxSystemInterface001", NULL) != NULL)
{ {
return MMBackend_AlienSwarm; return MMBackend_AlienSwarm;
} }
if (strcmp(game_name, "portal2") == 0) void *lib = (void *)serverFactory;
{ void *addr;
return MMBackend_Portal2; if (strcmp(game_name, "portal2") == 0
} || (addr = mm_FindPattern(lib, "baseportalcombatweapon", sizeof("baseportalcombatweapon") - 1)))
{
return MMBackend_Blade; return MMBackend_Portal2;
} }
else if (engineFactory("VPrecacheSystem001", NULL) != NULL)
{ return MMBackend_Blade;
if (engineFactory("ServerGameTags002", NULL) != NULL) }
{ else if (engineFactory("VPrecacheSystem001", NULL) != NULL)
return MMBackend_NuclearDawn; {
} if (engineFactory("ServerGameTags002", NULL) != NULL)
else if (strcmp(game_name, "contagion") == 0) {
{ return MMBackend_NuclearDawn;
return MMBackend_Contagion; }
} else
else {
{ void *lib = (void *)serverFactory;
return MMBackend_Left4Dead2; void *addr;
} if (strcmp(game_name, "contagion") == 0
} || (addr = mm_FindPattern(lib, "Contagion_Chat_All", sizeof("Contagion_Chat_All") - 1)))
{
return MMBackend_Left4Dead; return MMBackend_Contagion;
} }
else if (engineFactory("VEngineServer021", NULL) != NULL) else
{ {
/* Check for OB */ return MMBackend_Left4Dead2;
if (engineFactory("VEngineCvar004", NULL) != NULL) }
{ }
if (engineFactory("VModelInfoServer002", NULL) != NULL) }
{
/* BGT has same iface version numbers and libs as ep2 */ return MMBackend_Left4Dead;
if (strcmp(game_name, "pm") == 0) }
{ else if (engineFactory("VEngineServer021", NULL) != NULL)
return MMBackend_BloodyGoodTime; {
} /* Check for OB */
else if (engineFactory("VEngineCvar004", NULL) != NULL)
{ {
return MMBackend_Episode2; if (engineFactory("VModelInfoServer002", NULL) != NULL)
} {
} /* BGT has same iface version numbers and libs as ep2 */
else if (engineFactory("VModelInfoServer003", NULL) != NULL) void *lib = (void *)serverFactory;
{ void *addr;
if (engineFactory("VFileSystem017", NULL) != NULL) if (strcmp(game_name, "pm") == 0
{ || (addr = mm_FindPattern(lib, "DT_PMPlayerResource", sizeof("DT_PMPlayerResource") - 1)))
return MMBackend_EYE; {
} return MMBackend_BloodyGoodTime;
else if (strcmp(game_name, "cstrike") == 0) }
{ else
return MMBackend_CSS; {
} return MMBackend_Episode2;
else if (strcmp(game_name, "tf") == 0) }
{ }
return MMBackend_TF2; else if (engineFactory("VModelInfoServer003", NULL) != NULL)
} {
else if (strcmp(game_name, "dod") == 0) if (engineFactory("VFileSystem017", NULL) != NULL)
{ {
return MMBackend_DODS; return MMBackend_EYE;
} }
else if (strcmp(game_name, "hl2mp") == 0) else
{ {
return MMBackend_HL2DM; void *lib = (void *)serverFactory;
} void *addr;
else if (strcmp(game_name, "cstrike") == 0
{ || (addr = mm_FindPattern(lib, "DT_CSPlayerResource", sizeof("DT_CSPlayerResource") - 1)))
return MMBackend_SDK2013; {
} return MMBackend_CSS;
} }
} else if (strcmp(game_name, "tf") == 0
/* Check for Episode One/Old Engine */ || (addr = mm_FindPattern(lib, "DT_TFPlayerResource", sizeof("DT_TFPlayerResource") - 1)))
else if (engineFactory("VModelInfoServer001", NULL) != NULL && {
(engineFactory("VEngineCvar003", NULL) != NULL || return MMBackend_TF2;
engineFactory("VEngineCvar002", NULL) != NULL)) }
{ else if (strcmp(game_name, "dod") == 0
/* Check for Dark Messiah which has a weird directory structure */ || (addr = mm_FindPattern(lib, "DT_DODPlayerResource", sizeof("DT_DODPlayerResource") - 1)))
if (strcmp(game_name, ".") == 0) {
{ return MMBackend_DODS;
return MMBackend_DarkMessiah; }
} else if (strcmp(game_name, "hl2mp") == 0
return MMBackend_Episode1; || (addr = mm_FindPattern(lib, "Half-Life 2 Deathmatch", sizeof("Half-Life 2 Deathmatch") - 1)))
} {
} return MMBackend_HL2DM;
}
return MMBackend_UNKNOWN; else
} {
return MMBackend_SDK2013;
}
}
}
}
/* Check for Episode One/Old Engine */
else if (engineFactory("VModelInfoServer001", NULL) != NULL &&
(engineFactory("VEngineCvar003", NULL) != NULL ||
engineFactory("VEngineCvar002", NULL) != NULL))
{
/* Check for Dark Messiah which has a weird directory structure */
if (strcmp(game_name, ".") == 0)
{
return MMBackend_DarkMessiah;
}
return MMBackend_Episode1;
}
}
return MMBackend_UNKNOWN;
}

View File

@ -34,6 +34,13 @@
#include "loader.h" #include "loader.h"
#include "utility.h" #include "utility.h"
#if defined __linux__
#include <link.h>
#define PAGE_SIZE 4096
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#endif
#if defined _WIN32 #if defined _WIN32
static void static void
mm_GetPlatformError(char *buffer, size_t maxlength) mm_GetPlatformError(char *buffer, size_t maxlength)
@ -345,3 +352,228 @@ mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
return true; return true;
} }
struct DynLibInfo
{
void *baseAddress;
size_t memorySize;
};
static bool
mm_GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
{
uintptr_t baseAddr;
if (libPtr == NULL)
{
return false;
}
#ifdef _WIN32
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<uintptr_t>(info.AllocationBase);
/* All this is for our insane sanity checks :o */
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(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 __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<uintptr_t>(info.dli_fbase);
file = reinterpret_cast<Elf32_Ehdr *>(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<Elf32_Phdr *>(baseAddr + file->e_phoff);
for (uint16_t i = 0; i < phdrCount; i++)
{
Elf32_Phdr &hdr = phdr[i];
/* We only really care about the segment with executable code */
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
{
/* From glibc, elf/dl-load.c:
* c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
* & ~(GLRO(dl_pagesize) - 1));
*
* In glibc, the segment file size is aligned up to the nearest page size and
* added to the virtual address of the segment. We just want the size here.
*/
lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
break;
}
}
#elif defined __APPLE__
Dl_info info;
struct mach_header *file;
struct segment_command *seg;
uint32_t cmd_count;
if (!dladdr(libPtr, &info))
{
return false;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
}
/* This is for our insane sanity checks :o */
baseAddr = (uintptr_t)info.dli_fbase;
file = (struct mach_header *)baseAddr;
/* Check Mach-O magic */
if (file->magic != MH_MAGIC)
{
return false;
}
/* Check architecture (32-bit/x86) */
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
{
return false;
}
/* For our purposes, this must be a dynamic library */
if (file->filetype != MH_DYLIB)
{
return false;
}
cmd_count = file->ncmds;
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
/* Add up memory sizes of mapped segments */
for (uint32_t i = 0; i < cmd_count; i++)
{
if (seg->cmd == LC_SEGMENT)
{
lib.memorySize += seg->vmsize;
}
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
}
#endif
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true;
}
void *mm_FindPattern(const void *libPtr, const char *pattern, size_t len)
{
DynLibInfo lib;
bool found;
char *ptr, *end;
memset(&lib, 0, sizeof(DynLibInfo));
if (!mm_GetLibraryInfo(libPtr, lib))
{
return NULL;
}
ptr = reinterpret_cast<char *>(lib.baseAddress);
end = ptr + lib.memorySize - len;
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;
}

View File

@ -66,5 +66,8 @@ mm_PathCmp(const char *path1, const char *path2);
extern bool extern bool
mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength); mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength);
extern void *
mm_FindPattern(const void *libPtr, const char *pattern, size_t len);
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ */ #endif /* _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ */