You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
471 lines
11 KiB
471 lines
11 KiB
// |
|
// (http://planethalflife.com/botman/) |
|
// |
|
// namefunc.cpp |
|
// |
|
|
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "enginecallback.h" |
|
#include "cbase.h" |
|
|
|
#include "bot.h" |
|
|
|
|
|
#define MAX_SYMBOLS 1000 /* max exported symbols */ |
|
|
|
#define DOS_SIGNATURE 0x5A4D /* MZ */ |
|
#define NT_SIGNATURE 0x00004550 /* PE00 */ |
|
|
|
|
|
//extern GIVEFNPTRSTODLL other_GiveFnptrsToDll; |
|
extern HINSTANCE h_Library; |
|
|
|
// globals |
|
WORD *p_Ordinals = NULL; |
|
DWORD *p_Functions = NULL; |
|
DWORD *p_Names = NULL; |
|
char *p_FunctionNames[MAX_SYMBOLS]; |
|
int num_ordinals; |
|
unsigned long base_offset; |
|
|
|
|
|
typedef struct { // DOS .EXE header |
|
WORD e_magic; // Magic number |
|
WORD e_cblp; // Bytes on last page of file |
|
WORD e_cp; // Pages in file |
|
WORD e_crlc; // Relocations |
|
WORD e_cparhdr; // Size of header in paragraphs |
|
WORD e_minalloc; // Minimum extra paragraphs needed |
|
WORD e_maxalloc; // Maximum extra paragraphs needed |
|
WORD e_ss; // Initial (relative) SS value |
|
WORD e_sp; // Initial SP value |
|
WORD e_csum; // Checksum |
|
WORD e_ip; // Initial IP value |
|
WORD e_cs; // Initial (relative) CS value |
|
WORD e_lfarlc; // File address of relocation table |
|
WORD e_ovno; // Overlay number |
|
WORD e_res[4]; // Reserved words |
|
WORD e_oemid; // OEM identifier (for e_oeminfo) |
|
WORD e_oeminfo; // OEM information; e_oemid specific |
|
WORD e_res2[10]; // Reserved words |
|
LONG e_lfanew; // File address of new exe header |
|
} DOS_HEADER, *P_DOS_HEADER; |
|
|
|
typedef struct { |
|
WORD Machine; |
|
WORD NumberOfSections; |
|
DWORD TimeDateStamp; |
|
DWORD PointerToSymbolTable; |
|
DWORD NumberOfSymbols; |
|
WORD SizeOfOptionalHeader; |
|
WORD Characteristics; |
|
} PE_HEADER, *P_PE_HEADER; |
|
|
|
#define SIZEOF_SHORT_NAME 8 |
|
|
|
typedef struct { |
|
BYTE Name[SIZEOF_SHORT_NAME]; |
|
union { |
|
DWORD PhysicalAddress; |
|
DWORD VirtualSize; |
|
} Misc; |
|
DWORD VirtualAddress; |
|
DWORD SizeOfRawData; |
|
DWORD PointerToRawData; |
|
DWORD PointerToRelocations; |
|
DWORD PointerToLinenumbers; |
|
WORD NumberOfRelocations; |
|
WORD NumberOfLinenumbers; |
|
DWORD Characteristics; |
|
} SECTION_HEADER, *P_SECTION_HEADER; |
|
|
|
typedef struct { |
|
DWORD VirtualAddress; |
|
DWORD Size; |
|
} DATA_DIRECTORY, *P_DATA_DIRECTORY; |
|
|
|
#define NUMBEROF_DIRECTORY_ENTRIES 16 |
|
|
|
typedef struct { |
|
WORD Magic; |
|
BYTE MajorLinkerVersion; |
|
BYTE MinorLinkerVersion; |
|
DWORD SizeOfCode; |
|
DWORD SizeOfInitializedData; |
|
DWORD SizeOfUninitializedData; |
|
DWORD AddressOfEntryPoint; |
|
DWORD BaseOfCode; |
|
DWORD BaseOfData; |
|
DWORD ImageBase; |
|
DWORD SectionAlignment; |
|
DWORD FileAlignment; |
|
WORD MajorOperatingSystemVersion; |
|
WORD MinorOperatingSystemVersion; |
|
WORD MajorImageVersion; |
|
WORD MinorImageVersion; |
|
WORD MajorSubsystemVersion; |
|
WORD MinorSubsystemVersion; |
|
DWORD Win32VersionValue; |
|
DWORD SizeOfImage; |
|
DWORD SizeOfHeaders; |
|
DWORD CheckSum; |
|
WORD Subsystem; |
|
WORD DllCharacteristics; |
|
DWORD SizeOfStackReserve; |
|
DWORD SizeOfStackCommit; |
|
DWORD SizeOfHeapReserve; |
|
DWORD SizeOfHeapCommit; |
|
DWORD LoaderFlags; |
|
DWORD NumberOfRvaAndSizes; |
|
DATA_DIRECTORY DataDirectory[NUMBEROF_DIRECTORY_ENTRIES]; |
|
} OPTIONAL_HEADER, *P_OPTIONAL_HEADER; |
|
|
|
typedef struct { |
|
DWORD Characteristics; |
|
DWORD TimeDateStamp; |
|
WORD MajorVersion; |
|
WORD MinorVersion; |
|
DWORD Name; |
|
DWORD Base; |
|
DWORD NumberOfFunctions; |
|
DWORD NumberOfNames; |
|
DWORD AddressOfFunctions; // RVA from base of image |
|
DWORD AddressOfNames; // RVA from base of image |
|
DWORD AddressOfNameOrdinals; // RVA from base of image |
|
} EXPORT_DIRECTORY, *P_EXPORT_DIRECTORY; |
|
|
|
|
|
void FgetString(char *str, FILE *bfp) |
|
{ |
|
char ch; |
|
|
|
while ((ch = fgetc(bfp)) != EOF) |
|
{ |
|
*str++ = ch; |
|
if (ch == 0) |
|
break; |
|
} |
|
} |
|
|
|
|
|
void FreeNameFuncGlobals(void) |
|
{ |
|
if (p_Ordinals) |
|
free(p_Ordinals); |
|
if (p_Functions) |
|
free(p_Functions); |
|
if (p_Names) |
|
free(p_Names); |
|
|
|
for (int i=0; i < num_ordinals; i++) |
|
{ |
|
if (p_FunctionNames[i]) |
|
free(p_FunctionNames[i]); |
|
} |
|
} |
|
|
|
void getMSVCName(char *out_name, char *in_name) |
|
{ |
|
char *pos; |
|
|
|
if (in_name[0] == '?') // is this a MSVC C++ mangled name? |
|
{ |
|
if ((pos = strstr(in_name, "@@")) != NULL) |
|
{ |
|
int len = pos - in_name; |
|
|
|
strcpy(out_name, &in_name[1]); // strip off the leading '?' |
|
out_name[len-1] = 0; // terminate string at the "@@" |
|
|
|
return; |
|
} |
|
} |
|
|
|
strcpy(out_name, in_name); |
|
} |
|
|
|
void LoadSymbols(char *filename) |
|
{ |
|
FILE *bfp; |
|
DOS_HEADER dos_header; |
|
LONG nt_signature; |
|
PE_HEADER pe_header; |
|
SECTION_HEADER section_header; |
|
BOOL edata_found; |
|
OPTIONAL_HEADER optional_header; |
|
LONG edata_offset; |
|
LONG edata_delta; |
|
EXPORT_DIRECTORY export_directory; |
|
LONG name_offset; |
|
LONG ordinal_offset; |
|
LONG function_offset; |
|
char function_name[256]; |
|
int i, index; |
|
BOOL error; |
|
char msg[80]; |
|
|
|
for (i=0; i < num_ordinals; i++) |
|
p_FunctionNames[i] = NULL; |
|
|
|
if ((bfp=fopen(filename, "rb")) == NULL) |
|
{ |
|
sprintf(msg, "DLL file %s not found!", filename); |
|
ALERT(at_error, msg); |
|
return; |
|
} |
|
|
|
if (fread(&dos_header, sizeof(dos_header), 1, bfp) != 1) |
|
{ |
|
sprintf(msg, "%s is NOT a valid DLL file!", filename); |
|
ALERT(at_error, msg); |
|
return; |
|
} |
|
|
|
if (dos_header.e_magic != DOS_SIGNATURE) |
|
{ |
|
ALERT(at_error, "file does not have a valid DLL signature!"); |
|
return; |
|
} |
|
|
|
if (fseek(bfp, dos_header.e_lfanew, SEEK_SET) == -1) |
|
{ |
|
ALERT(at_error, "error seeking to new exe header!"); |
|
return; |
|
} |
|
|
|
if (fread(&nt_signature, sizeof(nt_signature), 1, bfp) != 1) |
|
{ |
|
ALERT(at_error, "file does not have a valid NT signature!"); |
|
return; |
|
} |
|
|
|
if (nt_signature != NT_SIGNATURE) |
|
{ |
|
ALERT(at_error, "file does not have a valid NT signature!"); |
|
return; |
|
} |
|
|
|
if (fread(&pe_header, sizeof(pe_header), 1, bfp) != 1) |
|
{ |
|
ALERT(at_error, "file does not have a valid PE header!"); |
|
return; |
|
} |
|
|
|
if (pe_header.SizeOfOptionalHeader == 0) |
|
{ |
|
ALERT(at_error, "file does not have an optional header!"); |
|
return; |
|
} |
|
|
|
if (fread(&optional_header, sizeof(optional_header), 1, bfp) != 1) |
|
{ |
|
ALERT(at_error, "file does not have a valid optional header!"); |
|
return; |
|
} |
|
|
|
edata_found = FALSE; |
|
|
|
for (i=0; i < pe_header.NumberOfSections; i++) |
|
{ |
|
if (fread(§ion_header, sizeof(section_header), 1, bfp) != 1) |
|
{ |
|
ALERT(at_error, "error reading section header!"); |
|
return; |
|
} |
|
|
|
if (strcmp((char *)section_header.Name, ".edata") == 0) |
|
{ |
|
edata_found = TRUE; |
|
break; |
|
} |
|
} |
|
|
|
if (edata_found) |
|
{ |
|
edata_offset = section_header.PointerToRawData; |
|
edata_delta = section_header.VirtualAddress - section_header.PointerToRawData; |
|
} |
|
else |
|
{ |
|
edata_offset = optional_header.DataDirectory[0].VirtualAddress; |
|
edata_delta = 0L; |
|
} |
|
|
|
|
|
if (fseek(bfp, edata_offset, SEEK_SET) == -1) |
|
{ |
|
ALERT(at_error, "file does not have a valid exports section!"); |
|
return; |
|
} |
|
|
|
if (fread(&export_directory, sizeof(export_directory), 1, bfp) != 1) |
|
{ |
|
ALERT(at_error, "file does not have a valid optional header!"); |
|
return; |
|
} |
|
|
|
num_ordinals = export_directory.NumberOfNames; // also number of ordinals |
|
|
|
if (num_ordinals > MAX_SYMBOLS) |
|
{ |
|
ALERT(at_error, "too many symbols to process. make MAX_SYMBOLS bigger."); |
|
return; |
|
} |
|
|
|
|
|
ordinal_offset = export_directory.AddressOfNameOrdinals - edata_delta; |
|
|
|
if (fseek(bfp, ordinal_offset, SEEK_SET) == -1) |
|
{ |
|
ALERT(at_error, "file does not have a valid ordinals section!"); |
|
return; |
|
} |
|
|
|
if ((p_Ordinals = (WORD *)malloc(num_ordinals * sizeof(WORD))) == NULL) |
|
{ |
|
ALERT(at_error, "error allocating memory for ordinals section!"); |
|
return; |
|
} |
|
|
|
if (fread(p_Ordinals, num_ordinals * sizeof(WORD), 1, bfp) != 1) |
|
{ |
|
FreeNameFuncGlobals(); |
|
|
|
ALERT(at_error, "error reading ordinals table!"); |
|
return; |
|
} |
|
|
|
|
|
function_offset = export_directory.AddressOfFunctions - edata_delta; |
|
|
|
if (fseek(bfp, function_offset, SEEK_SET) == -1) |
|
{ |
|
ALERT(at_error, "file does not have a valid export address section!"); |
|
return; |
|
} |
|
|
|
if ((p_Functions = (DWORD *)malloc(num_ordinals * sizeof(DWORD))) == NULL) |
|
{ |
|
ALERT(at_error, "error allocating memory for export address section!"); |
|
return; |
|
} |
|
|
|
if (fread(p_Functions, num_ordinals * sizeof(DWORD), 1, bfp) != 1) |
|
{ |
|
FreeNameFuncGlobals(); |
|
|
|
ALERT(at_error, "error reading export address section!"); |
|
return; |
|
} |
|
|
|
|
|
name_offset = export_directory.AddressOfNames - edata_delta; |
|
|
|
if (fseek(bfp, name_offset, SEEK_SET) == -1) |
|
{ |
|
FreeNameFuncGlobals(); |
|
|
|
ALERT(at_error, "file does not have a valid names section!"); |
|
return; |
|
} |
|
|
|
if ((p_Names = (DWORD *)malloc(num_ordinals * sizeof(DWORD))) == NULL) |
|
{ |
|
FreeNameFuncGlobals(); |
|
|
|
ALERT(at_error, "error allocating memory for names section!"); |
|
return; |
|
} |
|
|
|
if (fread(p_Names, num_ordinals * sizeof(DWORD), 1, bfp) != 1) |
|
{ |
|
FreeNameFuncGlobals(); |
|
|
|
ALERT(at_error, "error reading names table!"); |
|
return; |
|
} |
|
|
|
error = FALSE; |
|
|
|
for (i=0; (i < num_ordinals) && (error==FALSE); i++) |
|
{ |
|
name_offset = p_Names[i] - edata_delta; |
|
|
|
if (name_offset != 0) |
|
{ |
|
if (fseek(bfp, name_offset, SEEK_SET) == -1) |
|
error = TRUE; |
|
else |
|
{ |
|
FgetString(function_name, bfp); |
|
|
|
if ((p_FunctionNames[i] = (char *)malloc(strlen(function_name)+1)) == NULL) |
|
error = TRUE; |
|
else |
|
getMSVCName(p_FunctionNames[i], function_name); |
|
} |
|
} |
|
} |
|
|
|
if (error) |
|
{ |
|
FreeNameFuncGlobals(); |
|
|
|
ALERT(at_error, "error in loading names section!"); |
|
return; |
|
} |
|
|
|
fclose(bfp); |
|
|
|
void *game_GiveFnptrsToDll; |
|
|
|
for (i=0; i < num_ordinals; i++) |
|
{ |
|
if (strcmp("GiveFnptrsToDll", p_FunctionNames[i]) == 0) |
|
{ |
|
index = p_Ordinals[i]; |
|
|
|
game_GiveFnptrsToDll = (void *)GetProcAddress(h_Library, "GiveFnptrsToDll"); |
|
base_offset = (unsigned long)(game_GiveFnptrsToDll) - p_Functions[index]; |
|
|
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
unsigned long FUNCTION_FROM_NAME(const char *pName) |
|
{ |
|
int i, index; |
|
|
|
for (i=0; i < num_ordinals; i++) |
|
{ |
|
if (strcmp(pName, p_FunctionNames[i]) == 0) |
|
{ |
|
index = p_Ordinals[i]; |
|
|
|
return p_Functions[index] + base_offset; |
|
} |
|
} |
|
|
|
return 0L; // couldn't find the function name to return address |
|
} |
|
|
|
|
|
const char *NAME_FOR_FUNCTION(unsigned long function) |
|
{ |
|
int i, index; |
|
|
|
for (i=0; i < num_ordinals; i++) |
|
{ |
|
index = p_Ordinals[i]; |
|
|
|
if ((function - base_offset) == p_Functions[index]) |
|
{ |
|
return p_FunctionNames[i]; |
|
} |
|
} |
|
|
|
return NULL; // couldn't find the function address to return name |
|
}
|
|
|