Browse Source

Move memory-scanning tooling to separate code units

Might reuse these in the future, so I'll go ahead and add the flexibility now.
nosoop 4 years ago
parent
commit
6581f407e0
4 changed files with 171 additions and 76 deletions
  1. 1 0
      AMBuildScript
  2. 109 0
      memscan.cpp
  3. 52 0
      memscan.h
  4. 9 76
      mmsplugin.cpp

+ 1 - 0
AMBuildScript

@@ -1,6 +1,7 @@
 proj_name = 'tf2dynschema'
 proj_srcs = [
   'mmsplugin.cpp',
+  'memscan.cpp',
 ]
 proj_c_flags = [
   '-Wall',

+ 109 - 0
memscan.cpp

@@ -0,0 +1,109 @@
+#include "memscan.h"
+
+uintptr_t FindPattern(uintptr_t start, uintptr_t end, const char* pattern, size_t length) {
+	uintptr_t ptr = start;
+	while (ptr < end - length) {
+		bool f = true;
+		const char* cur = reinterpret_cast<char*>(ptr);
+		for (register size_t i = 0; i < length; i++) {
+			if (pattern[i] != '\x2A' && pattern[i] != cur[i]) {
+				f = false;
+				break;
+			}
+		}
+		if (f) {
+			return ptr;
+		}
+		ptr++;
+	}
+	return 0;
+}
+
+#if WINDOWS
+CWinLibInfo::CWinLibInfo(void* pInBase) {
+	MEMORY_BASIC_INFORMATION info;
+	if (!VirtualQuery(pInBase, &info, sizeof(MEMORY_BASIC_INFORMATION))) {
+		this->m_bValid = false;
+		return;
+	}
+	uintptr_t base = reinterpret_cast<uintptr_t>(info.AllocationBase);
+	IMAGE_DOS_HEADER *dos = reinterpret_cast<IMAGE_DOS_HEADER *>(base);
+	IMAGE_NT_HEADERS *pe = reinterpret_cast<IMAGE_NT_HEADERS *>(base + dos->e_lfanew);
+	IMAGE_OPTIONAL_HEADER *opt = &pe->OptionalHeader;
+	size_t size = opt->SizeOfImage;
+	
+	this->m_StartRange = reinterpret_cast<uintptr_t>(info.AllocationBase);
+	this->m_EndRange = this->m_StartRange + size;
+	this->m_bValid = true;
+}
+
+bool CWinLibInfo::LocateSymbol(const char* name, void** result) {
+	return false;
+}
+
+bool CWinLibInfo::LocatePattern(const char* bytes, size_t length, void** result) {
+	if (!this->m_bValid) {
+		return false;
+	}
+	
+	uintptr_t pResult = FindPattern(this->m_StartRange, this->m_EndRange, bytes, length);
+	if (pResult) {
+		*result = reinterpret_cast<void*>(pResult);
+		return true;
+	}
+	return false;
+}
+#elif _LINUX
+CLinuxLibInfo::CLinuxLibInfo(void* pInBase) {
+	if (!dladdr(pInBase, &this->m_info)) {
+		this->m_bValid = false;
+		return;
+	}
+	
+	elf_version(EV_CURRENT);
+	
+	this->m_fd = open(m_info.dli_fname, O_RDONLY);
+	this->m_Elf = elf_begin(this->m_fd, ELF_C_READ, NULL);
+	this->m_bValid = true;
+}
+
+bool CLinuxLibInfo::LocatePattern(const char* bytes, size_t length, void** result) {
+	return false;
+}
+
+bool CLinuxLibInfo::LocateSymbol(const char* name, void** result) {
+	if (!this->m_bValid) {
+		return false;
+	}
+	
+	Elf_Scn *scn = NULL;
+	GElf_Shdr shdr;
+	while ((scn = elf_nextscn(this->m_Elf, scn)) != NULL) {
+		gelf_getshdr(scn, &shdr);
+		if (shdr.sh_type == SHT_SYMTAB) {
+			break;
+		}
+	}
+
+	Elf_Data *data = elf_getdata(scn, NULL);
+	size_t count = shdr.sh_size / shdr.sh_entsize;
+
+	// iterate symbols
+	for (size_t i = 0; i < count; ++i) {
+		GElf_Sym sym;
+		gelf_getsym(data, i, &sym);
+		
+		const char *symname = elf_strptr(this->m_Elf, shdr.sh_link, sym.st_name);
+		if (!strcmp(symname, name)) {
+			*result = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(m_info.dli_fbase) + sym.st_value);
+			return true;
+		}
+	}
+	return false;
+}
+
+CLinuxLibInfo::~CLinuxLibInfo() {
+	elf_end(this->m_Elf);
+	close(this->m_fd);
+}
+#endif

+ 52 - 0
memscan.h

@@ -0,0 +1,52 @@
+#ifndef _INCLUDE_MEMSCAN_UTIL_H_
+#define _INCLUDE_MEMSCAN_UTIL_H_
+
+#include <stdio.h>
+#include <cstdint>
+
+#if WINDOWS
+#include <windows.h>
+#elif _LINUX
+#include "mmsplugin.h"
+#include <fcntl.h>
+#include <gelf.h>
+#endif
+
+class ILibInfo {
+public:
+	virtual ~ILibInfo() {};
+	virtual bool LocatePattern(const char* bytes, size_t length, void** result) = 0;
+	virtual bool LocateSymbol(const char* name, void** result) = 0;
+	
+protected:
+	bool m_bValid;
+};
+
+#if WINDOWS
+class CWinLibInfo : public ILibInfo {
+public:
+	CWinLibInfo(void* pInBase);
+	
+	virtual bool LocatePattern(const char* bytes, size_t length, void** result);
+	virtual bool LocateSymbol(const char* name, void** result);
+	
+private:
+	uintptr_t m_StartRange, m_EndRange;
+};
+#elif _LINUX
+class CLinuxLibInfo : public ILibInfo {
+public:
+	CLinuxLibInfo(void* pInBase);
+	~CLinuxLibInfo();
+	
+	virtual bool LocatePattern(const char* bytes, size_t length, void** result);
+	virtual bool LocateSymbol(const char* name, void** result);
+	
+private:
+	int m_fd;
+	Elf *m_Elf;
+	Dl_info m_info;
+};
+#endif
+
+#endif

+ 9 - 76
mmsplugin.cpp

@@ -14,12 +14,7 @@
 #include <KeyValues.h>
 #include <filesystem.h>
 
-#if WINDOWS
-#include <windows.h>
-#elif _LINUX
-#include <fcntl.h>
-#include <gelf.h>
-#endif
+#include "memscan.h"
 
 SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
 SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
@@ -79,26 +74,6 @@ typedef bool (__cdecl *CEconItemAttributeInitFromKV_fn)(CEconItemAttributeDefini
 #endif
 CEconItemAttributeInitFromKV_fn fnItemAttributeInitFromKV = nullptr;
 
-uintptr_t FindPattern(uintptr_t start, uintptr_t end, const char* pattern, size_t length) {
-	uintptr_t ptr = start;
-	bool f;
-	while (ptr < end - length) {
-		f = true;
-		const char* cur = reinterpret_cast<char*>(ptr);
-		for (register size_t i = 0; i < length; i++) {
-			if (pattern[i] != '\x2A' && pattern[i] != cur[i]) {
-				f = false;
-				break;
-			}
-		}
-		if (f) {
-			return ptr;
-		}
-		ptr++;
-	}
-	return 0;
-}
-
 bool DynSchema::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
 {
 	PLUGIN_SAVEVARS();
@@ -110,59 +85,17 @@ bool DynSchema::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, boo
 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, server, this, &DynSchema::Hook_LevelInitPost, true);
 
 	// get the base address of the server
-	// TODO windows support
 #if WINDOWS
-	MEMORY_BASIC_INFORMATION info;
-	if (!VirtualQuery(server, &info, sizeof(MEMORY_BASIC_INFORMATION))) {
-		return false;
-	}
-	uintptr_t base = reinterpret_cast<uintptr_t>(info.AllocationBase);
-	IMAGE_DOS_HEADER *dos = reinterpret_cast<IMAGE_DOS_HEADER *>(base);
-	IMAGE_NT_HEADERS *pe = reinterpret_cast<IMAGE_NT_HEADERS *>(base + dos->e_lfanew);
-	IMAGE_OPTIONAL_HEADER *opt = &pe->OptionalHeader;
-	size_t size = opt->SizeOfImage;
+	CWinLibInfo lib(server);
 	
-	fnGetEconItemSchema = (GetEconItemSchemaFn_t*) (FindPattern(base, base + size, "\xE8\x2A\x2A\x2A\x2A\x83\xC0\x04\xC3", 9));
-	fnItemAttributeInitFromKV = (CEconItemAttributeInitFromKV_fn) (FindPattern(base, base + size, "\x55\x8B\xEC\x53\x8B\x5D\x08\x56\x8B\xF1\x8B\xCB\x57\xE8\x2A\x2A\x2A\x2A", 18));
+	lib.LocatePattern("\xE8\x2A\x2A\x2A\x2A\x83\xC0\x04\xC3", 9, (void**) &fnGetEconItemSchema);
+	lib.LocatePattern("\x55\x8B\xEC\x53\x8B\x5D\x08\x56\x8B\xF1\x8B\xCB\x57\xE8\x2A\x2A\x2A\x2A", 18, (void**) &fnItemAttributeInitFromKV);
 #elif _LINUX
-	Dl_info info;
-	if (!dladdr(server, &info)) {
-		return false;
-	}
+	CLinuxLibInfo lib(server);
 	
-	// locate symbols within our server binary
-	elf_version(EV_CURRENT);
-
-	int fd = open(info.dli_fname, O_RDONLY);
-	Elf *elf = elf_begin(fd, ELF_C_READ, NULL);
-
-	Elf_Scn *scn = NULL;
-	GElf_Shdr shdr;
-	while ((scn = elf_nextscn(elf, scn)) != NULL) {
-		gelf_getshdr(scn, &shdr);
-		if (shdr.sh_type == SHT_SYMTAB) {
-			break;
-		}
-	}
-
-	Elf_Data *data = elf_getdata(scn, NULL);
-	size_t count = shdr.sh_size / shdr.sh_entsize;
-
-	/* print the symbol names */
-	for (size_t i = 0; i < count; ++i) {
-		GElf_Sym sym;
-		gelf_getsym(data, i, &sym);
-		
-		const char *symname = elf_strptr(elf, shdr.sh_link, sym.st_name);
-		if (!strcmp(symname,
-				"_ZN28CEconItemAttributeDefinition11BInitFromKVEP9KeyValuesP10CUtlVectorI10CUtlString10CUtlMemoryIS3_iEE")) {
-			fnItemAttributeInitFromKV = (CEconItemAttributeInitFromKV_fn) (reinterpret_cast<uintptr_t>(info.dli_fbase) + sym.st_value);
-		} else if (!strcmp(symname, "_Z15GEconItemSchemav")) {
-			fnGetEconItemSchema = reinterpret_cast<GetEconItemSchemaFn_t*>(reinterpret_cast<uintptr_t>(info.dli_fbase) + sym.st_value);
-		}
-	}
-	elf_end(elf);
-	close(fd);
+	lib.LocateSymbol("_ZN28CEconItemAttributeDefinition11BInitFromKVEP9KeyValuesP10CUtlVectorI10CUtlString10CUtlMemoryIS3_iEE",
+			(void**) &fnItemAttributeInitFromKV);
+	lib.LocateSymbol("_Z15GEconItemSchemav", (void**) &fnGetEconItemSchema);
 #endif
 	
 	if (!fnItemAttributeInitFromKV || !fnGetEconItemSchema) {
@@ -252,7 +185,7 @@ const char *DynSchema::GetLicense() {
 }
 
 const char *DynSchema::GetVersion() {
-	return "1.0.1";
+	return "1.0.2";
 }
 
 const char *DynSchema::GetDate() {