add fallback chain in cbLoadDll for path resolution
This commit is contained in:
parent
077d26eaec
commit
cf8b7f70a7
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue