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;
|
auto result = false;
|
||||||
if(GetMappedFileNameW(hProcess, hModule, wszDosFileName, _countof(wszDosFileName)))
|
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));
|
result = !!GetModuleFileNameExW(hProcess, hModule, wszFileName, _countof(wszFileName));
|
||||||
else
|
|
||||||
result = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
result = !!GetModuleFileNameExW(hProcess, hModule, wszFileName, _countof(wszFileName));
|
result = !!GetModuleFileNameExW(hProcess, hModule, wszFileName, _countof(wszFileName));
|
||||||
|
|
|
||||||
|
|
@ -1844,14 +1844,46 @@ static void cbLoadDll(LOAD_DLL_DEBUG_INFO* LoadDll)
|
||||||
hActiveThread = ThreadGetHandle(GetDebugData()->dwThreadId);
|
hActiveThread = ThreadGetHandle(GetDebugData()->dwThreadId);
|
||||||
void* base = LoadDll->lpBaseOfDll;
|
void* base = LoadDll->lpBaseOfDll;
|
||||||
|
|
||||||
|
// Retrieve the DLL path using a fallback
|
||||||
|
// https://github.com/x64dbg/x64dbg/issues/3756
|
||||||
char DLLDebugFileName[MAX_PATH] = "";
|
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)))
|
validPath = true;
|
||||||
strcpy_s(DLLDebugFileName, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "??? (GetFileNameFromHandle failed)")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Update memory map
|
||||||
MemUpdateMapAsync();
|
MemUpdateMapAsync();
|
||||||
|
|
|
||||||
|
|
@ -859,7 +859,7 @@ void GetModuleInfo(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
#undef GetUnsafeModuleInfo
|
#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
|
// Handle a new module being loaded
|
||||||
if(!Base || !Size || !FullPath)
|
if(!Base || !Size || !FullPath)
|
||||||
|
|
@ -928,25 +928,68 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
|
||||||
if(!info.isVirtual)
|
if(!info.isVirtual)
|
||||||
{
|
{
|
||||||
auto wszFullPath = StringUtils::Utf8ToUtf16(FullPath);
|
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))
|
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
|
// Fix an anti-debug trick, which opens exclusive access to the file
|
||||||
CloseHandle(info.fileHandle);
|
CloseHandle(info.fileHandle);
|
||||||
info.fileHandle = (HANDLE)1; // Set to non-zero for TitanEngine compatibility
|
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);
|
// 3. If both failed, try reading from process memory as last resort
|
||||||
info.size = Size;
|
// 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
|
else
|
||||||
{
|
{
|
||||||
info.fileHandle = nullptr;
|
GetModuleInfo(info, info.fileMapVA);
|
||||||
info.loadedSize = 0;
|
Size = HEADER_FIELD(info.headers, SizeOfImage);
|
||||||
info.fileMap = nullptr;
|
info.size = Size;
|
||||||
info.fileMapVA = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ struct MODINFO
|
||||||
};
|
};
|
||||||
|
|
||||||
ULONG64 ModRvaToOffset(ULONG64 base, PIMAGE_NT_HEADERS ntHeaders, ULONG64 rva);
|
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);
|
bool ModUnload(duint Base);
|
||||||
void ModClear(bool updateGui = true);
|
void ModClear(bool updateGui = true);
|
||||||
MODINFO* ModInfoFromAddr(duint Address);
|
MODINFO* ModInfoFromAddr(duint Address);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue