1
0
Fork 0

add fallback chain in cbLoadDll for path resolution

This commit is contained in:
AzuLX 2026-01-10 18:59:01 +00:00
parent 077d26eaec
commit cf8b7f70a7
No known key found for this signature in database
GPG Key ID: BED7E7DC23A637BC
4 changed files with 99 additions and 17 deletions

View File

@ -272,10 +272,17 @@ bool GetFileNameFromModuleHandle(HANDLE hProcess, HMODULE hModule, char* szFileN
auto result = false;
if(GetMappedFileNameW(hProcess, hModule, wszDosFileName, _countof(wszDosFileName)))
{
if(!DevicePathToPathW(wszDosFileName, wszFileName, _countof(wszFileName)))
if(DevicePathToPathW(wszDosFileName, wszFileName, _countof(wszFileName)))
{
// Verify the file exists - GetMappedFileNameW can return stale paths due to kernel section caching
// https://github.com/x64dbg/x64dbg/issues/3756
if(GetFileAttributesW(wszFileName) != INVALID_FILE_ATTRIBUTES)
result = true;
}
// Fall back to GetModuleFileNameExW if the path conversion failed or the file doesn't exist
if(!result)
result = !!GetModuleFileNameExW(hProcess, hModule, wszFileName, _countof(wszFileName));
else
result = true;
}
else
result = !!GetModuleFileNameExW(hProcess, hModule, wszFileName, _countof(wszFileName));

View File

@ -1844,14 +1844,46 @@ static void cbLoadDll(LOAD_DLL_DEBUG_INFO* LoadDll)
hActiveThread = ThreadGetHandle(GetDebugData()->dwThreadId);
void* base = LoadDll->lpBaseOfDll;
// Retrieve the DLL path using a fallback
// https://github.com/x64dbg/x64dbg/issues/3756
char DLLDebugFileName[MAX_PATH] = "";
if(!GetFileNameFromHandle(LoadDll->hFile, DLLDebugFileName, _countof(DLLDebugFileName)))
bool validPath = false;
//1 - Try kernel path from file handle
if(GetFileNameFromHandle(LoadDll->hFile, DLLDebugFileName, _countof(DLLDebugFileName)) &&
FileExists(DLLDebugFileName))
{
if(!GetFileNameFromModuleHandle(fdProcessInfo->hProcess, HMODULE(base), DLLDebugFileName, _countof(DLLDebugFileName)))
strcpy_s(DLLDebugFileName, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "??? (GetFileNameFromHandle failed)")));
validPath = true;
}
ModLoad((duint)base, 1, DLLDebugFileName);
//2 - Invalidate section cache and retry
// FSCTL_CHECK_FOR_SECTION releases cached image sections. This primarily helps step 3 (GetMappedFileNameW)
// which uses NtQueryVirtualMemory. The retry here is kinda speculative - GetFileNameFromHandle uses
// NtQueryInformationFile which may not benefit, but we retry anyway in case it helps.
// https://github.com/x64dbg/x64dbg/issues/3756
if(!validPath && LoadDll->hFile)
{
IO_STATUS_BLOCK iosb = {};
constexpr ULONG FSCTL_CHECK_FOR_SECTION = 0x90348;
NtFsControlFile(LoadDll->hFile, nullptr, nullptr, nullptr, &iosb, FSCTL_CHECK_FOR_SECTION, nullptr, 0, nullptr, 0);
if(GetFileNameFromHandle(LoadDll->hFile, DLLDebugFileName, _countof(DLLDebugFileName)) &&
FileExists(DLLDebugFileName))
{
validPath = true;
}
}
//3 - Try GetMappedFileNameW (with internal fallback to PEB)
if(!validPath)
{
validPath = GetFileNameFromModuleHandle(fdProcessInfo->hProcess, HMODULE(base), DLLDebugFileName, _countof(DLLDebugFileName));
}
//Give up
if(!validPath)
strcpy_s(DLLDebugFileName, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "??? (GetFileNameFromHandle failed)")));
ModLoad((duint)base, 1, DLLDebugFileName, true, LoadDll->hFile);
// Update memory map
MemUpdateMapAsync();

View File

@ -859,7 +859,7 @@ void GetModuleInfo(MODINFO & Info, ULONG_PTR FileMapVA)
#undef GetUnsafeModuleInfo
}
bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols, HANDLE hFile)
{
// Handle a new module being loaded
if(!Base || !Size || !FullPath)
@ -928,25 +928,68 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
if(!info.isVirtual)
{
auto wszFullPath = StringUtils::Utf8ToUtf16(FullPath);
bool fileLoaded = false;
// Load the physical module from disk
// 1. Try loading the physical module from disk
if(StaticFileLoadW(wszFullPath.c_str(), UE_ACCESS_READ, false, &info.fileHandle, &info.loadedSize, &info.fileMap, &info.fileMapVA))
{
// Fix an anti-debug trick, which opens exclusive access to the file
CloseHandle(info.fileHandle);
info.fileHandle = (HANDLE)1; // Set to non-zero for TitanEngine compatibility
fileLoaded = true;
}
GetModuleInfo(info, info.fileMapVA);
// 2. If path-based loading failed and we have a file handle, try mapping from it
// This handles cases where the file is locked with exclusive access
// https://github.com/x64dbg/x64dbg/issues/3756
if(!fileLoaded && hFile)
{
DWORD fileSize = GetFileSize(hFile, nullptr);
if(fileSize != INVALID_FILE_SIZE && fileSize > 0)
{
HANDLE hMap = CreateFileMappingW(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr);
if(hMap)
{
LPVOID mapView = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if(mapView)
{
info.fileHandle = (HANDLE)1; // Non-zero for TitanEngine compatibility
info.loadedSize = fileSize;
info.fileMap = hMap;
info.fileMapVA = (ULONG_PTR)mapView;
fileLoaded = true;
}
else
{
CloseHandle(hMap);
}
}
}
}
Size = HEADER_FIELD(info.headers, SizeOfImage);
info.size = Size;
// 3. If both failed, try reading from process memory as last resort
// Note: This may not work perfectly for file offset -> RVA conversions since process memory is SEC_IMAGE mapped
if(!fileLoaded)
{
info.mappedData.realloc(Size);
if(MemRead(Base, info.mappedData(), info.mappedData.size()))
{
info.loadedSize = (DWORD)Size;
GetModuleInfo(info, (ULONG_PTR)info.mappedData());
}
else
{
info.fileHandle = nullptr;
info.loadedSize = 0;
info.fileMap = nullptr;
info.fileMapVA = 0;
}
}
else
{
info.fileHandle = nullptr;
info.loadedSize = 0;
info.fileMap = nullptr;
info.fileMapVA = 0;
GetModuleInfo(info, info.fileMapVA);
Size = HEADER_FIELD(info.headers, SizeOfImage);
info.size = Size;
}
}
else

View File

@ -147,7 +147,7 @@ struct MODINFO
};
ULONG64 ModRvaToOffset(ULONG64 base, PIMAGE_NT_HEADERS ntHeaders, ULONG64 rva);
bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols = true);
bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols = true, HANDLE hFile = nullptr);
bool ModUnload(duint Base);
void ModClear(bool updateGui = true);
MODINFO* ModInfoFromAddr(duint Address);