diff --git a/GUI/host/textthread.cpp b/GUI/host/textthread.cpp index 79a8a0b..f5c7db6 100644 --- a/GUI/host/textthread.cpp +++ b/GUI/host/textthread.cpp @@ -58,7 +58,6 @@ void TextThread::Push(BYTE* data, int length) if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch) { return repeatingChars.find(ch) != repeatingChars.end(); })) buffer.clear(); if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received { - if (hp.type & BLOCK_FLOOD) Host::RemoveHook(tp.processId, tp.addr); repeatingChars = std::unordered_set(buffer.begin(), buffer.end()); AddSentence(std::move(buffer)); buffer.clear(); @@ -88,7 +87,6 @@ void TextThread::Flush() sentence.erase(std::remove(sentence.begin(), sentence.end(), L'\0')); if (Output(*this, sentence)) storage->append(sentence); } - if (hp.type & BLOCK_FLOOD && totalSize > PIPE_BUFFER_SIZE) Host::RemoveHook(tp.processId, tp.addr); std::scoped_lock lock(bufferMutex); if (buffer.empty()) return; diff --git a/include/const.h b/include/const.h index 995922f..d68a842 100644 --- a/include/const.h +++ b/include/const.h @@ -4,7 +4,7 @@ // 8/23/2013 jichi // Branch: ITH/common.h, rev 128 -enum { STRING = 12, MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 10000, SHIFT_JIS = 932, MAX_MODULE_SIZE = 120, PATTERN_SIZE = 30, HOOK_NAME_SIZE = 30, FIXED_SPLIT_VALUE = 0x10001 }; +enum { STRING = 12, MESSAGE_SIZE = 500, PIPE_BUFFER_SIZE = 10000, SHIFT_JIS = 932, MAX_MODULE_SIZE = 120, PATTERN_SIZE = 30, HOOK_NAME_SIZE = 60, FIXED_SPLIT_VALUE = 0x10001 }; enum WildcardByte { XX = 0x11 }; enum HostCommandType { HOST_COMMAND_NEW_HOOK, HOST_COMMAND_REMOVE_HOOK, HOST_COMMAND_FIND_HOOK, HOST_COMMAND_MODIFY_HOOK, HOST_COMMAND_HIJACK_PROCESS, HOST_COMMAND_DETACH }; @@ -27,8 +27,7 @@ enum HookParamType : unsigned FIXING_SPLIT = 0x800, DIRECT_READ = 0x1000, // /R read code instead of classic /H hook code FULL_STRING = 0x2000, - BLOCK_FLOOD = 0x4000, // remove this hook if flooding text causing perf issues - HEX_DUMP = 0x8000, - HOOK_ENGINE = 0x10000, - HOOK_ADDITIONAL = 0x20000, + HEX_DUMP = 0x4000, + HOOK_ENGINE = 0x8000, + HOOK_ADDITIONAL = 0x10000, }; diff --git a/texthook/engine/engine.cc b/texthook/engine/engine.cc index cfa8df1..abf3c1f 100644 --- a/texthook/engine/engine.cc +++ b/texthook/engine/engine.cc @@ -16717,6 +16717,7 @@ void InsertMonoHook(HMODULE h) if (!getDomain || !getName || !getJitInfo) goto failed; static auto domain = getDomain(); if (!domain) goto failed; + ConsoleOutput("Textractor: Mono Dynamic ENTER (hook = %s)", loadedConfig ? loadedConfig : "brute force"); const BYTE prolog[] = { 0x55, 0x8b, 0xec }; for (auto addr : Util::SearchMemory(prolog, sizeof(prolog), PAGE_EXECUTE_READWRITE)) { @@ -16726,24 +16727,29 @@ void InsertMonoHook(HMODULE h) { if (getJitInfo(domain, addr)) if (char* name = getName(addr)) - if (strstr(name, "string:") && !strstr(name, "string:mem")) + if ((!loadedConfig && strstr(name, "string:") && !strstr(name, "string:mem")) || (loadedConfig && strstr(name, loadedConfig))) { HookParam hp = {}; hp.address = addr; - hp.type = USING_UNICODE | FULL_STRING | BLOCK_FLOOD; + hp.type = USING_UNICODE | FULL_STRING; hp.offset = 4; + char nameForUser[HOOK_NAME_SIZE] = {}; + strncpy_s(nameForUser, name + 1, HOOK_NAME_SIZE - 1); + if (char* end = strstr(nameForUser, " + 0x0")) *end = 0; hp.text_fun = [](DWORD esp_base, HookParam*, BYTE, DWORD* data, DWORD* split, DWORD* len) { MonoString* string = (MonoString*)argof(1, esp_base); *data = (DWORD)string->chars; *len = string->length * 2; }; - NewHook(hp, name); + NewHook(hp, nameForUser); } } __except (EXCEPTION_EXECUTE_HANDLER) {} }(addr); } + if (!loadedConfig) ConsoleOutput("Textractor: Mono Dynamic used brute force: if performance issues arise, please create a TextractorConfig.txt file" + "next to the main executable and put the name of a working hook inside it"); return true; failed: ConsoleOutput("Textractor: Mono Dynamic failed"); diff --git a/texthook/engine/engine.h b/texthook/engine/engine.h index 4fb3acf..e1d63e6 100644 --- a/texthook/engine/engine.h +++ b/texthook/engine/engine.h @@ -15,6 +15,7 @@ namespace Engine { // Global variables extern wchar_t *processName, // cached processPath[MAX_PATH]; // cached +inline const char *requestedEngine = nullptr, *loadedConfig = nullptr; // Artikash 6/17/2019 TODO: These have the wrong values on x64 /** jichi 12/24/2014 diff --git a/texthook/engine/match.cc b/texthook/engine/match.cc index c1bb7a2..cbc177e 100644 --- a/texthook/engine/match.cc +++ b/texthook/engine/match.cc @@ -12,6 +12,8 @@ namespace Engine WCHAR* processName, // cached processPath[MAX_PATH]; // cached + char configFileData[1000]; + bool UnsafeDetermineEngineType(); // jichi 10/21/2014: Return whether found the game engine @@ -41,6 +43,19 @@ namespace Engine { GetModuleFileNameW(nullptr, processPath, MAX_PATH); processName = wcsrchr(processPath, L'\\') + 1; + wchar_t configFilename[MAX_PATH + sizeof(L"TextractorConfig.txt")]; + wcsncpy_s(configFilename, processPath, MAX_PATH - 1); + wcscpy_s(wcsrchr(configFilename, L'\\') + 1, sizeof(L"TextractorConfig.txt"), L"TextractorConfig.txt"); + if (AutoHandle<> configFile = CreateFileW(configFilename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) + { + if (ReadFile(configFile, configFileData, sizeof(configFileData) - 1, DUMMY, nullptr)) ConsoleOutput("Textractor: game configuration loaded"); + if (strncmp(configFileData, "Engine:", 7) == 0) + { + if (loadedConfig = strchr(configFileData, '\n')) *(char*)loadedConfig++ = 0; + ConsoleOutput("Textractor: Engine = %s", requestedEngine = configFileData + 7); + } + else loadedConfig = configFileData; + } processStartAddress = processStopAddress = (uintptr_t)GetModuleHandleW(nullptr); MEMORY_BASIC_INFORMATION info; diff --git a/texthook/engine/match64.cc b/texthook/engine/match64.cc index c0edef2..2ed9a50 100644 --- a/texthook/engine/match64.cc +++ b/texthook/engine/match64.cc @@ -80,6 +80,7 @@ namespace Engine if (!getDomain || !getName || !getJitInfo) goto failed; static auto domain = getDomain(); if (!domain) goto failed; + ConsoleOutput("Textractor: Mono Dynamic ENTER (hook = %s)", loadedConfig ? loadedConfig : "brute force"); const BYTE prolog1[] = { 0x55, 0x48, 0x8b, 0xec }; const BYTE prolog2[] = { 0x48, 0x83, 0xec }; for (auto [prolog, size] : Array{ { prolog1, sizeof(prolog1) }, { prolog2, sizeof(prolog2) } }) @@ -91,13 +92,17 @@ namespace Engine { if (getJitInfo(domain, addr)) if (char* name = getName(addr)) - if (strstr(name, "string:") && strstr(name, "+ 0x0") && !strstr(name, "string:mem")) + if ((!loadedConfig && strstr(name, "string:") && strstr(name, "+ 0x0") && !strstr(name, "string:mem")) || + loadedConfig && strstr(name, loadedConfig) && strstr(name, "+ 0x0")) { HookParam hp = {}; hp.address = addr; - hp.type = USING_STRING | USING_UNICODE | BLOCK_FLOOD | FULL_STRING; + hp.type = USING_STRING | USING_UNICODE | FULL_STRING; hp.offset = -0x20; // rcx hp.padding = 20; + char nameForUser[HOOK_NAME_SIZE] = {}; + strncpy_s(nameForUser, name + 1, HOOK_NAME_SIZE - 1); + if (char* end = strstr(nameForUser, " + 0x0")) *end = 0; hp.length_fun = [](uintptr_t, uintptr_t data) { /* Artikash 6/18/2019: @@ -106,12 +111,14 @@ namespace Engine int len = *(int*)(data - 4); return len > 0 && len < PIPE_BUFFER_SIZE ? len * 2 : 0; }; - NewHook(hp, name); + NewHook(hp, nameForUser); } } __except (EXCEPTION_EXECUTE_HANDLER) {} }(addr); } + if (!loadedConfig) ConsoleOutput("Textractor: Mono Dynamic used brute force: if performance issues arise, please create a TextractorConfig.txt file" + "next to the main executable and put the name of a working hook inside it"); return true; failed: ConsoleOutput("Textractor: Mono Dynamic failed");