mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Sanitize PDB root name from loaded modules (#1687)
This commit is contained in:
parent
8e5a84792e
commit
3d59fa3da0
10 changed files with 181 additions and 39 deletions
|
|
@ -58,7 +58,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Version.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\lib\CoreCLR;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
@ -137,6 +137,7 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ntdll.cpp" />
|
||||
<ClCompile Include="unicode.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
|
|
@ -176,6 +177,7 @@
|
|||
<ClInclude Include="DalamudStartInfo.h" />
|
||||
<ClInclude Include="hooks.h" />
|
||||
<ClInclude Include="logging.h" />
|
||||
<ClInclude Include="ntdll.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="unicode.h" />
|
||||
<ClInclude Include="utils.h" />
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@
|
|||
<ClCompile Include="DalamudStartInfo.cpp">
|
||||
<Filter>Dalamud.Boot DLL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ntdll.cpp">
|
||||
<Filter>Dalamud.Boot DLL</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\CoreCLR\CoreCLR.h">
|
||||
|
|
@ -140,6 +143,9 @@
|
|||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="crashhandler_shared.h" />
|
||||
<ClInclude Include="ntdll.h">
|
||||
<Filter>Dalamud.Boot DLL</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Dalamud.Boot.rc" />
|
||||
|
|
|
|||
|
|
@ -2,39 +2,9 @@
|
|||
|
||||
#include "hooks.h"
|
||||
|
||||
#include "ntdll.h"
|
||||
#include "logging.h"
|
||||
|
||||
enum {
|
||||
LDR_DLL_NOTIFICATION_REASON_LOADED = 1,
|
||||
LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2,
|
||||
};
|
||||
|
||||
struct LDR_DLL_UNLOADED_NOTIFICATION_DATA {
|
||||
ULONG Flags; //Reserved.
|
||||
const UNICODE_STRING* FullDllName; //The full path name of the DLL module.
|
||||
const UNICODE_STRING* BaseDllName; //The base file name of the DLL module.
|
||||
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
||||
};
|
||||
|
||||
struct LDR_DLL_LOADED_NOTIFICATION_DATA {
|
||||
ULONG Flags; //Reserved.
|
||||
const UNICODE_STRING* FullDllName; //The full path name of the DLL module.
|
||||
const UNICODE_STRING* BaseDllName; //The base file name of the DLL module.
|
||||
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
||||
};
|
||||
|
||||
union LDR_DLL_NOTIFICATION_DATA {
|
||||
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
||||
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
||||
};
|
||||
|
||||
using PLDR_DLL_NOTIFICATION_FUNCTION = VOID CALLBACK(_In_ ULONG NotificationReason, _In_ const LDR_DLL_NOTIFICATION_DATA* NotificationData, _In_opt_ PVOID Context);
|
||||
|
||||
static const auto LdrRegisterDllNotification = utils::loaded_module(GetModuleHandleW(L"ntdll.dll")).get_exported_function<NTSTATUS(NTAPI)(ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, PVOID* Cookie)>("LdrRegisterDllNotification");
|
||||
static const auto LdrUnregisterDllNotification = utils::loaded_module(GetModuleHandleW(L"ntdll.dll")).get_exported_function<NTSTATUS(NTAPI)(PVOID Cookie)>("LdrUnregisterDllNotification");
|
||||
|
||||
hooks::getprocaddress_singleton_import_hook::getprocaddress_singleton_import_hook()
|
||||
: m_pfnGetProcAddress(GetProcAddress)
|
||||
, m_thunk("kernel32!GetProcAddress(Singleton Import Hook)",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
|
||||
#include "utils.h"
|
||||
|
|
|
|||
15
Dalamud.Boot/ntdll.cpp
Normal file
15
Dalamud.Boot/ntdll.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#include "pch.h"
|
||||
|
||||
#include "ntdll.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
NTSTATUS LdrRegisterDllNotification(ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, PVOID* Cookie) {
|
||||
static const auto pfn = utils::loaded_module(GetModuleHandleW(L"ntdll.dll")).get_exported_function<NTSTATUS(NTAPI)(ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, PVOID* Cookie)>("LdrRegisterDllNotification");
|
||||
return pfn(Flags, NotificationFunction, Context, Cookie);
|
||||
}
|
||||
|
||||
NTSTATUS LdrUnregisterDllNotification(PVOID Cookie) {
|
||||
static const auto pfn = utils::loaded_module(GetModuleHandleW(L"ntdll.dll")).get_exported_function<NTSTATUS(NTAPI)(PVOID Cookie)>("LdrUnregisterDllNotification");
|
||||
return pfn(Cookie);
|
||||
}
|
||||
33
Dalamud.Boot/ntdll.h
Normal file
33
Dalamud.Boot/ntdll.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
// ntdll exports
|
||||
enum {
|
||||
LDR_DLL_NOTIFICATION_REASON_LOADED = 1,
|
||||
LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2,
|
||||
};
|
||||
|
||||
struct LDR_DLL_UNLOADED_NOTIFICATION_DATA {
|
||||
ULONG Flags; //Reserved.
|
||||
const UNICODE_STRING* FullDllName; //The full path name of the DLL module.
|
||||
const UNICODE_STRING* BaseDllName; //The base file name of the DLL module.
|
||||
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
||||
};
|
||||
|
||||
struct LDR_DLL_LOADED_NOTIFICATION_DATA {
|
||||
ULONG Flags; //Reserved.
|
||||
const UNICODE_STRING* FullDllName; //The full path name of the DLL module.
|
||||
const UNICODE_STRING* BaseDllName; //The base file name of the DLL module.
|
||||
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
||||
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
||||
};
|
||||
|
||||
union LDR_DLL_NOTIFICATION_DATA {
|
||||
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
||||
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
||||
};
|
||||
|
||||
using PLDR_DLL_NOTIFICATION_FUNCTION = VOID CALLBACK(_In_ ULONG NotificationReason, _In_ const LDR_DLL_NOTIFICATION_DATA* NotificationData, _In_opt_ PVOID Context);
|
||||
|
||||
NTSTATUS LdrRegisterDllNotification(ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, PVOID* Cookie);
|
||||
NTSTATUS LdrUnregisterDllNotification(PVOID Cookie);
|
||||
|
|
@ -15,14 +15,20 @@
|
|||
#include <Windows.h>
|
||||
|
||||
// Windows Header Files (2)
|
||||
#include <DbgHelp.h>
|
||||
#include <Dbt.h>
|
||||
#include <dwmapi.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <PathCch.h>
|
||||
#include <Psapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <SubAuth.h>
|
||||
#include <TlHelp32.h>
|
||||
|
||||
// Windows Header Files (3)
|
||||
#include <icmpapi.h> // Must be loaded after iphlpapi.h
|
||||
|
||||
// MSVC Compiler Intrinsic
|
||||
#include <intrin.h>
|
||||
|
||||
|
|
@ -30,6 +36,7 @@
|
|||
#include <comdef.h>
|
||||
|
||||
// C++ Standard Libraries
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
#include "DalamudStartInfo.h"
|
||||
#include "hooks.h"
|
||||
#include "logging.h"
|
||||
#include "ntdll.h"
|
||||
#include "utils.h"
|
||||
#include <iphlpapi.h>
|
||||
#include <icmpapi.h>
|
||||
|
||||
template<typename T>
|
||||
static std::span<T> assume_nonempty_span(std::span<T> t, const char* descr) {
|
||||
|
|
@ -546,6 +545,109 @@ void xivfixes::prevent_icmphandle_crashes(bool bApply) {
|
|||
}
|
||||
}
|
||||
|
||||
void xivfixes::symbol_load_patches(bool bApply) {
|
||||
static const char* LogTag = "[xivfixes:symbol_load_patches]";
|
||||
|
||||
static std::optional<hooks::import_hook<decltype(SymInitialize)>> s_hookSymInitialize;
|
||||
static PVOID s_dllNotificationCookie = nullptr;
|
||||
|
||||
static const auto RemoveFullPathPdbInfo = [](const utils::loaded_module& mod) {
|
||||
const auto ddva = mod.data_directory(IMAGE_DIRECTORY_ENTRY_DEBUG).VirtualAddress;
|
||||
if (!ddva)
|
||||
return;
|
||||
|
||||
const auto& ddir = mod.ref_as<IMAGE_DEBUG_DIRECTORY>(ddva);
|
||||
if (ddir.Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
|
||||
// The Visual C++ debug information.
|
||||
// Ghidra calls it "DotNetPdbInfo".
|
||||
static constexpr DWORD DotNetPdbInfoSignatureValue = 0x53445352;
|
||||
struct DotNetPdbInfo {
|
||||
DWORD Signature; // RSDS
|
||||
GUID Guid;
|
||||
DWORD Age;
|
||||
char PdbPath[1];
|
||||
};
|
||||
|
||||
const auto& pdbref = mod.ref_as<DotNetPdbInfo>(ddir.AddressOfRawData);
|
||||
if (pdbref.Signature == DotNetPdbInfoSignatureValue) {
|
||||
const auto pathSpan = std::string_view(pdbref.PdbPath, strlen(pdbref.PdbPath));
|
||||
const auto pathWide = unicode::convert<std::wstring>(pathSpan);
|
||||
std::wstring windowsDirectory(GetWindowsDirectoryW(nullptr, 0) + 1, L'\0');
|
||||
windowsDirectory.resize(
|
||||
GetWindowsDirectoryW(windowsDirectory.data(), static_cast<UINT>(windowsDirectory.size())));
|
||||
if (!PathIsRelativeW(pathWide.c_str()) && !PathIsSameRootW(windowsDirectory.c_str(), pathWide.c_str())) {
|
||||
utils::memory_tenderizer pathOverwrite(&pdbref.PdbPath, pathSpan.size(), PAGE_READWRITE);
|
||||
auto sep = std::find(pathSpan.rbegin(), pathSpan.rend(), '/');
|
||||
if (sep == pathSpan.rend())
|
||||
sep = std::find(pathSpan.rbegin(), pathSpan.rend(), '\\');
|
||||
if (sep != pathSpan.rend()) {
|
||||
logging::I(
|
||||
"{} Stripping pdb path folder: {} to {}",
|
||||
LogTag,
|
||||
pathSpan,
|
||||
&*sep + 1);
|
||||
memmove(const_cast<char*>(pathSpan.data()), &*sep + 1, sep - pathSpan.rbegin() + 1);
|
||||
} else {
|
||||
logging::I("{} Leaving pdb path unchanged: {}", LogTag, pathSpan);
|
||||
}
|
||||
} else {
|
||||
logging::I("{} Leaving pdb path unchanged: {}", LogTag, pathSpan);
|
||||
}
|
||||
} else {
|
||||
logging::I("{} CODEVIEW struct signature mismatch: got {:08X} instead.", LogTag, pdbref.Signature);
|
||||
}
|
||||
} else {
|
||||
logging::I("{} Debug directory: type {} is unsupported.", LogTag, ddir.Type);
|
||||
}
|
||||
};
|
||||
|
||||
if (bApply) {
|
||||
if (!g_startInfo.BootEnabledGameFixes.contains("symbol_load_patches")) {
|
||||
logging::I("{} Turned off via environment variable.", LogTag);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& mod : utils::loaded_module::all_modules())
|
||||
RemoveFullPathPdbInfo(mod);
|
||||
|
||||
if (!s_dllNotificationCookie) {
|
||||
const auto res = LdrRegisterDllNotification(
|
||||
0,
|
||||
[](ULONG notiReason, const LDR_DLL_NOTIFICATION_DATA* pData, void* /* context */) {
|
||||
if (notiReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
|
||||
RemoveFullPathPdbInfo(pData->Loaded.DllBase);
|
||||
},
|
||||
nullptr,
|
||||
&s_dllNotificationCookie);
|
||||
|
||||
if (res != STATUS_SUCCESS) {
|
||||
logging::E("{} LdrRegisterDllNotification failure: 0x{:08X}", LogTag, res);
|
||||
s_dllNotificationCookie = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
s_hookSymInitialize.emplace("dbghelp.dll!SymInitialize (import, symbol_load_patches)", "dbghelp.dll", "SymInitialize", 0);
|
||||
s_hookSymInitialize->set_detour([](HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess) noexcept {
|
||||
logging::I("{} Suppressed SymInitialize.", LogTag);
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
});
|
||||
|
||||
logging::I("{} Enable", LogTag);
|
||||
}
|
||||
else {
|
||||
if (s_hookSymInitialize) {
|
||||
logging::I("{} Disable", LogTag);
|
||||
s_hookSymInitialize.reset();
|
||||
}
|
||||
|
||||
if (s_dllNotificationCookie) {
|
||||
(void)LdrUnregisterDllNotification(s_dllNotificationCookie);
|
||||
s_dllNotificationCookie = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xivfixes::apply_all(bool bApply) {
|
||||
for (const auto& [taskName, taskFunction] : std::initializer_list<std::pair<const char*, void(*)(bool)>>
|
||||
{
|
||||
|
|
@ -554,7 +656,8 @@ void xivfixes::apply_all(bool bApply) {
|
|||
{ "disable_game_openprocess_access_check", &disable_game_openprocess_access_check },
|
||||
{ "redirect_openprocess", &redirect_openprocess },
|
||||
{ "backup_userdata_save", &backup_userdata_save },
|
||||
{ "prevent_icmphandle_crashes", &prevent_icmphandle_crashes }
|
||||
{ "prevent_icmphandle_crashes", &prevent_icmphandle_crashes },
|
||||
{ "symbol_load_patches", &symbol_load_patches },
|
||||
}
|
||||
) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace xivfixes {
|
|||
void redirect_openprocess(bool bApply);
|
||||
void backup_userdata_save(bool bApply);
|
||||
void prevent_icmphandle_crashes(bool bApply);
|
||||
void symbol_load_patches(bool bApply);
|
||||
|
||||
void apply_all(bool bApply);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,9 +395,15 @@ namespace Dalamud.Injector
|
|||
startInfo.BootShowConsole = args.Contains("--console");
|
||||
startInfo.BootEnableEtw = args.Contains("--etw");
|
||||
startInfo.BootLogPath = GetLogPath(startInfo.LogPath, "dalamud.boot", startInfo.LogName);
|
||||
startInfo.BootEnabledGameFixes = new List<string> {
|
||||
"prevent_devicechange_crashes", "disable_game_openprocess_access_check",
|
||||
"redirect_openprocess", "backup_userdata_save", "prevent_icmphandle_crashes",
|
||||
startInfo.BootEnabledGameFixes = new()
|
||||
{
|
||||
// See: xivfixes.h, xivfixes.cpp
|
||||
"prevent_devicechange_crashes",
|
||||
"disable_game_openprocess_access_check",
|
||||
"redirect_openprocess",
|
||||
"backup_userdata_save",
|
||||
"prevent_icmphandle_crashes",
|
||||
"symbol_load_patches",
|
||||
};
|
||||
startInfo.BootDotnetOpenProcessHookMode = 0;
|
||||
startInfo.BootWaitMessageBox |= args.Contains("--msgbox1") ? 1 : 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue