From b8bd602474f8f322e0cc840cc87c822b1ab0a27f Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 6 Jun 2019 23:53:37 -0400 Subject: [PATCH] more user friendly hook searching and refactors --- GUI/mainwindow.cpp | 25 +- include/types.h | 6 +- text.cpp | 19 +- texthook/CMakeLists.txt | 2 + texthook/engine/engine.cc | 18 +- texthook/engine/engine.h | 12 +- texthook/engine/match.cc | 923 ++----------------------------------- texthook/engine/match32.cc | 824 +++++++++++++++++++++++++++++++++ texthook/engine/match64.cc | 23 +- 9 files changed, 923 insertions(+), 929 deletions(-) create mode 100644 texthook/engine/match32.cc diff --git a/GUI/mainwindow.cpp b/GUI/mainwindow.cpp index 1d96bc6..485c599 100644 --- a/GUI/mainwindow.cpp +++ b/GUI/mainwindow.cpp @@ -33,6 +33,7 @@ extern const char* SEARCH_DURATION; extern const char* PATTERN_OFFSET; extern const char* MIN_ADDRESS; extern const char* MAX_ADDRESS; +extern const char* HOOK_SEARCH_FILTER; extern const char* START_HOOK_SEARCH; extern const char* SAVE_SEARCH_RESULTS; extern const char* TEXT_FILES; @@ -336,11 +337,11 @@ void MainWindow::FindHooks() void launch() { auto layout = new QFormLayout(this); - auto patternInput = new QLineEdit("8B FF 55 8B EC", this); + auto patternInput = new QLineEdit(x64 ? "CC CC 48 89" : "CC CC 55 8B EC", this); layout->addRow(SEARCH_PATTERN, patternInput); for (auto[value, label] : Array>{ - { sp.searchTime, SEARCH_DURATION }, - { sp.offset, PATTERN_OFFSET }, + { sp.searchTime = 20000, SEARCH_DURATION }, + { sp.offset = 2, PATTERN_OFFSET }, }) { auto spinBox = new QSpinBox(this); @@ -350,8 +351,8 @@ void MainWindow::FindHooks() connect(spinBox, qOverload(&QSpinBox::valueChanged), [=, &value] { value = spinBox->value(); }); } for (auto[value, label] : Array>{ - { sp.minAddress, MIN_ADDRESS }, - { sp.maxAddress, MAX_ADDRESS }, + { sp.minAddress = 0, MIN_ADDRESS }, + { sp.maxAddress = -1ULL, MAX_ADDRESS }, }) { auto input = new QLineEdit(QString::number(value, 16), this); @@ -361,19 +362,23 @@ void MainWindow::FindHooks() bool ok; if (uintptr_t newValue = input.toULongLong(&ok, 16); ok) value = newValue; }); - } + } + auto filterInput = new QLineEdit(this); + layout->addRow(HOOK_SEARCH_FILTER, filterInput); auto save = new QPushButton(START_HOOK_SEARCH, this); layout->addWidget(save); connect(save, &QPushButton::clicked, this, &QDialog::accept); - connect(save, &QPushButton::clicked, [this, patternInput] + connect(save, &QPushButton::clicked, [this, patternInput, filterInput] { - QByteArray pattern = QByteArray::fromHex(patternInput->text().toUtf8()); + QByteArray pattern = QByteArray::fromHex(patternInput->text().replace("??", "11").toUtf8()); if (pattern.size() < 3) return; + std::wregex filter(L"."); + if (!filterInput->text().isEmpty()) try { filter = std::wregex(S(filterInput->text())); } catch (std::regex_error&) {}; memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), 25)); auto hooks = std::make_shared(); - Host::FindHooks(processId, sp, [hooks](HookParam hp, DWORD processId, const std::wstring& text) + Host::FindHooks(processId, sp, [hooks, filter](HookParam hp, DWORD processId, const std::wstring& text) { - hooks->append(S(Util::GenerateCode(hp, processId)) + ": " + S(text) + "\n"); + if (std::regex_search(text, filter)) hooks->append(S(Util::GenerateCode(hp, processId)) + ": " + S(text) + "\n"); }); QString fileName = QFileDialog::getSaveFileName(this, SAVE_SEARCH_RESULTS, "./Hooks.txt", TEXT_FILES); if (fileName.isEmpty()) fileName = "Hooks.txt"; diff --git a/include/types.h b/include/types.h index a59f693..7249fd4 100644 --- a/include/types.h +++ b/include/types.h @@ -62,9 +62,9 @@ struct SearchParam { BYTE pattern[25] = {}; // pattern in memory to search for int length, // length of pattern - offset = 0, // offset from start of pattern to add hook - searchTime = 30000; // ms - uintptr_t minAddress = 0, maxAddress = (uintptr_t)-1LL; + offset, // offset from start of pattern to add hook + searchTime; // ms + uintptr_t minAddress, maxAddress; }; struct InsertHookCmd // From host diff --git a/text.cpp b/text.cpp index c48faba..4e18071 100644 --- a/text.cpp +++ b/text.cpp @@ -47,15 +47,16 @@ const char* INVALID_EXTENSION = u8"%1 is an invalid extension"; const char* CONFIRM_EXTENSION_OVERWRITE = u8"Another version of this extension already exists, do you want to delete and overwrite it?"; const char* EXTENSION_WRITE_ERROR = u8"Failed to save extension"; const char* USE_JP_LOCALE = u8"Emulate japanese locale?"; -extern const char* HOOH_SEARCH_UNSTABLE_WARNING = u8"Searching for hooks is unstable! Be prepared for your game to crash!"; -extern const char* SEARCH_PATTERN = u8"Search pattern (hex byte array)"; -extern const char* SEARCH_DURATION = u8"Search duration (ms)"; -extern const char* PATTERN_OFFSET = u8"Offset from pattern start"; -extern const char* MIN_ADDRESS = u8"Minimum address (hex)"; -extern const char* MAX_ADDRESS = u8"Maximum address (hex)"; -extern const char* START_HOOK_SEARCH = u8"Start hook search"; -extern const char* SAVE_SEARCH_RESULTS = u8"Save search results"; -extern const char* TEXT_FILES = u8"Text (*.txt)"; +const char* HOOH_SEARCH_UNSTABLE_WARNING = u8"Searching for hooks is unstable! Be prepared for your game to crash!"; +const char* SEARCH_PATTERN = u8"Search pattern (hex byte array)"; +const char* SEARCH_DURATION = u8"Search duration (ms)"; +const char* PATTERN_OFFSET = u8"Offset from pattern start"; +const char* MIN_ADDRESS = u8"Minimum address (hex)"; +const char* MAX_ADDRESS = u8"Maximum address (hex)"; +const char* HOOK_SEARCH_FILTER = u8"Results must match this regex"; +const char* START_HOOK_SEARCH = u8"Start hook search"; +const char* SAVE_SEARCH_RESULTS = u8"Save search results"; +const char* TEXT_FILES = u8"Text (*.txt)"; const char* FILTER_REPETITION = u8"Repetition Filter"; const char* DEFAULT_CODEPAGE = u8"Default Codepage"; const char* FLUSH_DELAY = u8"Flush Delay"; diff --git a/texthook/CMakeLists.txt b/texthook/CMakeLists.txt index 6e05fc9..5c6c9cf 100644 --- a/texthook/CMakeLists.txt +++ b/texthook/CMakeLists.txt @@ -5,6 +5,7 @@ set(texthook_src main.cc texthook.cc hookfinder.cc + engine/match.cc engine/match64.cc engine/native/pchooks.cc util/ithsys/ithsys.cc @@ -17,6 +18,7 @@ set(texthook_src hookfinder.cc engine/engine.cc engine/match.cc + engine/match32.cc engine/native/pchooks.cc util/util.cc util/ithsys/ithsys.cc diff --git a/texthook/engine/engine.cc b/texthook/engine/engine.cc index f86cff2..9d5e08d 100644 --- a/texthook/engine/engine.cc +++ b/texthook/engine/engine.cc @@ -1618,7 +1618,7 @@ bool InsertBGI1Hook() //ConsoleOutput("Probably BGI. Wait for text."); //SwitchTrigger(true); - //trigger_fun_=InsertBGIDynamicHook; + //trigger_fun=InsertBGIDynamicHook; ConsoleOutput("vnreng:BGI: failed"); return false; } @@ -2232,7 +2232,7 @@ void InsertRealliveHook() { //ConsoleOutput("Probably Reallive. Wait for text."); ConsoleOutput("vnreng: TRIGGER Reallive"); - trigger_fun_ = InsertRealliveDynamicHook; + trigger_fun = InsertRealliveDynamicHook; SetTrigger(); } @@ -5787,7 +5787,7 @@ bool InsertShinaHook() int ver = GetShinaRioVersion(); if (ver >= 50) { SetTrigger(); - trigger_fun_ = StackSearchingTrigger; + trigger_fun = StackSearchingTrigger; ConsoleOutput("Textractor: ShinaRio 2.50+: adding trigger"); return true; } @@ -5960,7 +5960,7 @@ void InsertWaffleHook() return; } //ConsoleOutput("Probably Waffle. Wait for text."); - trigger_fun_ = InsertWaffleDynamicHook; + trigger_fun = InsertWaffleDynamicHook; SetTrigger(); //ConsoleOutput("vnreng:WAFFLE: failed"); } @@ -7656,7 +7656,7 @@ bool InsertLiveDynamicHook(LPVOID addr, DWORD frame, DWORD stack) //void InsertLiveHook() //{ // ConsoleOutput("Probably Live. Wait for text."); -// trigger_fun_=InsertLiveDynamicHook; +// trigger_fun=InsertLiveDynamicHook; // SwitchTrigger(true); //} bool InsertLiveHook() @@ -8524,7 +8524,7 @@ bool InsertSystemAoiDynamic() { ConsoleOutput("vnreng: DYNAMIC SystemAoi"); //ConsoleOutput("Probably SoftHouseChara. Wait for text."); - trigger_fun_ = InsertSystemAoiDynamicHook; + trigger_fun = InsertSystemAoiDynamicHook; SetTrigger(); return true; } @@ -8811,7 +8811,7 @@ bool InsertIGSDynamicHook(LPVOID addr, DWORD frame, DWORD stack) void InsertIronGameSystemHook() { //ConsoleOutput("Probably IronGameSystem. Wait for text."); - trigger_fun_ = InsertIGSDynamicHook; + trigger_fun = InsertIGSDynamicHook; SetTrigger(); ConsoleOutput("vnreng: TRIGGER IronGameSystem"); } @@ -9448,7 +9448,7 @@ bool InsertRyokuchaDynamicHook(LPVOID addr, DWORD frame, DWORD stack) void InsertRyokuchaHook() { //ConsoleOutput("Probably Ryokucha. Wait for text."); - trigger_fun_ = InsertRyokuchaDynamicHook; + trigger_fun = InsertRyokuchaDynamicHook; SetTrigger(); ConsoleOutput("vnreng: TRIGGER Ryokucha"); } @@ -16512,7 +16512,7 @@ void InsertMonoHook(HMODULE h) Mono calling convention uses 'this' as first argument on stack Must be dynamic hook bootstrapped from other mono api or mono_domain_get won't work */ - trigger_fun_ = [](LPVOID addr, DWORD, DWORD) + trigger_fun = [](LPVOID addr, DWORD, DWORD) { static auto getDomain = (MonoDomain*(*)())GetProcAddress(mono, "mono_domain_get"); static auto getJitInfo = (MonoObject*(*)(MonoDomain*, uintptr_t))GetProcAddress(mono, "mono_jit_info_table_find"); diff --git a/texthook/engine/engine.h b/texthook/engine/engine.h index 3004ee8..99e8f9c 100644 --- a/texthook/engine/engine.h +++ b/texthook/engine/engine.h @@ -8,7 +8,7 @@ struct HookParam; // defined in ith types.h -extern DWORD processStartAddress, processStopAddress; +extern uintptr_t processStartAddress, processStopAddress; namespace Engine { @@ -16,9 +16,13 @@ namespace Engine { extern wchar_t *processName, // cached processPath[MAX_PATH]; // cached -//extern LPVOID trigger_addr; -typedef bool (* trigger_fun_t)(LPVOID addr, DWORD frame, DWORD stack); -extern trigger_fun_t trigger_fun_; +/** jichi 12/24/2014 + * @param addr function address + * @param frame real address of the function, supposed to be the same as addr + * @param stack address of current stack - 4 + * @return If success, which is reverted + */ +inline bool (*trigger_fun)(LPVOID addr, DWORD frame, DWORD stack); bool InsertMonoHooks(); // Mono diff --git a/texthook/engine/match.cc b/texthook/engine/match.cc index 812941b..4cf7b47 100644 --- a/texthook/engine/match.cc +++ b/texthook/engine/match.cc @@ -1,887 +1,58 @@ -// match.cc -// 8/9/2013 jichi -// Branch: ITH_Engine/engine.cpp, revision 133 - -#include "engine/match.h" -#include "engine/engine.h" -#include "engine/native/pchooks.h" -#include "util/util.h" +#include "match.h" +#include "engine.h" #include "main.h" -#include "ithsys/ithsys.h" +#include "native/pchooks.h" extern const char* HIJACK_ERROR; -//#define ConsoleOutput(...) (void)0 // jichi 8/18/2013: I don't need ConsoleOutput +uintptr_t processStartAddress, processStopAddress; -enum { MAX_REL_ADDR = 0x200000 }; // jichi 8/18/2013: maximum relative address - -// - Global variables - - -DWORD processStartAddress, processStopAddress; - -namespace Engine { - -WCHAR *processName, // cached - processPath[MAX_PATH]; // cached - -//LPVOID trigger_addr; -/** jichi 12/24/2014 - * @param addr function address - * @param frame real address of the function, supposed to be the same as addr - * @param stack address of current stack - 4 - * @return If success, which is reverted -*/ -trigger_fun_t trigger_fun_; - -} // namespace Engine - -// - Methods - - -namespace Engine { namespace { // unnamed - -bool DetermineGameHooks() // 7/19/2015 +namespace Engine { -#if 0 // jichi 7/19/2015: Disabled as it will crash the game - if (Util::CheckFile(L"UE3ShaderCompileWorker.exe") && Util::CheckFile(L"awesomium_process.exe")) { - InsertLovaGameHook(); - return true; - } -#endif // 0 - return false; -} + WCHAR* processName, // cached + processPath[MAX_PATH]; // cached -// jichi 7/17/2014: Disable GDI hooks for PPSSPP -bool DeterminePCEngine() -{ - if (DetermineGameHooks()) { - ConsoleOutput("vnreng: found game-specific hook"); - return true; - } + bool UnsafeDetermineEngineType(); - if (Util::CheckFile(L"PPSSPP*.exe")) { // jichi 7/12/2014 PPSSPPWindows.exe, PPSSPPEX.exe PPSSPPSP.exe - //InsertPPSSPPHooks(); // Artikash 8/4/2018: removed for now as doesn't work for non ancient ppsspp versions - return true; - } - - if (Util::CheckFile(L"pcsx2*.exe")) { // jichi 7/19/2014 PCSX2.exe or PCSX2WX.exe - InsertPCSX2Hooks(); - return true; - } - - if (Util::CheckFile(L"Dolphin.exe")) { // jichi 7/20/2014 - InsertGCHooks(); - return true; - } - - // jichi 5/14/2015: Skip hijacking BALDRSKY ZEROs - //if (Util::CheckFile(L"bsz_Data\\Mono\\mono.dll") || Util::CheckFile(L"bsz2_Data\\Mono\\mono.dll")) { - // ConsoleOutput("vnreng: IGNORE BALDRSKY ZEROs"); - // return true; - //} - - for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" }) - if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); - else for (int i = 0; i < 50; ++i) - if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); - - if (GetProcAddress((HMODULE)processStartAddress, "?Write@String@v8@@QBEHPAGHHH@Z")) - InsertV8Hook((HMODULE)processStartAddress); - if (HMODULE module = GetModuleHandleW(L"node.dll")) - InsertV8Hook(module); - if (HMODULE module = GetModuleHandleW(L"nw.dll")) - InsertV8Hook(module); - - if (InsertMonoHooks()) { - return true; - } - - // PC games - PcHooks::hookGDIFunctions(); - PcHooks::hookGDIPlusFunctions(); - const char check[] = "sdffffffkjldfjlhjweiumxnvq1204tergdmnxcq1111111111111111111111408t03kxjb40"; - Util::SearchMemory((const BYTE*)check, sizeof(check)); // Not too sure about the stability of this guy, so test it here - return false; -} - -bool DetermineEngineByFile1() -{ - // Artikash 7/14/2018: AIRNovel - sample game https://vndb.org/v18814 - if (Util::CheckFile(L"*.swf")) - { - //InsertAdobeAirHook(); - InsertAIRNovelHook(); - return true; - } - - // Artikash 8/9/2018: Renpy - sample game https://vndb.org/v19843 - if (Util::CheckFile(L"*.py")) - { - InsertRenpyHook(); - return true; - } - - if (Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)")) { - if (Util::SearchResourceString(L"TVP(KIRIKIRI) Z ")) { // TVP(KIRIKIRI) Z CORE - // jichi 11/24/2014: Disabled that might crash VBH - //if (Util::CheckFile(L"plugin\\KAGParser.dll")) - // InsertKAGParserHook(); - //else if (Util::CheckFile(L"plugin\\KAGParserEx.dll")) - // InsertKAGParserExHook(); - if (InsertKiriKiriZHook()) - return true; - } - InsertKiriKiriHook(); - return true; - } - // 8/2/2014 jichi: Game name shown as 2RM - Adventure Engine, text also in GetGlyphOutlineA - if (Util::SearchResourceString(L"2RM") && Util::SearchResourceString(L"Adventure Engine")) { - Insert2RMHook(); - return true; - } - // 8/2/2014 jichi: Copyright is side-B, a conf.dat will be generated after the game is launched - // It also contains lua5.1.dll and lua5.dll - if (Util::SearchResourceString(L"side-B")) { - InsertSideBHook(); - return true; - } - if (Util::CheckFile(L"bgi.*") || Util::CheckFile(L"sysgrp.arc")) { - InsertBGIHook(); - return true; - } - if (Util::CheckFile(L"Bootup.dat") && InsertBootupHook()) // 5/22/2015 Bootup - // lstrlenW can also find text with repetition though - return true; - if (Util::CheckFile(L"AGERC.DLL")) { // 6/1/2014 jichi: Eushully, AGE.EXE - InsertEushullyHook(); - return true; - } - if (Util::CheckFile(L"data*.arc") && Util::CheckFile(L"stream*.arc")) { - InsertMajiroHook(); - return true; - } - // jichi 5/31/2014 - if (//Util::CheckFile(L"Silkys.exe") || // It might or might not have Silkys.exe - // data, effect, layer, mes, music - Util::CheckFile(L"data.arc") && Util::CheckFile(L"effect.arc") && Util::CheckFile(L"mes.arc")) { - InsertElfHook(); - return true; - } - // jichi 6/9/2015: Skip Silkys Sakura - if ( // Almost the same as Silkys except mes.arc is replaced by Script.arc - Util::CheckFile(L"data.arc") && Util::CheckFile(L"effect.arc") && Util::CheckFile(L"Script.arc")) { - InsertSilkysHook(); - return true; - } - if (Util::CheckFile(L"data\\pack\\*.cpz")) { - InsertCMVSHook(); - return true; - } - // jichi 10/12/2013: Restore wolf engine - // jichi 10/18/2013: Check for data/*.wolf - if (Util::CheckFile(L"data.wolf") || Util::CheckFile(L"data\\*.wolf") || Util::CheckFile(L"data\\basicdata\\cdatabase.dat")) { - InsertWolfHook(); - return true; - } - if (Util::CheckFile(L"AdvData\\DAT\\NAMES.DAT")) { - InsertCircusHook1(); - return true; - } - if (Util::CheckFile(L"AdvData\\GRP\\NAMES.DAT")) { - InsertCircusHook2(); - return true; - } - if (Util::CheckFile(L"*.noa") || Util::CheckFile(L"data\\*.noa")) { - InsertCotophaHook(); - return true; - } - if (Util::CheckFile(L"*.pfs")) { // jichi 10/1/2013 - InsertArtemisHook(); - return true; - } - if (Util::CheckFile(L"*.int")) { - InsertCatSystemHook(); - return true; - } - if (Util::CheckFile(L"message.dat")) { - InsertAtelierHook(); - return true; - } - if (Util::CheckFile(L"Check.mdx")) { // jichi 4/1/2014: AUGame - InsertTencoHook(); - return true; - } - // jichi 12/25/2013: It may or may not be QLIE. - // AlterEgo also has GameData/sound.pack but is not QLIE - if (Util::CheckFile(L"GameData\\*.pack") && InsertQLIEHook()) - return true; - - if (Util::CheckFile(L"dll\\Pal.dll")) { - InsertPalHook(); - return true; - } - - if (Util::CheckFile(L"*.pac")) { - // jichi 6/3/2014: AMUSE CRAFT and SOFTPAL - // Selectively insert, so that lstrlenA can still get correct text if failed - //if (Util::CheckFile(L"dll\\resource.dll") && Util::CheckFile(L"dll\\pal.dll") && InsertAmuseCraftHook()) - // return true; - - if (Util::CheckFile(L"Thumbnail.pac")) { - //ConsoleOutput("vnreng: IGNORE NeXAS"); - InsertNeXASHook(); // jichi 7/6/2014: GIGA - return true; - } - - if (Util::SearchResourceString(L"SOFTPAL")) { - ConsoleOutput("vnreng: IGNORE SoftPal UNiSONSHIFT"); - return true; - } - } - // jichi 12/27/2014: LunaSoft - if (Util::CheckFile(L"Pac\\*.pac")) { - InsertLunaSoftHook(); - return true; - } - // jichi 9/16/2013: Add Gesen18 - if (Util::CheckFile(L"*.szs") || Util::CheckFile(L"Data\\*.szs")) { - InsertUnicornHook(); - return true; - } - // jichi 12/22/2013: Add rejet - if (Util::CheckFile(L"gd.dat") && Util::CheckFile(L"pf.dat") && Util::CheckFile(L"sd.dat")) { - InsertRejetHook(); - return true; - } - // Only examined with version 1.0 - //if (Util::CheckFile(L"Adobe AIR\\Versions\\*\\Adobe AIR.dll")) { // jichi 4/15/2014: FIXME: Wildcard not working - if (Util::CheckFile(L"Adobe AIR\\Versions\\1.0\\Adobe AIR.dll")) { // jichi 4/15/2014: Adobe AIR - InsertAdobeAirHook(); - return true; - } - return false; -} - -bool DetermineEngineByFile2() -{ - if (Util::CheckFile(L"resident.dll")) { - InsertRetouchHook(); - return true; - } - if (Util::CheckFile(L"Malie.ini") || Util::CheckFile(L"Malie.exe")) { // jichi: 9/9/2014: Add malie.exe in case malie.ini is missing - InsertMalieHook(); - return true; - } - if (Util::CheckFile(L"live.dll")) { - InsertLiveHook(); - return true; - } - // 9/5/2013 jichi - if (Util::CheckFile(L"aInfo.db")) { - InsertNextonHook(); - return true; - } - if (Util::CheckFile(L"*.lpk")) { - InsertLucifenHook(); - return true; - } - if (Util::CheckFile(L"cfg.pak")) { - InsertWaffleHook(); - return true; - } - if (Util::CheckFile(L"Arc00.dat")) { - InsertTinkerBellHook(); - return true; - } - if (Util::CheckFile(L"*.vfs")) { // jichi 7/6/2014: Better to test AoiLib.dll? ja.wikipedia.org/wiki/ソフトハウスキャラ - InsertSystemAoiHook(); - return true; - } - if (Util::CheckFile(L"*.mbl")) { - InsertMBLHook(); - return true; - } - // jichi 8/1/2014: YU-RIS engine, lots of clockup game also has this pattern - if (Util::CheckFile(L"pac\\*.ypf") || Util::CheckFile(L"*.ypf")) { - // jichi 8/14/2013: CLOCLUP: "ノーブレスオブリージュ" would crash the game. - if (!Util::CheckFile(L"noblesse.exe")) - InsertYurisHook(); - return true; - } - if (Util::CheckFile(L"*.npa")) { - InsertNitroplusHook(); - return true; - } - return false; -} - -bool DetermineEngineByFile3() -{ - //if (Util::CheckFile(L"libscr.dll")) { // already checked - // InsertBrunsHook(); - // return true; - //} - - // jichi 10/12/2013: Sample args.txt: - // See: http://tieba.baidu.com/p/2631413816 - // -workdir - // . - // -loadpath - // . - // am.cfg - if (Util::CheckFile(L"args.txt")) { - InsertBrunsHook(); - return true; - } - if (Util::CheckFile(L"emecfg.ecf")) { - InsertEMEHook(); - return true; - } - if (Util::CheckFile(L"rrecfg.rcf")) { - InsertRREHook(); - return true; - } - if (Util::CheckFile(L"*.fpk") || Util::CheckFile(L"data\\*.fpk")) { - InsertCandyHook(); - return true; - } - if (Util::CheckFile(L"arc.a*")) { - InsertApricoTHook(); - return true; - } - if (Util::CheckFile(L"*.mpk")) { - InsertStuffScriptHook(); - return true; - } - if (Util::CheckFile(L"USRDIR\\*.mpk")) { // jichi 12/2/2014 - InsertStuffScriptHook(); - return true; - } - if (Util::CheckFile(L"Execle.exe")) { - InsertTriangleHook(); - return true; - } - // jichi 2/28/2015: No longer work for "大正×対称アリス episode I" from Primula - //if (Util::CheckFile(L"PSetup.exe")) { - // InsertPensilHook(); - // return true; - //} - if (Util::CheckFile(L"Yanesdk.dll")) { - InsertAB2TryHook(); - return true; - } - if (Util::CheckFile(L"*.med")) { - InsertMEDHook(); - return true; - } - return false; -} - -bool DetermineEngineByFile4() -{ - if (Util::CheckFile(L"EAGLS.dll")) { // jichi 3/24/2014: E.A.G.L.S - //ConsoleOutput("vnreng: IGNORE EAGLS"); - InsertEaglsHook(); - return true; - } - if (Util::CheckFile(L"bmp.pak") && Util::CheckFile(L"dsetup.dll")) { - // 1/1/2016 jich: skip izumo4 from studio ego that is not supported by debonosu - if (Util::CheckFile(L"*izumo4*.exe")) { - PcHooks::hookOtherPcFunctions(); - return true; - } - InsertDebonosuHook(); - return true; - } - if (Util::CheckFile(L"C4.EXE") || Util::CheckFile(L"XEX.EXE")) { - InsertC4Hook(); - return true; - } - if (Util::CheckFile(L"Rio.arc") && Util::CheckFile(L"Chip*.arc")) { - InsertWillPlusHook(); - return true; - } - if (Util::CheckFile(L"*.tac")) { - InsertTanukiHook(); - return true; - } - if (Util::CheckFile(L"*.gxp")) { - InsertGXPHook(); - return true; - } - if (Util::CheckFile(L"*.aos")) { // jichi 4/2/2014: AOS hook - InsertAOSHook(); - return true; - } - if (Util::CheckFile(L"*.at2")) { // jichi 12/23/2014: Mink, sample files: voice.at2, voice.det, voice.nme - InsertMinkHook(); - return true; - } - if (Util::CheckFile(L"*.ykc")) { // jichi 7/15/2014: YukaSystem1 is not supported, though - //ConsoleOutput("vnreng: IGNORE YKC:Feng/HookSoft(SMEE)"); - InsertYukaSystem2Hook(); - return true; - } - if (Util::CheckFile(L"model\\*.hed")) { // jichi 9/8/2014: EXP - InsertExpHook(); - return true; - } - // jichi 2/6/2015 平安亭 - // dPi.dat, dPih.dat, dSc.dat, dSch.dat, dSo.dat, dSoh.dat, dSy.dat - //if (Util::CheckFile(L"dSoh.dat")) { // no idea why this file does not work - if (Util::CheckFile(L"dSch.dat")) { - InsertSyuntadaHook(); - return true; - } - - // jichi 2/28/2015: Delay checking Pensil in case something went wrong - // File pattern observed in [Primula] 大正×対称アリス episode I - // - PSetup.exe no longer exists - // - MovieTexture.dll information shows MovieTex dynamic library, copyright Pensil 2013 - // - ta_trial.exe information shows 2XT - Primula Adventure Engine - if (Util::CheckFile(L"PSetup.exe") || Util::CheckFile(L"PENCIL.*") || Util::SearchResourceString(L"2XT -")) { - InsertPensilHook(); - return true; - } - - return false; -} - -bool DetermineEngineByProcessName() -{ - WCHAR str[MAX_PATH]; - wcscpy_s(str, processName); - _wcslwr_s(str); // lower case - - if (wcsstr(str,L"reallive") || Util::CheckFile(L"Reallive.exe") || Util::CheckFile(L"REALLIVEDATA\\Start.ini")) { - InsertRealliveHook(); - return true; - } - - // jichi 8/19/2013: DO NOT WORK for games like「ハピメア」 - //if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) { - // InsertCMVSHook(); - // return true; - //} - - // jichi 8/17/2013: Handle "~" - if (wcsstr(str, L"siglusengine") || !wcsncmp(str, L"siglus~", 7) || Util::CheckFile(L"SiglusEngine.exe")) { - InsertSiglusHook(); - return true; - } - - if (wcsstr(str, L"taskforce2") || !wcsncmp(str, L"taskfo~", 7) || Util::CheckFile(L"Taskforce2.exe")) { - InsertTaskforce2Hook(); - return true; - } - - if (wcsstr(str,L"rugp") || Util::CheckFile(L"rugp.exe")) { - InsertRUGPHook(); - return true; - } - - // jichi 8/17/2013: Handle "~" - if (wcsstr(str, L"igs_sample") || !wcsncmp(str, L"igs_sa~", 7) || Util::CheckFile(L"igs_sample.exe")) { - InsertIronGameSystemHook(); - return true; - } - - if (wcsstr(str, L"bruns") || Util::CheckFile(L"bruns.exe")) { - InsertBrunsHook(); - return true; - } - - if (wcsstr(str, L"anex86") || Util::CheckFile(L"anex86.exe")) { - InsertAnex86Hook(); - return true; - } - - // jichi 8/17/2013: Handle "~" - if (wcsstr(str, L"shinydays") || !wcsncmp(str, L"shinyd~", 7) || Util::CheckFile(L"ShinyDays.exe")) { - InsertShinyDaysGameHook(); - return true; - } - - if (wcsstr(processName, L"SAISYS") || Util::CheckFile(L"SaiSys.exe")) { // jichi 4/19/2014: Marine Heart - InsertMarineHeartHook(); - return true; - } - - DWORD len = wcslen(str); - - // jichi 8/24/2013: Checking for Rio.ini or $procname.ini - //wcscpy(str+len-4, L"_?.war"); - //if (Util::CheckFile(str)) { - // InsertShinaHook(); - // return true; - //} - if (Util::CheckFile(L"*.ini")) { - if (InsertShinaHook()) - return true; - } - - // jichi 8/10/2013: Since *.bin is common, move CaramelBox to the end - str[len - 3] = L'b'; - str[len - 2] = L'i'; - str[len - 1] = L'n'; - str[len] = 0; - if ((Util::CheckFile(str) || Util::CheckFile(L"trial.bin")) // jichi 7/8/2014: add trial.bin - && InsertCaramelBoxHook()) - return true; - - // jichi 7/23/2015 It also has gameexe.bin existed - if (Util::CheckFile(L"configure.cfg") && Util::CheckFile(L"gfx.bin")) { - InsertEscudeHook(); - return true; - } - - // This must appear at last since str is modified - //wcscpy(str + len - 4, L"_checksum.exe"); - if (Util::CheckFile(L"*_checksum.exe")) { - InsertRyokuchaHook(); - - if (Util::CheckFile(L"*.iar") && Util::CheckFile(L"*.sec5")) // jichi 9/27/2014: For new Ryokucha games - InsertScenarioPlayerHook(); - return true; - } - - return false; -} - -bool DetermineEngineOther() -{ - if (InsertAliceHook()) - return true; - // jichi 1/19/2015: Disable inserting Lstr for System40 - // See: http://sakuradite.com/topic/618 - if (Util::CheckFile(L"System40.ini")) { - ConsoleOutput("vnreng: IGNORE old System40.ini"); - return true; - } - // jichi 12/26/2013: Add this after alicehook - if (Util::CheckFile(L"AliceStart.ini")) { - InsertSystem43Hook(); - return true; - } - - // Artikash 7/16/2018: Uses node/libuv: likely v8 - sample game https://vndb.org/v22975 - //if (GetProcAddress(GetModuleHandleW(nullptr), "uv_uptime") || GetModuleHandleW(L"node.dll")) - //{ - // InsertV8Hook(); - // return true; - //} - - // jichi 8/24/2013: Move into functions - // Artikash 6/15/2018: Removed this detection for Abel Software games. IthGetFileInfo no longer works correctly - //static BYTE static_file_info[0x1000]; - //if (IthGetFileInfo(L"*01", static_file_info)) - // if (*(DWORD*)static_file_info == 0) { - // STATUS_INFO_LENGTH_MISMATCH; - // static WCHAR static_search_name[MAX_PATH]; - // LPWSTR name=(LPWSTR)(static_file_info+0x5E); - // int len = wcslen(name); - // name[len-2] = L'.'; - // name[len-1] = L'e'; - // name[len] = L'x'; - // name[len+1] = L'e'; - // name[len+2] = 0; - // if (Util::CheckFile(name)) { - // sizeof(FILE_BOTH_DIR_INFORMATION); - // name[len-2] = L'*'; - // name[len-1] = 0; - // wcscpy(static_search_name,name); - // IthGetFileInfo(static_search_name,static_file_info); - // union { - // FILE_BOTH_DIR_INFORMATION *both_info; - // DWORD addr; - // }; - // both_info = (FILE_BOTH_DIR_INFORMATION *)static_file_info; - // //BYTE* ptr=static_file_info; - // len=0; - // while (both_info->NextEntryOffset) { - // addr += both_info->NextEntryOffset; - // len++; - // } - // if (len > 3) { - // InsertAbelHook(); - // return true; - // } - // } - // } - - return false; -} - -// jichi 8/17/2014 -// Put the patterns that might break other games at last -bool DetermineEngineAtLast() -{ - if (Util::CheckFile(L"MovieTexture.dll") && (InsertPensilHook() || Insert2RMHook())) // MovieTexture.dll also exists in 2RM games such as 母子愛2体験版, which is checked first - return true; - if ((Util::CheckFile(L"system") && Util::CheckFile(L"system.dat")) || Util::CheckFile(L"*01")) { // jichi 7/31/2015 & Artikash 6/15/2018 - InsertAbelHook(); - return true; - } - if (Util::CheckFile(L"data\\*.cpk")) { // jichi 12/2/2014 - Insert5pbHook(); - return true; - } - // jichi 7/6/2014: named as ScenarioPlayer since resource string could be: scenario player program for xxx - // Do this at last as it is common - if (Util::CheckFile(L"*.iar") && Util::CheckFile(L"*.sec5")) { // jichi 4/18/2014: Other game engine could also have *.iar such as Ryokucha - InsertScenarioPlayerHook(); - return true; - } - //if (Util::CheckFile(L"arc0.dat") && Util::CheckFile(L"script.dat") // jichi 11/14/2014: too common - if (Util::SearchResourceString(L"HorkEye")) { // appear in copyright: Copyright (C) HorkEye, http://horkeye.com - InsertHorkEyeHook(); - return true; - } - if (Util::CheckFile(L"comnArc.arc") // jichi 8/17/2014: this file might exist in multiple files - && InsertNexton1Hook()) // old nexton game - return true; - if (Util::CheckFile(L"arc.dat") // jichi 9/27/2014: too common - && InsertApricoTHook()) - return true; - if (Util::CheckFile(L"*.pak") // jichi 12/25/2014: too common - && InsertLeafHook()) - return true; - if (Util::CheckFile(L"*.dat") // mireado 08/22/2016: too common - && InsertNekopackHook()) - return true; - // jichi 10/31/2014 - // File description: Adobe Flash Player 10.2r153 - // Product name: Shockwave Flash - // Original filename: SAFlashPlayer.exe - // Legal trademarks: Adobe Flash Player - // No idea why, this must appear at last or it will crash - if (Util::SearchResourceString(L"Adobe Flash Player 10")) { - InsertAdobeFlash10Hook(); // only v10 might be supported. Otherwise, fallback to Lstr hooks - return true; - } - if (Util::CheckFile(L"dat\\*.arc")) { // jichi 2/6/2015 - InsertFocasLensHook(); // Touhou - return true; - } - - // jichi 8/23/2015: Tamamo - if (Util::CheckFile(L"data.pck") && Util::CheckFile(L"image.pck") && Util::CheckFile(L"script.pck")) { - //if (Util::CheckFile(L"QtGui.dll")) - InsertTamamoHook(); - return true; - } - - return false; -} - -// jichi 6/1/2014 -// Artikash 9/3/2018 Hook wchar by default -//bool DetermineEngineGeneric() -//{ -// bool ret = false; -// -// //if (Util::CheckFile(L"AlterEgo.exe")) { -// // ConsoleOutput("vnreng: AlterEgo, INSERT WideChar hooks"); -// // ret = true; -// //} else if (Util::CheckFile(L"data\\Sky\\*")) { -// // ConsoleOutput("vnreng: TEATIME, INSERT WideChar hooks"); -// // ret = true; -// //} -// ////} else if (Util::CheckFile(L"image\\*.po2") || Util::CheckFile(L"image\\*.jo2")) { -// //// ConsoleOutput("vnreng: HarukaKanata, INSERT WideChar hooks"); // はるかかなた -// //// ret = true; -// ////} -// //if (ret) -// // PcHooks::hookWcharFunctions(); -// PcHooks::hookWcharFunctions(); -// return ret; -//} - -bool DetermineNoEngine() -{ - //if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO) - // ConsoleOutput("vnreng: IGNORE Unity"); - // return true; - //} - //if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) { - // ConsoleOutput("vnreng: IGNORE Unity"); - // return true; - //} - - // jichi 6/7/2015: RPGMaker v3 - if (Util::CheckFile(L"*.rgss3a")) { - ConsoleOutput("vnreng: IGNORE RPGMaker RGSS3"); - return true; - } - - // jichi 11/22/2015: 凍京NECRO 体験版 - if (Util::CheckFile(L"*.npk")) { - ConsoleOutput("vnreng: IGNORE new Nitroplus"); - return true; - } - - // 8/29/2015 jichi: minori, text in GetGlyphOutlineA - if (Util::CheckFile(L"*.paz")) { - ConsoleOutput("vnreng: IGNORE minori"); - return true; - } - - // 7/28/2015 jichi: Favorite games - if (Util::CheckFile(L"*.hcb")) { - ConsoleOutput("vnreng: IGNORE FVP"); - return true; - } - - // jichi 2/14/2015: Guilty+ RIN×SEN (PK) - if (/*Util::CheckFile(L"rio.ini") || */Util::CheckFile(L"*.war")) { - ConsoleOutput("vnreng: IGNORE unknown ShinaRio"); - return true; - } - - if (Util::CheckFile(L"AdvHD.exe") || Util::CheckFile(L"AdvHD.dll")) { - ConsoleOutput("vnreng: IGNORE Adv Player HD"); // supposed to be WillPlus - return true; - } - - if (Util::CheckFile(L"ScrPlayer.exe")) { - ConsoleOutput("vnreng: IGNORE ScrPlayer"); - return true; - } - - if (Util::CheckFile(L"nnnConfig2.exe")) { - ConsoleOutput("vnreng: IGNORE Nya NNNConfig"); - return true; - } - - // jichi 4/30/2015: Skip games made from らすこう, such as とある人妻のネトラレ事情 - // It has garbage from lstrlenW. Correct text is supposed to be in TabbedTextOutA. - if (Util::CheckFile(L"data_cg.dpm")) { - ConsoleOutput("vnreng: IGNORE DPM data_cg.dpm"); - return true; - } - - //if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE - // ConsoleOutput("vnreng: IGNORE Eushully"); - // return true; - //} - - if (Util::CheckFile(L"game_sys.exe")) { - ConsoleOutput("vnreng: IGNORE Atelier Kaguya BY/TH"); - return true; - } - - if (Util::CheckFile(L"*.bsa")) { - ConsoleOutput("vnreng: IGNORE Bishop"); - return true; - } - - // jichi 3/19/2014: Escude game - // Example: bgm.bin gfx.bin maou.bin script.bin snd.bin voc.bin - if (Util::CheckFile(L"gfx.bin") && Util::CheckFile(L"snd.bin") && Util::CheckFile(L"voc.bin")) { - ConsoleOutput("vnreng: IGNORE Escude"); - return true; - } - - // jichi 2/18/2015: Ignore if there is Nitro+ copyright - if (Util::SearchResourceString(L"Nitro+")) { - ConsoleOutput("vnreng: IGNORE unknown Nitro+"); - return true; - } - - // jichi 12/28/2014: "Chartreux Inc." in Copyright. - // Sublimary brands include Rosebleu, MORE, etc. - // GetGlyphOutlineA already works. - if (Util::SearchResourceString(L"Chartreux")) { - ConsoleOutput("vnreng: IGNORE Chartreux"); - return true; - } - - if (Util::CheckFile(L"MovieTexture.dll")) { - ConsoleOutput("vnreng: IGNORE MovieTexture"); - return true; - } - - if (wcsstr(processName, L"lcsebody") || !wcsncmp(processName, L"lcsebo~", 7) || Util::CheckFile(L"lcsebody*")) { // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA - ConsoleOutput("vnreng: IGNORE lcsebody"); - return true; - } - - wchar_t str[MAX_PATH]; - DWORD i; - for (i = 0; processName[i]; i++) { - str[i] = processName[i]; - if (processName[i] == L'.') - break; - } - *(DWORD *)(str + i + 1) = 0x630068; //.hcb - *(DWORD *)(str + i + 3) = 0x62; - if (Util::CheckFile(str)) { - ConsoleOutput("vnreng: IGNORE FVP"); // jichi 10/3/2013: such like アトリエかぐや - return true; - } - return false; -} - -// jichi 9/14/2013: Certain ITH functions like FindEntryAligned might raise exception without admin priv -// Return if succeeded. -bool UnsafeDetermineEngineType() -{ - return DeterminePCEngine() - || DetermineEngineByFile1() - || DetermineEngineByFile2() - || DetermineEngineByFile3() - || DetermineEngineByFile4() - || DetermineEngineByProcessName() - || DetermineEngineOther() - || DetermineEngineAtLast() - || DetermineNoEngine() - ; -} - -// jichi 10/21/2014: Return whether found the game engine -bool DetermineEngineType() -{ - // jichi 9/27/2013: disable game engine for debugging use - bool found = false; -#ifndef ITH_DISABLE_ENGINE - __try { found = UnsafeDetermineEngineType(); } - __except (EXCEPTION_EXECUTE_HANDLER) { ConsoleOutput(HIJACK_ERROR); } -#endif // ITH_DISABLE_ENGINE - if (!found) { // jichi 10/2/2013: Only enable it if no game engine is detected - PcHooks::hookOtherPcFunctions(); - } //else - // ConsoleOutput("vnreng: found game engine, IGNORE non gui hooks"); - return found; -} - -} // unnamed - -DWORD InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack) -{ - return trigger_fun_ ? !trigger_fun_(addr, frame, stack) : 0; -} - -void Hijack() -{ - static bool hijacked = false; - if (hijacked) return; - GetModuleFileNameW(nullptr, processPath, MAX_PATH); - processName = wcsrchr(processPath, L'\\') + 1; - - ::processStartAddress = ::processStopAddress = (DWORD)GetModuleHandleW(nullptr); - MEMORY_BASIC_INFORMATION info; - do + // jichi 10/21/2014: Return whether found the game engine + bool DetermineEngineType() { - VirtualQuery((void*)::processStopAddress, &info, sizeof(info)); - ::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize; - } while (info.Protect > PAGE_NOACCESS); - processStopAddress -= info.RegionSize; + // jichi 9/27/2013: disable game engine for debugging use + bool found = false; +#ifndef ITH_DISABLE_ENGINE + __try { found = UnsafeDetermineEngineType(); } + __except (EXCEPTION_EXECUTE_HANDLER) { ConsoleOutput(HIJACK_ERROR); } +#endif // ITH_DISABLE_ENGINE + if (!found) { // jichi 10/2/2013: Only enable it if no game engine is detected + PcHooks::hookOtherPcFunctions(); + } //else + // ConsoleOutput("vnreng: found game engine, IGNORE non gui hooks"); + return found; + } - DetermineEngineType(); - hijacked = true; + DWORD InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack) + { + return trigger_fun ? !trigger_fun(addr, frame, stack) : 0; + } + + void Hijack() + { + static bool hijacked = false; + if (hijacked) return; + GetModuleFileNameW(nullptr, processPath, MAX_PATH); + processName = wcsrchr(processPath, L'\\') + 1; + + processStartAddress = processStopAddress = (uintptr_t)GetModuleHandleW(nullptr); + MEMORY_BASIC_INFORMATION info; + do + { + VirtualQuery((void*)processStopAddress, &info, sizeof(info)); + processStopAddress = (uintptr_t)info.BaseAddress + info.RegionSize; + } while (info.Protect > PAGE_NOACCESS); + processStopAddress -= info.RegionSize; + + DetermineEngineType(); + hijacked = true; + ConsoleOutput("Textractor: finished hijacking %S located from 0x%p to 0x%p", processName, processStartAddress, processStopAddress); + } } - -} // namespace Engine - -// - API - - -// EOF diff --git a/texthook/engine/match32.cc b/texthook/engine/match32.cc new file mode 100644 index 0000000..0c5b465 --- /dev/null +++ b/texthook/engine/match32.cc @@ -0,0 +1,824 @@ +// match.cc +// 8/9/2013 jichi +// Branch: ITH_Engine/engine.cpp, revision 133 + +#include "engine/match.h" +#include "engine/engine.h" +#include "engine/native/pchooks.h" +#include "util/util.h" +#include "main.h" +#include "ithsys/ithsys.h" + +//#define ConsoleOutput(...) (void)0 // jichi 8/18/2013: I don't need ConsoleOutput + +enum { MAX_REL_ADDR = 0x200000 }; // jichi 8/18/2013: maximum relative address + +// - Methods - + +namespace Engine { namespace { // unnamed + +bool DetermineGameHooks() // 7/19/2015 +{ +#if 0 // jichi 7/19/2015: Disabled as it will crash the game + if (Util::CheckFile(L"UE3ShaderCompileWorker.exe") && Util::CheckFile(L"awesomium_process.exe")) { + InsertLovaGameHook(); + return true; + } +#endif // 0 + return false; +} + +// jichi 7/17/2014: Disable GDI hooks for PPSSPP +bool DeterminePCEngine() +{ + if (DetermineGameHooks()) { + ConsoleOutput("vnreng: found game-specific hook"); + return true; + } + + if (Util::CheckFile(L"PPSSPP*.exe")) { // jichi 7/12/2014 PPSSPPWindows.exe, PPSSPPEX.exe PPSSPPSP.exe + //InsertPPSSPPHooks(); // Artikash 8/4/2018: removed for now as doesn't work for non ancient ppsspp versions + return true; + } + + if (Util::CheckFile(L"pcsx2*.exe")) { // jichi 7/19/2014 PCSX2.exe or PCSX2WX.exe + InsertPCSX2Hooks(); + return true; + } + + if (Util::CheckFile(L"Dolphin.exe")) { // jichi 7/20/2014 + InsertGCHooks(); + return true; + } + + // jichi 5/14/2015: Skip hijacking BALDRSKY ZEROs + //if (Util::CheckFile(L"bsz_Data\\Mono\\mono.dll") || Util::CheckFile(L"bsz2_Data\\Mono\\mono.dll")) { + // ConsoleOutput("vnreng: IGNORE BALDRSKY ZEROs"); + // return true; + //} + + for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" }) + if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); + else for (int i = 0; i < 50; ++i) + if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); + + if (GetProcAddress((HMODULE)processStartAddress, "?Write@String@v8@@QBEHPAGHHH@Z")) + InsertV8Hook((HMODULE)processStartAddress); + if (HMODULE module = GetModuleHandleW(L"node.dll")) + InsertV8Hook(module); + if (HMODULE module = GetModuleHandleW(L"nw.dll")) + InsertV8Hook(module); + + if (InsertMonoHooks()) { + return true; + } + + // PC games + PcHooks::hookGDIFunctions(); + PcHooks::hookGDIPlusFunctions(); + const char check[] = "sdffffffkjldfjlhjweiumxnvq1204tergdmnxcq1111111111111111111111408t03kxjb40"; + Util::SearchMemory((const BYTE*)check, sizeof(check)); // Not too sure about the stability of this guy, so test it here + return false; +} + +bool DetermineEngineByFile1() +{ + // Artikash 7/14/2018: AIRNovel - sample game https://vndb.org/v18814 + if (Util::CheckFile(L"*.swf")) + { + //InsertAdobeAirHook(); + InsertAIRNovelHook(); + return true; + } + + // Artikash 8/9/2018: Renpy - sample game https://vndb.org/v19843 + if (Util::CheckFile(L"*.py")) + { + InsertRenpyHook(); + return true; + } + + if (Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)")) { + if (Util::SearchResourceString(L"TVP(KIRIKIRI) Z ")) { // TVP(KIRIKIRI) Z CORE + // jichi 11/24/2014: Disabled that might crash VBH + //if (Util::CheckFile(L"plugin\\KAGParser.dll")) + // InsertKAGParserHook(); + //else if (Util::CheckFile(L"plugin\\KAGParserEx.dll")) + // InsertKAGParserExHook(); + if (InsertKiriKiriZHook()) + return true; + } + InsertKiriKiriHook(); + return true; + } + // 8/2/2014 jichi: Game name shown as 2RM - Adventure Engine, text also in GetGlyphOutlineA + if (Util::SearchResourceString(L"2RM") && Util::SearchResourceString(L"Adventure Engine")) { + Insert2RMHook(); + return true; + } + // 8/2/2014 jichi: Copyright is side-B, a conf.dat will be generated after the game is launched + // It also contains lua5.1.dll and lua5.dll + if (Util::SearchResourceString(L"side-B")) { + InsertSideBHook(); + return true; + } + if (Util::CheckFile(L"bgi.*") || Util::CheckFile(L"sysgrp.arc")) { + InsertBGIHook(); + return true; + } + if (Util::CheckFile(L"Bootup.dat") && InsertBootupHook()) // 5/22/2015 Bootup + // lstrlenW can also find text with repetition though + return true; + if (Util::CheckFile(L"AGERC.DLL")) { // 6/1/2014 jichi: Eushully, AGE.EXE + InsertEushullyHook(); + return true; + } + if (Util::CheckFile(L"data*.arc") && Util::CheckFile(L"stream*.arc")) { + InsertMajiroHook(); + return true; + } + // jichi 5/31/2014 + if (//Util::CheckFile(L"Silkys.exe") || // It might or might not have Silkys.exe + // data, effect, layer, mes, music + Util::CheckFile(L"data.arc") && Util::CheckFile(L"effect.arc") && Util::CheckFile(L"mes.arc")) { + InsertElfHook(); + return true; + } + // jichi 6/9/2015: Skip Silkys Sakura + if ( // Almost the same as Silkys except mes.arc is replaced by Script.arc + Util::CheckFile(L"data.arc") && Util::CheckFile(L"effect.arc") && Util::CheckFile(L"Script.arc")) { + InsertSilkysHook(); + return true; + } + if (Util::CheckFile(L"data\\pack\\*.cpz")) { + InsertCMVSHook(); + return true; + } + // jichi 10/12/2013: Restore wolf engine + // jichi 10/18/2013: Check for data/*.wolf + if (Util::CheckFile(L"data.wolf") || Util::CheckFile(L"data\\*.wolf") || Util::CheckFile(L"data\\basicdata\\cdatabase.dat")) { + InsertWolfHook(); + return true; + } + if (Util::CheckFile(L"AdvData\\DAT\\NAMES.DAT")) { + InsertCircusHook1(); + return true; + } + if (Util::CheckFile(L"AdvData\\GRP\\NAMES.DAT")) { + InsertCircusHook2(); + return true; + } + if (Util::CheckFile(L"*.noa") || Util::CheckFile(L"data\\*.noa")) { + InsertCotophaHook(); + return true; + } + if (Util::CheckFile(L"*.pfs")) { // jichi 10/1/2013 + InsertArtemisHook(); + return true; + } + if (Util::CheckFile(L"*.int")) { + InsertCatSystemHook(); + return true; + } + if (Util::CheckFile(L"message.dat")) { + InsertAtelierHook(); + return true; + } + if (Util::CheckFile(L"Check.mdx")) { // jichi 4/1/2014: AUGame + InsertTencoHook(); + return true; + } + // jichi 12/25/2013: It may or may not be QLIE. + // AlterEgo also has GameData/sound.pack but is not QLIE + if (Util::CheckFile(L"GameData\\*.pack") && InsertQLIEHook()) + return true; + + if (Util::CheckFile(L"dll\\Pal.dll")) { + InsertPalHook(); + return true; + } + + if (Util::CheckFile(L"*.pac")) { + // jichi 6/3/2014: AMUSE CRAFT and SOFTPAL + // Selectively insert, so that lstrlenA can still get correct text if failed + //if (Util::CheckFile(L"dll\\resource.dll") && Util::CheckFile(L"dll\\pal.dll") && InsertAmuseCraftHook()) + // return true; + + if (Util::CheckFile(L"Thumbnail.pac")) { + //ConsoleOutput("vnreng: IGNORE NeXAS"); + InsertNeXASHook(); // jichi 7/6/2014: GIGA + return true; + } + + if (Util::SearchResourceString(L"SOFTPAL")) { + ConsoleOutput("vnreng: IGNORE SoftPal UNiSONSHIFT"); + return true; + } + } + // jichi 12/27/2014: LunaSoft + if (Util::CheckFile(L"Pac\\*.pac")) { + InsertLunaSoftHook(); + return true; + } + // jichi 9/16/2013: Add Gesen18 + if (Util::CheckFile(L"*.szs") || Util::CheckFile(L"Data\\*.szs")) { + InsertUnicornHook(); + return true; + } + // jichi 12/22/2013: Add rejet + if (Util::CheckFile(L"gd.dat") && Util::CheckFile(L"pf.dat") && Util::CheckFile(L"sd.dat")) { + InsertRejetHook(); + return true; + } + // Only examined with version 1.0 + //if (Util::CheckFile(L"Adobe AIR\\Versions\\*\\Adobe AIR.dll")) { // jichi 4/15/2014: FIXME: Wildcard not working + if (Util::CheckFile(L"Adobe AIR\\Versions\\1.0\\Adobe AIR.dll")) { // jichi 4/15/2014: Adobe AIR + InsertAdobeAirHook(); + return true; + } + return false; +} + +bool DetermineEngineByFile2() +{ + if (Util::CheckFile(L"resident.dll")) { + InsertRetouchHook(); + return true; + } + if (Util::CheckFile(L"Malie.ini") || Util::CheckFile(L"Malie.exe")) { // jichi: 9/9/2014: Add malie.exe in case malie.ini is missing + InsertMalieHook(); + return true; + } + if (Util::CheckFile(L"live.dll")) { + InsertLiveHook(); + return true; + } + // 9/5/2013 jichi + if (Util::CheckFile(L"aInfo.db")) { + InsertNextonHook(); + return true; + } + if (Util::CheckFile(L"*.lpk")) { + InsertLucifenHook(); + return true; + } + if (Util::CheckFile(L"cfg.pak")) { + InsertWaffleHook(); + return true; + } + if (Util::CheckFile(L"Arc00.dat")) { + InsertTinkerBellHook(); + return true; + } + if (Util::CheckFile(L"*.vfs")) { // jichi 7/6/2014: Better to test AoiLib.dll? ja.wikipedia.org/wiki/ソフトハウスキャラ + InsertSystemAoiHook(); + return true; + } + if (Util::CheckFile(L"*.mbl")) { + InsertMBLHook(); + return true; + } + // jichi 8/1/2014: YU-RIS engine, lots of clockup game also has this pattern + if (Util::CheckFile(L"pac\\*.ypf") || Util::CheckFile(L"*.ypf")) { + // jichi 8/14/2013: CLOCLUP: "ノーブレスオブリージュ" would crash the game. + if (!Util::CheckFile(L"noblesse.exe")) + InsertYurisHook(); + return true; + } + if (Util::CheckFile(L"*.npa")) { + InsertNitroplusHook(); + return true; + } + return false; +} + +bool DetermineEngineByFile3() +{ + //if (Util::CheckFile(L"libscr.dll")) { // already checked + // InsertBrunsHook(); + // return true; + //} + + // jichi 10/12/2013: Sample args.txt: + // See: http://tieba.baidu.com/p/2631413816 + // -workdir + // . + // -loadpath + // . + // am.cfg + if (Util::CheckFile(L"args.txt")) { + InsertBrunsHook(); + return true; + } + if (Util::CheckFile(L"emecfg.ecf")) { + InsertEMEHook(); + return true; + } + if (Util::CheckFile(L"rrecfg.rcf")) { + InsertRREHook(); + return true; + } + if (Util::CheckFile(L"*.fpk") || Util::CheckFile(L"data\\*.fpk")) { + InsertCandyHook(); + return true; + } + if (Util::CheckFile(L"arc.a*")) { + InsertApricoTHook(); + return true; + } + if (Util::CheckFile(L"*.mpk")) { + InsertStuffScriptHook(); + return true; + } + if (Util::CheckFile(L"USRDIR\\*.mpk")) { // jichi 12/2/2014 + InsertStuffScriptHook(); + return true; + } + if (Util::CheckFile(L"Execle.exe")) { + InsertTriangleHook(); + return true; + } + // jichi 2/28/2015: No longer work for "大正×対称アリス episode I" from Primula + //if (Util::CheckFile(L"PSetup.exe")) { + // InsertPensilHook(); + // return true; + //} + if (Util::CheckFile(L"Yanesdk.dll")) { + InsertAB2TryHook(); + return true; + } + if (Util::CheckFile(L"*.med")) { + InsertMEDHook(); + return true; + } + return false; +} + +bool DetermineEngineByFile4() +{ + if (Util::CheckFile(L"EAGLS.dll")) { // jichi 3/24/2014: E.A.G.L.S + //ConsoleOutput("vnreng: IGNORE EAGLS"); + InsertEaglsHook(); + return true; + } + if (Util::CheckFile(L"bmp.pak") && Util::CheckFile(L"dsetup.dll")) { + // 1/1/2016 jich: skip izumo4 from studio ego that is not supported by debonosu + if (Util::CheckFile(L"*izumo4*.exe")) { + PcHooks::hookOtherPcFunctions(); + return true; + } + InsertDebonosuHook(); + return true; + } + if (Util::CheckFile(L"C4.EXE") || Util::CheckFile(L"XEX.EXE")) { + InsertC4Hook(); + return true; + } + if (Util::CheckFile(L"Rio.arc") && Util::CheckFile(L"Chip*.arc")) { + InsertWillPlusHook(); + return true; + } + if (Util::CheckFile(L"*.tac")) { + InsertTanukiHook(); + return true; + } + if (Util::CheckFile(L"*.gxp")) { + InsertGXPHook(); + return true; + } + if (Util::CheckFile(L"*.aos")) { // jichi 4/2/2014: AOS hook + InsertAOSHook(); + return true; + } + if (Util::CheckFile(L"*.at2")) { // jichi 12/23/2014: Mink, sample files: voice.at2, voice.det, voice.nme + InsertMinkHook(); + return true; + } + if (Util::CheckFile(L"*.ykc")) { // jichi 7/15/2014: YukaSystem1 is not supported, though + //ConsoleOutput("vnreng: IGNORE YKC:Feng/HookSoft(SMEE)"); + InsertYukaSystem2Hook(); + return true; + } + if (Util::CheckFile(L"model\\*.hed")) { // jichi 9/8/2014: EXP + InsertExpHook(); + return true; + } + // jichi 2/6/2015 平安亭 + // dPi.dat, dPih.dat, dSc.dat, dSch.dat, dSo.dat, dSoh.dat, dSy.dat + //if (Util::CheckFile(L"dSoh.dat")) { // no idea why this file does not work + if (Util::CheckFile(L"dSch.dat")) { + InsertSyuntadaHook(); + return true; + } + + // jichi 2/28/2015: Delay checking Pensil in case something went wrong + // File pattern observed in [Primula] 大正×対称アリス episode I + // - PSetup.exe no longer exists + // - MovieTexture.dll information shows MovieTex dynamic library, copyright Pensil 2013 + // - ta_trial.exe information shows 2XT - Primula Adventure Engine + if (Util::CheckFile(L"PSetup.exe") || Util::CheckFile(L"PENCIL.*") || Util::SearchResourceString(L"2XT -")) { + InsertPensilHook(); + return true; + } + + return false; +} + +bool DetermineEngineByProcessName() +{ + WCHAR str[MAX_PATH]; + wcscpy_s(str, processName); + _wcslwr_s(str); // lower case + + if (wcsstr(str,L"reallive") || Util::CheckFile(L"Reallive.exe") || Util::CheckFile(L"REALLIVEDATA\\Start.ini")) { + InsertRealliveHook(); + return true; + } + + // jichi 8/19/2013: DO NOT WORK for games like「ハピメア」 + //if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) { + // InsertCMVSHook(); + // return true; + //} + + // jichi 8/17/2013: Handle "~" + if (wcsstr(str, L"siglusengine") || !wcsncmp(str, L"siglus~", 7) || Util::CheckFile(L"SiglusEngine.exe")) { + InsertSiglusHook(); + return true; + } + + if (wcsstr(str, L"taskforce2") || !wcsncmp(str, L"taskfo~", 7) || Util::CheckFile(L"Taskforce2.exe")) { + InsertTaskforce2Hook(); + return true; + } + + if (wcsstr(str,L"rugp") || Util::CheckFile(L"rugp.exe")) { + InsertRUGPHook(); + return true; + } + + // jichi 8/17/2013: Handle "~" + if (wcsstr(str, L"igs_sample") || !wcsncmp(str, L"igs_sa~", 7) || Util::CheckFile(L"igs_sample.exe")) { + InsertIronGameSystemHook(); + return true; + } + + if (wcsstr(str, L"bruns") || Util::CheckFile(L"bruns.exe")) { + InsertBrunsHook(); + return true; + } + + if (wcsstr(str, L"anex86") || Util::CheckFile(L"anex86.exe")) { + InsertAnex86Hook(); + return true; + } + + // jichi 8/17/2013: Handle "~" + if (wcsstr(str, L"shinydays") || !wcsncmp(str, L"shinyd~", 7) || Util::CheckFile(L"ShinyDays.exe")) { + InsertShinyDaysGameHook(); + return true; + } + + if (wcsstr(processName, L"SAISYS") || Util::CheckFile(L"SaiSys.exe")) { // jichi 4/19/2014: Marine Heart + InsertMarineHeartHook(); + return true; + } + + DWORD len = wcslen(str); + + // jichi 8/24/2013: Checking for Rio.ini or $procname.ini + //wcscpy(str+len-4, L"_?.war"); + //if (Util::CheckFile(str)) { + // InsertShinaHook(); + // return true; + //} + if (Util::CheckFile(L"*.ini")) { + if (InsertShinaHook()) + return true; + } + + // jichi 8/10/2013: Since *.bin is common, move CaramelBox to the end + str[len - 3] = L'b'; + str[len - 2] = L'i'; + str[len - 1] = L'n'; + str[len] = 0; + if ((Util::CheckFile(str) || Util::CheckFile(L"trial.bin")) // jichi 7/8/2014: add trial.bin + && InsertCaramelBoxHook()) + return true; + + // jichi 7/23/2015 It also has gameexe.bin existed + if (Util::CheckFile(L"configure.cfg") && Util::CheckFile(L"gfx.bin")) { + InsertEscudeHook(); + return true; + } + + // This must appear at last since str is modified + //wcscpy(str + len - 4, L"_checksum.exe"); + if (Util::CheckFile(L"*_checksum.exe")) { + InsertRyokuchaHook(); + + if (Util::CheckFile(L"*.iar") && Util::CheckFile(L"*.sec5")) // jichi 9/27/2014: For new Ryokucha games + InsertScenarioPlayerHook(); + return true; + } + + return false; +} + +bool DetermineEngineOther() +{ + if (InsertAliceHook()) + return true; + // jichi 1/19/2015: Disable inserting Lstr for System40 + // See: http://sakuradite.com/topic/618 + if (Util::CheckFile(L"System40.ini")) { + ConsoleOutput("vnreng: IGNORE old System40.ini"); + return true; + } + // jichi 12/26/2013: Add this after alicehook + if (Util::CheckFile(L"AliceStart.ini")) { + InsertSystem43Hook(); + return true; + } + + // Artikash 7/16/2018: Uses node/libuv: likely v8 - sample game https://vndb.org/v22975 + //if (GetProcAddress(GetModuleHandleW(nullptr), "uv_uptime") || GetModuleHandleW(L"node.dll")) + //{ + // InsertV8Hook(); + // return true; + //} + + // jichi 8/24/2013: Move into functions + // Artikash 6/15/2018: Removed this detection for Abel Software games. IthGetFileInfo no longer works correctly + //static BYTE static_file_info[0x1000]; + //if (IthGetFileInfo(L"*01", static_file_info)) + // if (*(DWORD*)static_file_info == 0) { + // STATUS_INFO_LENGTH_MISMATCH; + // static WCHAR static_search_name[MAX_PATH]; + // LPWSTR name=(LPWSTR)(static_file_info+0x5E); + // int len = wcslen(name); + // name[len-2] = L'.'; + // name[len-1] = L'e'; + // name[len] = L'x'; + // name[len+1] = L'e'; + // name[len+2] = 0; + // if (Util::CheckFile(name)) { + // sizeof(FILE_BOTH_DIR_INFORMATION); + // name[len-2] = L'*'; + // name[len-1] = 0; + // wcscpy(static_search_name,name); + // IthGetFileInfo(static_search_name,static_file_info); + // union { + // FILE_BOTH_DIR_INFORMATION *both_info; + // DWORD addr; + // }; + // both_info = (FILE_BOTH_DIR_INFORMATION *)static_file_info; + // //BYTE* ptr=static_file_info; + // len=0; + // while (both_info->NextEntryOffset) { + // addr += both_info->NextEntryOffset; + // len++; + // } + // if (len > 3) { + // InsertAbelHook(); + // return true; + // } + // } + // } + + return false; +} + +// jichi 8/17/2014 +// Put the patterns that might break other games at last +bool DetermineEngineAtLast() +{ + if (Util::CheckFile(L"MovieTexture.dll") && (InsertPensilHook() || Insert2RMHook())) // MovieTexture.dll also exists in 2RM games such as 母子愛2体験版, which is checked first + return true; + if ((Util::CheckFile(L"system") && Util::CheckFile(L"system.dat")) || Util::CheckFile(L"*01")) { // jichi 7/31/2015 & Artikash 6/15/2018 + InsertAbelHook(); + return true; + } + if (Util::CheckFile(L"data\\*.cpk")) { // jichi 12/2/2014 + Insert5pbHook(); + return true; + } + // jichi 7/6/2014: named as ScenarioPlayer since resource string could be: scenario player program for xxx + // Do this at last as it is common + if (Util::CheckFile(L"*.iar") && Util::CheckFile(L"*.sec5")) { // jichi 4/18/2014: Other game engine could also have *.iar such as Ryokucha + InsertScenarioPlayerHook(); + return true; + } + //if (Util::CheckFile(L"arc0.dat") && Util::CheckFile(L"script.dat") // jichi 11/14/2014: too common + if (Util::SearchResourceString(L"HorkEye")) { // appear in copyright: Copyright (C) HorkEye, http://horkeye.com + InsertHorkEyeHook(); + return true; + } + if (Util::CheckFile(L"comnArc.arc") // jichi 8/17/2014: this file might exist in multiple files + && InsertNexton1Hook()) // old nexton game + return true; + if (Util::CheckFile(L"arc.dat") // jichi 9/27/2014: too common + && InsertApricoTHook()) + return true; + if (Util::CheckFile(L"*.pak") // jichi 12/25/2014: too common + && InsertLeafHook()) + return true; + if (Util::CheckFile(L"*.dat") // mireado 08/22/2016: too common + && InsertNekopackHook()) + return true; + // jichi 10/31/2014 + // File description: Adobe Flash Player 10.2r153 + // Product name: Shockwave Flash + // Original filename: SAFlashPlayer.exe + // Legal trademarks: Adobe Flash Player + // No idea why, this must appear at last or it will crash + if (Util::SearchResourceString(L"Adobe Flash Player 10")) { + InsertAdobeFlash10Hook(); // only v10 might be supported. Otherwise, fallback to Lstr hooks + return true; + } + if (Util::CheckFile(L"dat\\*.arc")) { // jichi 2/6/2015 + InsertFocasLensHook(); // Touhou + return true; + } + + // jichi 8/23/2015: Tamamo + if (Util::CheckFile(L"data.pck") && Util::CheckFile(L"image.pck") && Util::CheckFile(L"script.pck")) { + //if (Util::CheckFile(L"QtGui.dll")) + InsertTamamoHook(); + return true; + } + + return false; +} + +// jichi 6/1/2014 +// Artikash 9/3/2018 Hook wchar by default +//bool DetermineEngineGeneric() +//{ +// bool ret = false; +// +// //if (Util::CheckFile(L"AlterEgo.exe")) { +// // ConsoleOutput("vnreng: AlterEgo, INSERT WideChar hooks"); +// // ret = true; +// //} else if (Util::CheckFile(L"data\\Sky\\*")) { +// // ConsoleOutput("vnreng: TEATIME, INSERT WideChar hooks"); +// // ret = true; +// //} +// ////} else if (Util::CheckFile(L"image\\*.po2") || Util::CheckFile(L"image\\*.jo2")) { +// //// ConsoleOutput("vnreng: HarukaKanata, INSERT WideChar hooks"); // はるかかなた +// //// ret = true; +// ////} +// //if (ret) +// // PcHooks::hookWcharFunctions(); +// PcHooks::hookWcharFunctions(); +// return ret; +//} + +bool DetermineNoEngine() +{ + //if (Util::CheckFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO) + // ConsoleOutput("vnreng: IGNORE Unity"); + // return true; + //} + //if (Util::CheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || Util::CheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) { + // ConsoleOutput("vnreng: IGNORE Unity"); + // return true; + //} + + // jichi 6/7/2015: RPGMaker v3 + if (Util::CheckFile(L"*.rgss3a")) { + ConsoleOutput("vnreng: IGNORE RPGMaker RGSS3"); + return true; + } + + // jichi 11/22/2015: 凍京NECRO 体験版 + if (Util::CheckFile(L"*.npk")) { + ConsoleOutput("vnreng: IGNORE new Nitroplus"); + return true; + } + + // 8/29/2015 jichi: minori, text in GetGlyphOutlineA + if (Util::CheckFile(L"*.paz")) { + ConsoleOutput("vnreng: IGNORE minori"); + return true; + } + + // 7/28/2015 jichi: Favorite games + if (Util::CheckFile(L"*.hcb")) { + ConsoleOutput("vnreng: IGNORE FVP"); + return true; + } + + // jichi 2/14/2015: Guilty+ RIN×SEN (PK) + if (/*Util::CheckFile(L"rio.ini") || */Util::CheckFile(L"*.war")) { + ConsoleOutput("vnreng: IGNORE unknown ShinaRio"); + return true; + } + + if (Util::CheckFile(L"AdvHD.exe") || Util::CheckFile(L"AdvHD.dll")) { + ConsoleOutput("vnreng: IGNORE Adv Player HD"); // supposed to be WillPlus + return true; + } + + if (Util::CheckFile(L"ScrPlayer.exe")) { + ConsoleOutput("vnreng: IGNORE ScrPlayer"); + return true; + } + + if (Util::CheckFile(L"nnnConfig2.exe")) { + ConsoleOutput("vnreng: IGNORE Nya NNNConfig"); + return true; + } + + // jichi 4/30/2015: Skip games made from らすこう, such as とある人妻のネトラレ事情 + // It has garbage from lstrlenW. Correct text is supposed to be in TabbedTextOutA. + if (Util::CheckFile(L"data_cg.dpm")) { + ConsoleOutput("vnreng: IGNORE DPM data_cg.dpm"); + return true; + } + + //if (Util::CheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE + // ConsoleOutput("vnreng: IGNORE Eushully"); + // return true; + //} + + if (Util::CheckFile(L"game_sys.exe")) { + ConsoleOutput("vnreng: IGNORE Atelier Kaguya BY/TH"); + return true; + } + + if (Util::CheckFile(L"*.bsa")) { + ConsoleOutput("vnreng: IGNORE Bishop"); + return true; + } + + // jichi 3/19/2014: Escude game + // Example: bgm.bin gfx.bin maou.bin script.bin snd.bin voc.bin + if (Util::CheckFile(L"gfx.bin") && Util::CheckFile(L"snd.bin") && Util::CheckFile(L"voc.bin")) { + ConsoleOutput("vnreng: IGNORE Escude"); + return true; + } + + // jichi 2/18/2015: Ignore if there is Nitro+ copyright + if (Util::SearchResourceString(L"Nitro+")) { + ConsoleOutput("vnreng: IGNORE unknown Nitro+"); + return true; + } + + // jichi 12/28/2014: "Chartreux Inc." in Copyright. + // Sublimary brands include Rosebleu, MORE, etc. + // GetGlyphOutlineA already works. + if (Util::SearchResourceString(L"Chartreux")) { + ConsoleOutput("vnreng: IGNORE Chartreux"); + return true; + } + + if (Util::CheckFile(L"MovieTexture.dll")) { + ConsoleOutput("vnreng: IGNORE MovieTexture"); + return true; + } + + if (wcsstr(processName, L"lcsebody") || !wcsncmp(processName, L"lcsebo~", 7) || Util::CheckFile(L"lcsebody*")) { // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA + ConsoleOutput("vnreng: IGNORE lcsebody"); + return true; + } + + wchar_t str[MAX_PATH]; + DWORD i; + for (i = 0; processName[i]; i++) { + str[i] = processName[i]; + if (processName[i] == L'.') + break; + } + *(DWORD *)(str + i + 1) = 0x630068; //.hcb + *(DWORD *)(str + i + 3) = 0x62; + if (Util::CheckFile(str)) { + ConsoleOutput("vnreng: IGNORE FVP"); // jichi 10/3/2013: such like アトリエかぐや + return true; + } + return false; +} + +} // unnamed + +// jichi 9/14/2013: Certain ITH functions like FindEntryAligned might raise exception without admin priv +// Return if succeeded. +bool UnsafeDetermineEngineType() +{ + return DeterminePCEngine() + || DetermineEngineByFile1() + || DetermineEngineByFile2() + || DetermineEngineByFile3() + || DetermineEngineByFile4() + || DetermineEngineByProcessName() + || DetermineEngineOther() + || DetermineEngineAtLast() + || DetermineNoEngine() + ; +} + +} // namespace Engine + +// - API - + +// EOF diff --git a/texthook/engine/match64.cc b/texthook/engine/match64.cc index d5bbbe6..48a326c 100644 --- a/texthook/engine/match64.cc +++ b/texthook/engine/match64.cc @@ -2,30 +2,17 @@ #include "main.h" #include "native/pchooks.h" -extern const char* HIJACK_ERROR; - namespace Engine { - void HookDirectX() + bool UnsafeDetermineEngineType() { - for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" }) if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); else for (int i = 0; i < 50; ++i) if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); - } - void Hijack() - { - static bool hijacked = false; - if (hijacked) return; - hijacked = true; - __try - { - PcHooks::hookGDIFunctions(); - PcHooks::hookGDIPlusFunctions(); - PcHooks::hookOtherPcFunctions(); - HookDirectX(); - } - __except (EXCEPTION_EXECUTE_HANDLER) { ConsoleOutput(HIJACK_ERROR); } + + PcHooks::hookGDIFunctions(); + PcHooks::hookGDIPlusFunctions(); + return false; } } \ No newline at end of file