267 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| #include <dlfcn.h>
 | |
| #include <math.h>
 | |
| #include "gdc.h"
 | |
| #include "GameConfigs.h"
 | |
| #include "MemoryUtils.h"
 | |
| 
 | |
| MemoryUtils mu;
 | |
| 
 | |
| char *game = NULL;
 | |
| char *engine = NULL;
 | |
| char *binary = NULL;
 | |
| 
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
| 	char *gamedata = NULL;
 | |
| 	bool debug = false;
 | |
| 
 | |
| 	opterr = 0;
 | |
| 	int opt;
 | |
| 	while ((opt = getopt(argc, argv, "b:de:f:g:")) != -1)
 | |
| 		switch (opt)
 | |
| 		{
 | |
| 			case 'd':
 | |
| 				debug = true;
 | |
| 				break;
 | |
| 			case 'g':
 | |
| 				game = optarg;
 | |
| 				break;
 | |
| 
 | |
| 			case 'e':
 | |
| 				engine = optarg;
 | |
| 				break;
 | |
| 
 | |
| 			case 'f':
 | |
| 				gamedata = optarg;
 | |
| 				break;
 | |
| 
 | |
| 			case 'b':
 | |
| 				binary = optarg;
 | |
| 				break;
 | |
| 
 | |
| 			case '?':
 | |
| 				printf("Usage: ./gdc -g <game> -e <engine> -f <gamedata file> -b <binary>\n");
 | |
| 				return 0;
 | |
| 
 | |
| 			default:
 | |
| 				printf("WHAT\n");
 | |
| 				return 0;
 | |
| 		}
 | |
| 
 | |
| 	if (!game || !engine || !gamedata || !binary)
 | |
| 	{
 | |
| 		printf("Usage: ./gdc -g <game> -e <engine> -f <gamedata file> -b <binary>\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	printf("Game: %s\nEngine: %s\nGamedata: %s\nBinary: %s\n", game, engine, gamedata, binary);
 | |
| 
 | |
| 	void *handle = dlopen(binary, RTLD_LAZY);
 | |
| 	if (!handle)
 | |
| 	{
 | |
| 		printf("Couldn't open %s (%s)\n", binary, dlerror());
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	CGameConfig gc;
 | |
| 	char err[512];
 | |
| 	if (!gc.EnterFile(gamedata, err, sizeof(err)))
 | |
| 	{
 | |
| 		printf("%s: %s\n", gamedata, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	CGameConfig symbols;
 | |
| 	if (!symbols.EnterFile("symbols.txt", err, sizeof(err)))
 | |
| 	{
 | |
| 		printf("symbols.txt: %s\n", err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (debug)
 | |
| 		for (map<const char*, const char*, cmp_str>::iterator it = symbols.m_Keys.begin(); it != symbols.m_Keys.end(); it++)
 | |
| 			printf("%s - %s\n", it->first, it->second);
 | |
| 
 | |
| 	const char *vtsym = symbols.GetKeyValue("vtsym");
 | |
| 	if (!vtsym)
 | |
| 	{
 | |
| 		printf("Couldn't find vtsym\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| #if 0
 | |
| 	void *lolwhat = (void*)1;
 | |
| 	void *handle = lolwhat;
 | |
| 	handle = dlopen(binary, RTLD_LAZY);
 | |
| 	if (!handle)
 | |
| 	{
 | |
| 		printf("Couldn't open %s\n", binary);
 | |
| 		return 0;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	void **vt = (void**) mu.ResolveSymbol(handle, vtsym);
 | |
| 	if (!vt)
 | |
| 	{
 | |
| 		printf("Couldn't find vtable %s\n", vtsym);
 | |
| 		dlclose(handle);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
 | |
| 	{
 | |
| 		if (debug) printf("DEBUG %s - l: %d w: %d\n", it->name, it->lin, it->win);
 | |
| //		else
 | |
| 		{
 | |
| 			const char *symbol = symbols.GetKeyValue(it->name);
 | |
| 			if (symbol)
 | |
| 			{
 | |
| 				int offset = findVFunc(handle, vt, symbol);
 | |
| 
 | |
| 				if (offset == it->lin) printf("%s - good\n", it->name);
 | |
| 				else printf("%s - l: %d w: %d\n", it->name, offset, offset + it->lin - it->win);
 | |
| 			}
 | |
| 			else printf("%s - no Linux symbol, skipping\n", it->name);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	printf("\nWindows offsets are wild guesses!\n\n");
 | |
| 
 | |
| 	for (list<Sig>::iterator it = gc.m_Sigs.begin(); it != gc.m_Sigs.end(); it++)
 | |
| 	{
 | |
| 		if (debug) printf("DEBUG %s - %s - l: %s\n", it->name, it->lib == Server ? "server" : "engine", it->lin);
 | |
| //		else
 | |
| 		{
 | |
| 			if (it->lib != Server)
 | |
| 			{
 | |
| 				printf("%s - isn't server, skipping\n", it->name);
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			const char *symbol = it->lin;
 | |
| 
 | |
| 			if (!symbol) 
 | |
| 			{
 | |
| 				printf("%s - no Linux symbol, skipping\n", it->name);
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if (symbol[0] != '@')
 | |
| 			{
 | |
| 				printf("%s - didn't start with '@', skipping\n", it->name);
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			void *addr = mu.ResolveSymbol(handle, symbol + 1);
 | |
| 
 | |
| 			if (addr) printf("%s - good\n", it->name);
 | |
| 			else printf("%s - %s not found\n", it->name, it->lin);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* 
 | |
|    takes a mangled member function symbol and returns the position where the function name and parameters start
 | |
|    01234567890123456789012345678
 | |
|    _ZN9CTFPlayer12ForceRespawnEv
 | |
|                 ^13            ^28
 | |
| */
 | |
| void findFuncPos(const char *sym, int &func, int ¶ms)
 | |
| {
 | |
| 	int i = 0;
 | |
| 	while ((sym[i] < '0') || (sym[i] > '9')) i++;
 | |
| 	int classLen = atoi(sym + i);
 | |
| 	func = i + (int)ceil(log10(classLen)) + classLen;
 | |
| 	int funcLen = atoi(sym + func);
 | |
| 	params = func + (int)ceil(log10(funcLen)) + funcLen;
 | |
| }
 | |
| 
 | |
| int findVFunc(void *handle, void **vt, const char *symbol)
 | |
| {
 | |
| 	int offset = 1;
 | |
| 	//int overloads = 0;
 | |
| 	int funcPos, paramPos;
 | |
| 	findFuncPos(symbol, funcPos, paramPos);
 | |
| 
 | |
| 	for (int i = 0; i < 1000; i++)
 | |
| 	{
 | |
| 		void *pFunc = vt[i];
 | |
| 		const char *s;
 | |
| 
 | |
| //		Dl_info info;
 | |
| //		if (!mu.ResolveAddr(pFunc, &info)) continue;
 | |
| 		if (!(s = mu.ResolveAddr(handle, pFunc))) continue;
 | |
| 
 | |
| //		if ((i > 1) && (strncmp(info.dli_sname, "_ZTI", 4) == 0)) break;
 | |
| 		if ((i > 1) && (strncmp(s, "_ZTI", 4) == 0)) break;
 | |
| 
 | |
| 
 | |
| 		int tempFuncPos, tempParamPos;
 | |
| //		findFuncPos(info.dli_sname, tempFuncPos, tempParamPos);
 | |
| 		findFuncPos(s, tempFuncPos, tempParamPos);
 | |
| 
 | |
| #if 0
 | |
| 		if (strncmp(info.dli_sname[tempFuncPos], symbol[funcPos], paramPos - funcPos) == 0)
 | |
| 		{
 | |
| 			overloads++;
 | |
| 			if (firstOverload == -1) firstOverload = i - 1;
 | |
| 			if (strncmp(info.dli_sname[tempParamPos], symbol[paramPos], strlen(symbol) - paramPos) == 0)
 | |
| 			{
 | |
| 				offset = i;
 | |
| 				matchingOverload = overloads;
 | |
| 			}
 | |
| 		}
 | |
| #else
 | |
| //		if (strcmp(info.dli_sname + tempFuncPos, symbol + funcPos) == 0)
 | |
| 		if (strcmp(s + tempFuncPos, symbol + funcPos) == 0)
 | |
| 		{
 | |
| 			offset = i;
 | |
| 			break;
 | |
| 		}
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| 	return offset - 2;
 | |
| }
 | |
| 
 | |
| unsigned int strncopy(char *dest, const char *src, size_t count)
 | |
| {
 | |
| 	if (!count)
 | |
| 	{
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	char *start = dest;
 | |
| 	while ((*src) && (--count))
 | |
| 	{
 | |
| 		*dest++ = *src++;
 | |
| 	}
 | |
| 	*dest = '\0';
 | |
| 
 | |
| 	return (dest - start);
 | |
| }
 | |
| 
 | |
| size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 	va_start(ap, fmt);
 | |
| 	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
 | |
| 	va_end(ap);
 | |
| 
 | |
| 	if (len >= maxlength)
 | |
| 	{
 | |
| 		buffer[maxlength - 1] = '\0';
 | |
| 		return (maxlength - 1);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		return len;
 | |
| 	}
 | |
| }
 | |
| 
 |