PowerToys
PowerToys copied to clipboard
[FileLocksmith.Interop] Enhance File Path Resolution with GetFinalPathNameByHandle
Description of the new feature / enhancement
Context
In the current implementation of the FileLocksmith module NtdllExtensions::path_to_kernel_name is utilized to translate NT-style paths to a more conventional, drive-based format.
This translation is necessary after fetching file paths using the NtDll.NtQuerySystemInformation
function.
While this manual approach is functional, Windows API offers a more robust and potentially less error-prone method for achieving the same goal: GetFinalPathNameByHandleW. This function, given a file handle, returns the full drive-based path of the file, including handling various path nuances and edge cases automatically.
Proposal
Replace the current manual method implemented in path_to_kernel_name
with GetFinalPathNameByHandleW
Scenario when this would be used?
Convert the NT device object path to the path with the drive letter.
Supporting information
Reference implementation in pseudo C#
internal static class WinApi {
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
private static extern int GetFinalPathNameByHandleW(SafeFileHandle hFile, [Out] StringBuilder filePathBuffer, int filePathBufferSize, int flags);
public static string? GetFinalPathNameByHandle(SafeFileHandle hFile)
{
var buf = new StringBuilder();
var result = GetFinalPathNameByHandleW(hFile, buf, buf.Capacity, 0);
if(result == 0)
{
return null;
}
buf.EnsureCapacity(result);
result = GetFinalPathNameByHandleW(hFile, buf, buf.Capacity, 0);
if (result == 0)
{
return null;
}
var str = buf.ToString();
return str.StartsWith(@"\\?\") ? str.Substring(4) : str;
}
}
public void Test()
{
var handles = NtDll.QuerySystemHandleInformation();
foreach (var h in handles)
{
using var openedProcess = WinApi.OpenProcess(...);
var curProcess = WinApi.GetCurrentProcess();
var res = WinApi.DuplicateHandle(out var dupHandle);
// If the handle type is a File, then the driveLetterBasedFileFullName will have a value like "\\?\C:\Windows\System32\en-US\combase.dll.mui"
var driveLetterBasedFileFullName = WinApi.GetFinalPathNameByHandle(dupHandle)
}
}
@jaimecbernardo-msft - if you agree with this change I am going to take off the needs-triage label and add the Help-Wanted tag
@jaimecbernardo-msft - if you agree with this change I am going to take off the needs-triage label and add the Help-Wanted tag
Sounds good to me, @joadoumie . Thank you!