Attempt to fix for alex compat (#884)

This commit is contained in:
kizer 2022-06-18 02:01:38 +09:00 committed by GitHub
parent 399bc7b4de
commit d3c230f9e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 15 deletions

View file

@ -53,7 +53,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dbghelp.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\lib\CoreCLR;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>

View file

@ -13,7 +13,6 @@ static std::span<T> assume_nonempty_span(std::span<T> t, const char* descr) {
throw std::runtime_error(std::format("Unexpected empty span found: {}", descr));
return t;
}
void xivfixes::unhook_dll(bool bApply) {
static const auto LogTag = "[xivfixes:unhook_dll]";
static const auto LogTagW = L"[xivfixes:unhook_dll]";
@ -24,15 +23,15 @@ void xivfixes::unhook_dll(bool bApply) {
return;
const auto mods = utils::loaded_module::all_modules();
for (size_t i = 0; i < mods.size(); i++) {
const auto& mod = mods[i];
const auto test_module = [&](size_t i, const utils::loaded_module & mod) {
std::filesystem::path path;
try {
path = mod.path();
logging::I("{} [{}/{}] Module 0x{:X} ~ 0x{:X} (0x{:X}): \"{}\"", LogTagW, i + 1, mods.size(), mod.address_int(), mod.address_int() + mod.image_size(), mod.image_size(), path.wstring());
} catch (const std::exception& e) {
logging::W("{} [{}/{}] Module 0x{:X}: Failed to resolve path: {}", LogTag, i + 1, mods.size(), mod.address_int(), e.what());
continue;
return;
}
const auto moduleName = unicode::convert<std::string>(path.filename().wstring());
@ -45,7 +44,7 @@ void xivfixes::unhook_dll(bool bApply) {
auto hFsDllRaw = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (hFsDllRaw == INVALID_HANDLE_VALUE) {
logging::W("{} Module loaded in current process but could not open file: Win32 error {}", LogTag, GetLastError());
continue;
return;
}
auto hFsDll = std::unique_ptr<void, decltype(CloseHandle)*>(hFsDllRaw, &CloseHandle);
@ -54,11 +53,11 @@ void xivfixes::unhook_dll(bool bApply) {
if (DWORD read{}; ReadFile(hFsDll.get(), &buf[0], static_cast<DWORD>(buf.size()), &read, nullptr)) {
if (read < section.size_bytes()) {
logging::W("{} ReadFile: read {} bytes < requested {} bytes", LogTagW, read, section.size_bytes());
continue;
return;
}
} else {
logging::I("{} ReadFile: Win32 error {}", LogTagW, GetLastError());
continue;
return;
}
auto doRestore = false;
@ -142,8 +141,21 @@ void xivfixes::unhook_dll(bool bApply) {
} catch (const std::exception& e) {
logging::W("{} Error: {}", LogTag, e.what());
}
};
const auto aaaa = [&]() {
for (size_t i = 0; i < mods.size(); i++) {
const auto& mod = mods[i];
__try {
test_module(i, mod);
} __except (EXCEPTION_EXECUTE_HANDLER) {
logging::W("{} Error: Access Violation", LogTag);
}
}
};
aaaa();
}
using TFnGetInputDeviceManager = void* ();
static TFnGetInputDeviceManager* GetGetInputDeviceManager(HWND hwnd) {
@ -196,11 +208,12 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) {
logging::I(R"({} CreateWindow(0x{:08X}, "{}", "{}", 0x{:08X}, {}, {}, {}, {}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}) called; unhooking CreateWindowExA and hooking WndProc.)",
LogTag, dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, reinterpret_cast<size_t>(hWndParent), reinterpret_cast<size_t>(hMenu), reinterpret_cast<size_t>(hInstance), reinterpret_cast<size_t>(lpParam));
s_hookCreateWindowExA.reset();
s_hookWndProc.emplace("FFXIVGAME:WndProc (prevent_devicechange_crashes)", hWnd);
s_hookWndProc->set_detour([](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT {
if (uMsg == WM_DEVICECHANGE && wParam == DBT_DEVNODES_CHANGED) {
if (uMsg == WM_CREATE) {
s_hookCreateWindowExA.reset();
} else if (uMsg == WM_DEVICECHANGE && wParam == DBT_DEVNODES_CHANGED) {
if (!GetGetInputDeviceManager(hWnd)()) {
logging::I("{} WndProc(0x{:X}, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, {}) called but the game does not have InputDeviceManager initialized; doing nothing.", LogTag, reinterpret_cast<size_t>(hWnd), lParam);
return 0;
@ -229,6 +242,64 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) {
}
}
static bool is_xivalex(const std::filesystem::path& dllPath) {
DWORD verHandle = 0;
std::vector<uint8_t> block;
block.resize(GetFileVersionInfoSizeW(dllPath.c_str(), &verHandle));
if (block.empty())
return false;
if (!GetFileVersionInfoW(dllPath.c_str(), 0, static_cast<DWORD>(block.size()), &block[0]))
return false;
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} * lpTranslate;
UINT cbTranslate;
if (!VerQueryValueW(&block[0],
TEXT("\\VarFileInfo\\Translation"),
reinterpret_cast<LPVOID*>(&lpTranslate),
&cbTranslate)) {
return false;
}
for (size_t i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++) {
wchar_t* buf = nullptr;
UINT size = 0;
if (!VerQueryValueW(&block[0],
std::format(L"\\StringFileInfo\\{:04x}{:04x}\\FileDescription",
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage).c_str(),
reinterpret_cast<LPVOID*>(&buf),
&size)) {
continue;
}
auto currName = std::wstring_view(buf, size);
while (!currName.empty() && currName.back() == L'\0')
currName = currName.substr(0, currName.size() - 1);
if (currName.empty())
continue;
if (currName == L"XivAlexander Main DLL")
return true;
}
return false;
}
static bool is_openprocess_already_dealt_with() {
static const auto s_value = [] {
for (const auto& mod : utils::loaded_module::all_modules()) {
try {
if (is_xivalex(mod.path()))
return true;
} catch (...) {
// pass
}
}
return false;
}();
return s_value;
}
void xivfixes::disable_game_openprocess_access_check(bool bApply) {
static const char* LogTag = "[xivfixes:disable_game_openprocess_access_check]";
static std::optional<hooks::import_hook<decltype(OpenProcess)>> s_hook;
@ -238,6 +309,10 @@ void xivfixes::disable_game_openprocess_access_check(bool bApply) {
logging::I("{} Turned off via environment variable.", LogTag);
return;
}
if (is_openprocess_already_dealt_with()) {
logging::I("{} Someone else already did it.", LogTag);
return;
}
s_hook.emplace("kernel32.dll!OpenProcess (import, disable_game_openprocess_access_check)", "kernel32.dll", "OpenProcess", 0);
s_hook->set_detour([](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)->HANDLE {
@ -275,6 +350,10 @@ void xivfixes::redirect_openprocess(bool bApply) {
logging::I("{} Turned off via environment variable.", LogTag);
return;
}
if (is_openprocess_already_dealt_with()) {
logging::I("{} Someone else already did it.", LogTag);
return;
}
if (bootconfig::dotnet_openprocess_hook_mode() == bootconfig::ImportHooks) {
auto hook = std::make_shared<hooks::global_import_hook<decltype(OpenProcess)>>("kernel32.dll!OpenProcess (global import, redirect_openprocess)", L"kernel32.dll", "OpenProcess");