1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-01-19 08:52:34 +01:00

Merge pull request #7 from alliedmodders/more-missing-game-param

Add detection for more games when -game param is missing (r=asherkin).
This commit is contained in:
Nicholas Hastings 2014-08-16 11:46:20 -04:00
commit b42445bbd4
3 changed files with 282 additions and 26 deletions

View File

@ -97,8 +97,8 @@ static const char *backend_names[] =
#elif defined __APPLE__
#define LIBRARY_EXT ".dylib"
#define LIBRARY_MINEXT ".dylib"
#elif defined __linux__
#define LIBRARY_EXT LIB_SUFFIX
#elif defined __linux__
#define LIBRARY_EXT LIB_SUFFIX
#define LIBRARY_MINEXT ".so"
#endif
@ -295,7 +295,10 @@ mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serve
return MMBackend_AlienSwarm;
}
if (strcmp(game_name, "portal2") == 0)
void *lib = (void *)serverFactory;
void *addr;
if (strcmp(game_name, "portal2") == 0
|| (addr = mm_FindPattern(lib, "baseportalcombatweapon", sizeof("baseportalcombatweapon") - 1)))
{
return MMBackend_Portal2;
}
@ -308,13 +311,19 @@ mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serve
{
return MMBackend_NuclearDawn;
}
else if (strcmp(game_name, "contagion") == 0)
{
return MMBackend_Contagion;
}
else
{
return MMBackend_Left4Dead2;
void *lib = (void *)serverFactory;
void *addr;
if (strcmp(game_name, "contagion") == 0
|| (addr = mm_FindPattern(lib, "Contagion_Chat_All", sizeof("Contagion_Chat_All") - 1)))
{
return MMBackend_Contagion;
}
else
{
return MMBackend_Left4Dead2;
}
}
}
@ -328,7 +337,10 @@ mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serve
if (engineFactory("VModelInfoServer002", NULL) != NULL)
{
/* BGT has same iface version numbers and libs as ep2 */
if (strcmp(game_name, "pm") == 0)
void *lib = (void *)serverFactory;
void *addr;
if (strcmp(game_name, "pm") == 0
|| (addr = mm_FindPattern(lib, "DT_PMPlayerResource", sizeof("DT_PMPlayerResource") - 1)))
{
return MMBackend_BloodyGoodTime;
}
@ -343,25 +355,34 @@ mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serve
{
return MMBackend_EYE;
}
else if (strcmp(game_name, "cstrike") == 0)
{
return MMBackend_CSS;
}
else if (strcmp(game_name, "tf") == 0)
{
return MMBackend_TF2;
}
else if (strcmp(game_name, "dod") == 0)
{
return MMBackend_DODS;
}
else if (strcmp(game_name, "hl2mp") == 0)
{
return MMBackend_HL2DM;
}
else
{
return MMBackend_SDK2013;
void *lib = (void *)serverFactory;
void *addr;
if (strcmp(game_name, "cstrike") == 0
|| (addr = mm_FindPattern(lib, "DT_CSPlayerResource", sizeof("DT_CSPlayerResource") - 1)))
{
return MMBackend_CSS;
}
else if (strcmp(game_name, "tf") == 0
|| (addr = mm_FindPattern(lib, "DT_TFPlayerResource", sizeof("DT_TFPlayerResource") - 1)))
{
return MMBackend_TF2;
}
else if (strcmp(game_name, "dod") == 0
|| (addr = mm_FindPattern(lib, "DT_DODPlayerResource", sizeof("DT_DODPlayerResource") - 1)))
{
return MMBackend_DODS;
}
else if (strcmp(game_name, "hl2mp") == 0
|| (addr = mm_FindPattern(lib, "Half-Life 2 Deathmatch", sizeof("Half-Life 2 Deathmatch") - 1)))
{
return MMBackend_HL2DM;
}
else
{
return MMBackend_SDK2013;
}
}
}
}

View File

@ -34,6 +34,13 @@
#include "loader.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
static void
mm_GetPlatformError(char *buffer, size_t maxlength)
@ -345,3 +352,228 @@ mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
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
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_ */