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;
|
||
|
}
|
||
|
}
|
||
|
|