-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
305 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import argparse | ||
import csv | ||
import sys | ||
|
||
parser = argparse.ArgumentParser( | ||
prog="generate_detours", description="Generate stubs based on the stubs.csv file." | ||
) | ||
parser.add_argument( | ||
"-o", "--output", action="store", help="File to store the generated stubs in" | ||
) | ||
parser.add_argument( | ||
"-i", "--input-def", action="store", help="Def file to find mangled symbols in" | ||
) | ||
args = parser.parse_args() | ||
|
||
|
||
def get_path_of_mangled_symbol(symbol): | ||
if symbol[0] == "?": | ||
cpp_symbol = symbol[1:] | ||
path = cpp_symbol.split("@") | ||
last = next((idx for idx, x in enumerate(path) if x == ""), None) | ||
path = path[0:last] | ||
|
||
first_elem = path[0] | ||
if first_elem[0] == "?": | ||
if first_elem[1] == "0": | ||
cls = first_elem[2:] | ||
path[0] = cls + "::" + cls | ||
elif first_elem[1] == "1": | ||
cls = first_elem[2:] | ||
path[0] = cls + "::~" + cls | ||
elif first_elem[1:3] == "_H": | ||
return None | ||
else: | ||
print("WARNING: Unknown special symbol " + symbol) | ||
|
||
return "::".join(reversed(path)) | ||
elif symbol[0] == "_": | ||
return symbol[1:].split("@", 1)[0] | ||
else: | ||
raise Exception("Unknown symbol kind " + symbol) | ||
|
||
|
||
output = sys.stdout | ||
if args.output: | ||
output = open(args.output, "w") | ||
|
||
fun_to_mangled_map = {} | ||
with open(args.input_def) as f: | ||
for line in f: | ||
if len(line.strip()) == 0: | ||
continue | ||
|
||
if line.strip() == "EXPORTS": | ||
continue | ||
|
||
mangled_symbol = line.rsplit(" ", 1)[0].strip() | ||
fun_path = get_path_of_mangled_symbol(mangled_symbol) | ||
if fun_path is None: | ||
continue | ||
print(fun_path) | ||
if fun_path in fun_to_mangled_map: | ||
raise Exception("Overload detected, two functions patch " + fun_path) | ||
fun_to_mangled_map[fun_path] = mangled_symbol | ||
|
||
fun_to_mangled_map["operator_new"] = "??2@YAPAXI@Z" | ||
fun_to_mangled_map["_malloc"] = "malloc" | ||
fun_to_mangled_map["_calloc"] = "calloc" | ||
fun_to_mangled_map["_realloc"] = "realloc" | ||
fun_to_mangled_map["_free"] = "free" | ||
fun_to_mangled_map["__msize"] = "_msize" | ||
|
||
with open("config/mapping.csv") as f: | ||
mapping_csv = csv.reader(f) | ||
mapping_obj = {} | ||
for func in mapping_csv: | ||
fun_name = func[0] | ||
fun_addr = int(func[1], 16) | ||
mapping_obj[fun_name] = fun_addr | ||
|
||
f = open("config/implemented.csv") | ||
implemented_csv = csv.reader(f) | ||
|
||
print("Detouring detours[] = {", file=output) | ||
first = True | ||
for implemented in implemented_csv: | ||
if not first: | ||
print(",", file=output) | ||
|
||
fun_name = implemented[0] | ||
fun_mangled_name = fun_to_mangled_map[fun_name] | ||
fun_addr = mapping_obj[fun_name] | ||
print( | ||
" { " + hex(fun_addr) + ', "' + fun_mangled_name + '", FALSE }', | ||
end="", | ||
file=output, | ||
) | ||
first = False | ||
|
||
f = open("config/stubbed.csv") | ||
stubbed_csv = csv.reader(f) | ||
first = True | ||
for implemented in stubbed_csv: | ||
print(",", file=output) | ||
|
||
fun_name = implemented[0] | ||
fun_mangled_name = fun_to_mangled_map[fun_name] | ||
fun_addr = mapping_obj[fun_name] | ||
print( | ||
" { " + hex(fun_addr) + ', "' + fun_mangled_name + '", TRUE }', | ||
end="", | ||
file=output, | ||
) | ||
|
||
# Add some necessary detouring to share MSVCRT heap with the main executable | ||
for fun_name in ["_malloc", "_calloc", "_realloc", "operator_new", "_free", "__msize"]: | ||
print(",", file=output) | ||
|
||
fun_mangled_name = fun_to_mangled_map[fun_name] | ||
fun_addr = mapping_obj[fun_name] | ||
print( | ||
" { " + hex(fun_addr) + ', "' + fun_mangled_name + '", FALSE }', | ||
end="", | ||
file=output, | ||
) | ||
|
||
print("\n};", file=output) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// DLLBUILD support | ||
// | ||
// The DLLBUILD is a special build of th06 meant to be injected into th06 1.02h, | ||
// replacing the official functions with our own reimplementation. The primary | ||
// purpose here is to validate that our reimplementations work even when they | ||
// are not bit-accurate, but can also serve as a mechanism to enable modding | ||
// before the reimplementation work is complete. | ||
// | ||
// The way it works is rather simple: We use the Detours library to hijack all | ||
// the functions we have reimplemented from the original binary. Similarly, for | ||
// the functions we want to call but have not yet reimplemented, we generate | ||
// stub functions that simply forward the argument. Finally, to ensure the data | ||
// is shared, we integrate the DIFFBUILD mechanism to store data at fixed | ||
// locations in memory. | ||
// | ||
// The stubs are generated automatically by a script in | ||
// scripts/generate_stubs.py, based on the information found in | ||
// config/stubbed.csv. This generates a stubbed.cpp file that will be | ||
// automatically compiled and linked. | ||
// | ||
// Meanwhile, the list of functions to detour is auto-generated by another | ||
// script, scripts/generate_detours.py, based on the information found in | ||
// config/implemented.csv. | ||
|
||
#include "AnmManager.hpp" | ||
#include "AsciiManager.hpp" | ||
#include "Chain.hpp" | ||
#include "detours.h" | ||
#include <fstream> | ||
#include <string.h> | ||
|
||
struct Detouring | ||
{ | ||
size_t addressInOriginalBinary; | ||
char *nameInDllReplacement; | ||
BOOL stub; | ||
|
||
void *addrToReplace; | ||
void *replaceWith; | ||
}; | ||
|
||
#include "detouring.cpp" | ||
|
||
// For now, always use D3D_WRAPPER. In the future, we may want to swap it out | ||
// with another "host" dll. | ||
#define D3D_WRAPPER 1 | ||
#ifdef D3D_WRAPPER | ||
typedef IDirect3D8 *(WINAPI *Direct3DCreate8Proc)(UINT); | ||
extern "C" IDirect3D8 *__stdcall Direct3DCreate8(UINT sdk_version) | ||
{ | ||
char path[MAX_PATH + 1]; | ||
GetSystemDirectoryA(path, MAX_PATH); | ||
strncat(path, "\\d3d8.dll", MAX_PATH - strlen(path)); | ||
HMODULE d3d8dll = LoadLibraryA(path); | ||
if (d3d8dll == NULL) | ||
{ | ||
return NULL; | ||
} | ||
Direct3DCreate8Proc realproc = (Direct3DCreate8Proc)GetProcAddress(d3d8dll, "Direct3DCreate8"); | ||
if (!realproc) | ||
{ | ||
return NULL; | ||
} | ||
|
||
return realproc(sdk_version); | ||
} | ||
#endif | ||
|
||
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) | ||
{ | ||
if (DetourIsHelperProcess()) | ||
{ | ||
return TRUE; | ||
} | ||
|
||
if (dwReason == DLL_PROCESS_ATTACH) | ||
{ | ||
DetourRestoreAfterWith(); | ||
|
||
if (DetourTransactionBegin() != 0) | ||
{ | ||
// TODO: Show an error. | ||
return TRUE; | ||
} | ||
if (DetourUpdateThread(GetCurrentThread()) != 0) | ||
{ | ||
// TODO: Show an error | ||
DetourTransactionAbort(); | ||
return TRUE; | ||
} | ||
for (size_t i = 0; i < sizeof(detours) / sizeof(detours[0]); i++) | ||
{ | ||
if (!detours[i].stub) | ||
{ | ||
detours[i].addrToReplace = (void *)detours[i].addressInOriginalBinary; | ||
detours[i].replaceWith = (void *)GetProcAddress(hinst, detours[i].nameInDllReplacement); | ||
} | ||
else | ||
{ | ||
detours[i].addrToReplace = (void *)GetProcAddress(hinst, detours[i].nameInDllReplacement); | ||
detours[i].replaceWith = (void *)detours[i].addressInOriginalBinary; | ||
} | ||
if (DetourAttach(&detours[i].addrToReplace, detours[i].replaceWith) != 0) | ||
{ | ||
// TODO: Show an error | ||
DetourTransactionAbort(); | ||
return TRUE; | ||
} | ||
} | ||
if (DetourTransactionCommit() != 0) | ||
{ | ||
// TODO: Show an error | ||
return TRUE; | ||
} | ||
} | ||
else if (dwReason == DLL_PROCESS_DETACH) | ||
{ | ||
DetourTransactionBegin(); | ||
DetourUpdateThread(GetCurrentThread()); | ||
for (size_t i = 0; i < sizeof(detours) / sizeof(detours[0]); i++) | ||
{ | ||
DetourDetach(&detours[i].addrToReplace, detours[i].replaceWith); | ||
} | ||
DetourTransactionCommit(); | ||
} | ||
return TRUE; | ||
} |