more user friendly hook searching and refactors

This commit is contained in:
Akash Mozumdar 2019-06-06 23:53:37 -04:00
parent b18fe3ddd0
commit b8bd602474
9 changed files with 923 additions and 929 deletions

View File

@ -33,6 +33,7 @@ extern const char* SEARCH_DURATION;
extern const char* PATTERN_OFFSET; extern const char* PATTERN_OFFSET;
extern const char* MIN_ADDRESS; extern const char* MIN_ADDRESS;
extern const char* MAX_ADDRESS; extern const char* MAX_ADDRESS;
extern const char* HOOK_SEARCH_FILTER;
extern const char* START_HOOK_SEARCH; extern const char* START_HOOK_SEARCH;
extern const char* SAVE_SEARCH_RESULTS; extern const char* SAVE_SEARCH_RESULTS;
extern const char* TEXT_FILES; extern const char* TEXT_FILES;
@ -336,11 +337,11 @@ void MainWindow::FindHooks()
void launch() void launch()
{ {
auto layout = new QFormLayout(this); 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); layout->addRow(SEARCH_PATTERN, patternInput);
for (auto[value, label] : Array<std::tuple<int&, const char*>>{ for (auto[value, label] : Array<std::tuple<int&, const char*>>{
{ sp.searchTime, SEARCH_DURATION }, { sp.searchTime = 20000, SEARCH_DURATION },
{ sp.offset, PATTERN_OFFSET }, { sp.offset = 2, PATTERN_OFFSET },
}) })
{ {
auto spinBox = new QSpinBox(this); auto spinBox = new QSpinBox(this);
@ -350,8 +351,8 @@ void MainWindow::FindHooks()
connect(spinBox, qOverload<int>(&QSpinBox::valueChanged), [=, &value] { value = spinBox->value(); }); connect(spinBox, qOverload<int>(&QSpinBox::valueChanged), [=, &value] { value = spinBox->value(); });
} }
for (auto[value, label] : Array<std::tuple<uintptr_t&, const char*>>{ for (auto[value, label] : Array<std::tuple<uintptr_t&, const char*>>{
{ sp.minAddress, MIN_ADDRESS }, { sp.minAddress = 0, MIN_ADDRESS },
{ sp.maxAddress, MAX_ADDRESS }, { sp.maxAddress = -1ULL, MAX_ADDRESS },
}) })
{ {
auto input = new QLineEdit(QString::number(value, 16), this); auto input = new QLineEdit(QString::number(value, 16), this);
@ -361,19 +362,23 @@ void MainWindow::FindHooks()
bool ok; bool ok;
if (uintptr_t newValue = input.toULongLong(&ok, 16); ok) value = newValue; 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); auto save = new QPushButton(START_HOOK_SEARCH, this);
layout->addWidget(save); layout->addWidget(save);
connect(save, &QPushButton::clicked, this, &QDialog::accept); 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; 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)); memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), 25));
auto hooks = std::make_shared<QString>(); auto hooks = std::make_shared<QString>();
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); QString fileName = QFileDialog::getSaveFileName(this, SAVE_SEARCH_RESULTS, "./Hooks.txt", TEXT_FILES);
if (fileName.isEmpty()) fileName = "Hooks.txt"; if (fileName.isEmpty()) fileName = "Hooks.txt";

View File

@ -62,9 +62,9 @@ struct SearchParam
{ {
BYTE pattern[25] = {}; // pattern in memory to search for BYTE pattern[25] = {}; // pattern in memory to search for
int length, // length of pattern int length, // length of pattern
offset = 0, // offset from start of pattern to add hook offset, // offset from start of pattern to add hook
searchTime = 30000; // ms searchTime; // ms
uintptr_t minAddress = 0, maxAddress = (uintptr_t)-1LL; uintptr_t minAddress, maxAddress;
}; };
struct InsertHookCmd // From host struct InsertHookCmd // From host

View File

@ -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* 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* EXTENSION_WRITE_ERROR = u8"Failed to save extension";
const char* USE_JP_LOCALE = u8"Emulate japanese locale?"; 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!"; 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)"; const char* SEARCH_PATTERN = u8"Search pattern (hex byte array)";
extern const char* SEARCH_DURATION = u8"Search duration (ms)"; const char* SEARCH_DURATION = u8"Search duration (ms)";
extern const char* PATTERN_OFFSET = u8"Offset from pattern start"; const char* PATTERN_OFFSET = u8"Offset from pattern start";
extern const char* MIN_ADDRESS = u8"Minimum address (hex)"; const char* MIN_ADDRESS = u8"Minimum address (hex)";
extern const char* MAX_ADDRESS = u8"Maximum address (hex)"; const char* MAX_ADDRESS = u8"Maximum address (hex)";
extern const char* START_HOOK_SEARCH = u8"Start hook search"; const char* HOOK_SEARCH_FILTER = u8"Results must match this regex";
extern const char* SAVE_SEARCH_RESULTS = u8"Save search results"; const char* START_HOOK_SEARCH = u8"Start hook search";
extern const char* TEXT_FILES = u8"Text (*.txt)"; 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* FILTER_REPETITION = u8"Repetition Filter";
const char* DEFAULT_CODEPAGE = u8"Default Codepage"; const char* DEFAULT_CODEPAGE = u8"Default Codepage";
const char* FLUSH_DELAY = u8"Flush Delay"; const char* FLUSH_DELAY = u8"Flush Delay";

View File

@ -5,6 +5,7 @@ set(texthook_src
main.cc main.cc
texthook.cc texthook.cc
hookfinder.cc hookfinder.cc
engine/match.cc
engine/match64.cc engine/match64.cc
engine/native/pchooks.cc engine/native/pchooks.cc
util/ithsys/ithsys.cc util/ithsys/ithsys.cc
@ -17,6 +18,7 @@ set(texthook_src
hookfinder.cc hookfinder.cc
engine/engine.cc engine/engine.cc
engine/match.cc engine/match.cc
engine/match32.cc
engine/native/pchooks.cc engine/native/pchooks.cc
util/util.cc util/util.cc
util/ithsys/ithsys.cc util/ithsys/ithsys.cc

View File

@ -1618,7 +1618,7 @@ bool InsertBGI1Hook()
//ConsoleOutput("Probably BGI. Wait for text."); //ConsoleOutput("Probably BGI. Wait for text.");
//SwitchTrigger(true); //SwitchTrigger(true);
//trigger_fun_=InsertBGIDynamicHook; //trigger_fun=InsertBGIDynamicHook;
ConsoleOutput("vnreng:BGI: failed"); ConsoleOutput("vnreng:BGI: failed");
return false; return false;
} }
@ -2232,7 +2232,7 @@ void InsertRealliveHook()
{ {
//ConsoleOutput("Probably Reallive. Wait for text."); //ConsoleOutput("Probably Reallive. Wait for text.");
ConsoleOutput("vnreng: TRIGGER Reallive"); ConsoleOutput("vnreng: TRIGGER Reallive");
trigger_fun_ = InsertRealliveDynamicHook; trigger_fun = InsertRealliveDynamicHook;
SetTrigger(); SetTrigger();
} }
@ -5787,7 +5787,7 @@ bool InsertShinaHook()
int ver = GetShinaRioVersion(); int ver = GetShinaRioVersion();
if (ver >= 50) { if (ver >= 50) {
SetTrigger(); SetTrigger();
trigger_fun_ = StackSearchingTrigger<GetGlyphOutlineA, NULL>; trigger_fun = StackSearchingTrigger<GetGlyphOutlineA, NULL>;
ConsoleOutput("Textractor: ShinaRio 2.50+: adding trigger"); ConsoleOutput("Textractor: ShinaRio 2.50+: adding trigger");
return true; return true;
} }
@ -5960,7 +5960,7 @@ void InsertWaffleHook()
return; return;
} }
//ConsoleOutput("Probably Waffle. Wait for text."); //ConsoleOutput("Probably Waffle. Wait for text.");
trigger_fun_ = InsertWaffleDynamicHook; trigger_fun = InsertWaffleDynamicHook;
SetTrigger(); SetTrigger();
//ConsoleOutput("vnreng:WAFFLE: failed"); //ConsoleOutput("vnreng:WAFFLE: failed");
} }
@ -7656,7 +7656,7 @@ bool InsertLiveDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
//void InsertLiveHook() //void InsertLiveHook()
//{ //{
// ConsoleOutput("Probably Live. Wait for text."); // ConsoleOutput("Probably Live. Wait for text.");
// trigger_fun_=InsertLiveDynamicHook; // trigger_fun=InsertLiveDynamicHook;
// SwitchTrigger(true); // SwitchTrigger(true);
//} //}
bool InsertLiveHook() bool InsertLiveHook()
@ -8524,7 +8524,7 @@ bool InsertSystemAoiDynamic()
{ {
ConsoleOutput("vnreng: DYNAMIC SystemAoi"); ConsoleOutput("vnreng: DYNAMIC SystemAoi");
//ConsoleOutput("Probably SoftHouseChara. Wait for text."); //ConsoleOutput("Probably SoftHouseChara. Wait for text.");
trigger_fun_ = InsertSystemAoiDynamicHook; trigger_fun = InsertSystemAoiDynamicHook;
SetTrigger(); SetTrigger();
return true; return true;
} }
@ -8811,7 +8811,7 @@ bool InsertIGSDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
void InsertIronGameSystemHook() void InsertIronGameSystemHook()
{ {
//ConsoleOutput("Probably IronGameSystem. Wait for text."); //ConsoleOutput("Probably IronGameSystem. Wait for text.");
trigger_fun_ = InsertIGSDynamicHook; trigger_fun = InsertIGSDynamicHook;
SetTrigger(); SetTrigger();
ConsoleOutput("vnreng: TRIGGER IronGameSystem"); ConsoleOutput("vnreng: TRIGGER IronGameSystem");
} }
@ -9448,7 +9448,7 @@ bool InsertRyokuchaDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
void InsertRyokuchaHook() void InsertRyokuchaHook()
{ {
//ConsoleOutput("Probably Ryokucha. Wait for text."); //ConsoleOutput("Probably Ryokucha. Wait for text.");
trigger_fun_ = InsertRyokuchaDynamicHook; trigger_fun = InsertRyokuchaDynamicHook;
SetTrigger(); SetTrigger();
ConsoleOutput("vnreng: TRIGGER Ryokucha"); ConsoleOutput("vnreng: TRIGGER Ryokucha");
} }
@ -16512,7 +16512,7 @@ void InsertMonoHook(HMODULE h)
Mono calling convention uses 'this' as first argument on stack 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 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 getDomain = (MonoDomain*(*)())GetProcAddress(mono, "mono_domain_get");
static auto getJitInfo = (MonoObject*(*)(MonoDomain*, uintptr_t))GetProcAddress(mono, "mono_jit_info_table_find"); static auto getJitInfo = (MonoObject*(*)(MonoDomain*, uintptr_t))GetProcAddress(mono, "mono_jit_info_table_find");

View File

@ -8,7 +8,7 @@
struct HookParam; // defined in ith types.h struct HookParam; // defined in ith types.h
extern DWORD processStartAddress, processStopAddress; extern uintptr_t processStartAddress, processStopAddress;
namespace Engine { namespace Engine {
@ -16,9 +16,13 @@ namespace Engine {
extern wchar_t *processName, // cached extern wchar_t *processName, // cached
processPath[MAX_PATH]; // cached processPath[MAX_PATH]; // cached
//extern LPVOID trigger_addr; /** jichi 12/24/2014
typedef bool (* trigger_fun_t)(LPVOID addr, DWORD frame, DWORD stack); * @param addr function address
extern trigger_fun_t trigger_fun_; * @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 bool InsertMonoHooks(); // Mono

View File

@ -1,887 +1,58 @@
// match.cc #include "match.h"
// 8/9/2013 jichi #include "engine.h"
// 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 "main.h"
#include "ithsys/ithsys.h" #include "native/pchooks.h"
extern const char* HIJACK_ERROR; 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 namespace Engine
// - 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
{ {
#if 0 // jichi 7/19/2015: Disabled as it will crash the game WCHAR* processName, // cached
if (Util::CheckFile(L"UE3ShaderCompileWorker.exe") && Util::CheckFile(L"awesomium_process.exe")) { processPath[MAX_PATH]; // cached
InsertLovaGameHook();
return true;
}
#endif // 0
return false;
}
// jichi 7/17/2014: Disable GDI hooks for PPSSPP bool UnsafeDetermineEngineType();
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 // jichi 10/21/2014: Return whether found the game engine
//InsertPPSSPPHooks(); // Artikash 8/4/2018: removed for now as doesn't work for non ancient ppsspp versions bool DetermineEngineType()
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+ × (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
{ {
VirtualQuery((void*)::processStopAddress, &info, sizeof(info)); // jichi 9/27/2013: disable game engine for debugging use
::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize; bool found = false;
} while (info.Protect > PAGE_NOACCESS); #ifndef ITH_DISABLE_ENGINE
processStopAddress -= info.RegionSize; __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(); DWORD InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
hijacked = true; {
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

824
texthook/engine/match32.cc Normal file
View File

@ -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+ × (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

View File

@ -2,30 +2,17 @@
#include "main.h" #include "main.h"
#include "native/pchooks.h" #include "native/pchooks.h"
extern const char* HIJACK_ERROR;
namespace Engine namespace Engine
{ {
void HookDirectX() bool UnsafeDetermineEngineType()
{ {
for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" }) for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" })
if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module);
else for (int i = 0; i < 50; ++i) else for (int i = 0; i < 50; ++i)
if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module);
}
void Hijack() PcHooks::hookGDIFunctions();
{ PcHooks::hookGDIPlusFunctions();
static bool hijacked = false; return false;
if (hijacked) return;
hijacked = true;
__try
{
PcHooks::hookGDIFunctions();
PcHooks::hookGDIPlusFunctions();
PcHooks::hookOtherPcFunctions();
HookDirectX();
}
__except (EXCEPTION_EXECUTE_HANDLER) { ConsoleOutput(HIJACK_ERROR); }
} }
} }