我正致力于报告从本机系统API收集的一些信息。 (我知道这很糟糕......但我得到的信息是我无法得到的,而且如果/当这个时间到来时我不得不更新我的应用程序。)
本机API返回本机路径名,如ob
所示,即\SystemRoot\System32\Ntoskrnl.exe
或\??\C:\Program Files\VMWare Workstation\vstor-ws60.sys
。
我可以替换常用的前缀,即
std::wstring NtPathToWin32Path( std::wstring ntPath )
{
if (boost::starts_with(ntPath, L"\\\\?\\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 4);
return ntPath;
}
if (boost::starts_with(ntPath, L"\\??\\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 4);
}
if (boost::starts_with(ntPath, L"\\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 1);
}
if (boost::istarts_with(ntPath, L"globalroot\\"))
{
ntPath.erase(ntPath.begin(), ntPath.begin() + 11);
}
if (boost::istarts_with(ntPath, L"systemroot"))
{
ntPath.replace(ntPath.begin(), ntPath.begin() + 10, GetWindowsPath());
}
if (boost::istarts_with(ntPath, L"windows"))
{
ntPath.replace(ntPath.begin(), ntPath.begin() + 7, GetWindowsPath());
}
return ntPath;
}
TEST(Win32Path, NtPathDoubleQuestions)
{
ASSERT_EQ(L"C:\\Example", NtPathToWin32Path(L"\\??\\C:\\Example"));
}
TEST(Win32Path, NtPathUncBegin)
{
ASSERT_EQ(L"C:\\Example", NtPathToWin32Path(L"\\\\?\\C:\\Example"));
}
TEST(Win32Path, NtPathWindowsStart)
{
ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\\World"), NtPathToWin32Path(L"\\Windows\\Hello\\World"));
}
TEST(Win32Path, NtPathSystemrootStart)
{
ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\\World"), NtPathToWin32Path(L"\\SystemRoot\\Hello\\World"));
}
TEST(Win32Path, NtPathGlobalRootSystemRoot)
{
ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\\World"), NtPathToWin32Path(L"\\globalroot\\SystemRoot\\Hello\\World"));
}
但如果没有一些原生或其他的API会将这些API转换为Win32路径名,我会非常惊讶。这样的API是否存在?
答案 0 :(得分:8)
我们在生产代码中执行此操作。据我所知,没有API(公共或私人)处理这个问题。我们只是用一些前缀做一些字符串比较,它对我们有用。
显然在ntdll.dll中有一个名为RtlNtPathNameToDosPathName()的函数(在XP中引入?),但我不知道它的作用;我猜它会更多地与\ Device \ Harddisk0之类的东西有关。
但是,我不确定是否真的需要这样的功能。 Win32将路径(在CreateFile等意义上)传递给NT; NT不会将路径传递给Win32。所以ntdll.dll实际上并不需要从NT路径转到Win32路径。在极少数情况下,某些NT查询函数返回完整路径,任何转换函数都可能是Win32 dll的内部(例如,未导出)。我甚至不知道他们是否打扰,因为像GetModuleFileName()这样的东西只会返回用于加载图像的任何路径。我想这只是一个漏洞的抽象。答案 1 :(得分:4)
这是你可以尝试的东西。首先使用NtCreateFile打开文件,音量等进行阅读。然后使用返回的HANDLE获取here所述的完整路径。
答案 2 :(得分:1)
检查这一点以获取Win32中的规范路径名。它可能对您有所帮助:
http://pdh11.blogspot.com/2009/05/pathcanonicalize-versus-what-it-says-on.html
答案 3 :(得分:1)
请参阅my answer to this question。
您需要先在该路径上获取该文件的句柄,然后获取该句柄的Win32路径。
答案 4 :(得分:0)
我写了一个函数,将不同类型的NT设备名称(文件名,COM端口,网络路径等)转换为DOS路径。
有两个功能。一个将句柄转换为NT路径,另一个将此NT路径转换为DOS路径。
看看这里: How to get name associated with open HANDLE
// "\Device\HarddiskVolume3" (Harddisk Drive)
// "\Device\HarddiskVolume3\Temp" (Harddisk Directory)
// "\Device\HarddiskVolume3\Temp\transparent.jpeg" (Harddisk File)
// "\Device\Harddisk1\DP(1)0-0+6\foto.jpg" (USB stick)
// "\Device\TrueCryptVolumeP\Data\Passwords.txt" (Truecrypt Volume)
// "\Device\Floppy0\Autoexec.bat" (Floppy disk)
// "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB" (DVD drive)
// "\Device\Serial1" (real COM port)
// "\Device\USBSER000" (virtual COM port)
// "\Device\Mup\ComputerName\C$\Boot.ini" (network drive share, Windows 7)
// "\Device\LanmanRedirector\ComputerName\C$\Boot.ini" (network drive share, Windwos XP)
// "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP)
// "\Device\Afd" (internet socket)
// "\Device\Console000F" (unique name for any Console handle)
// "\Device\NamedPipe\Pipename" (named pipe)
// "\BaseNamedObjects\Objectname" (named mutex, named event, named semaphore)
// "\REGISTRY\MACHINE\SOFTWARE\Classes\.txt" (HKEY_CLASSES_ROOT\.txt)
答案 5 :(得分:0)
这有点晚了,但是我仍然会发布我的答案,因为即使在今天,这也是一个很好的问题!
我将共享经过测试并用于将NT转换为DOS路径的功能之一。就我而言,我还必须从ANSI转换为UNICODE,所以这对您来说是一个小小的收获,让您了解并了解如何实现。
所有这些代码都可以在用户模式下使用,因此我们需要先准备一些东西。
定义和结构:
typedef NTSTATUS(WINAPI* pRtlAnsiStringToUnicodeString)(PUNICODE_STRING, PANSI_STRING, BOOL);
typedef struct _RTL_BUFFER {
PUCHAR Buffer;
PUCHAR StaticBuffer;
SIZE_T Size;
SIZE_T StaticSize;
SIZE_T ReservedForAllocatedSize; // for future doubling
PVOID ReservedForIMalloc; // for future pluggable growth
} RTL_BUFFER, * PRTL_BUFFER;
typedef struct _RTL_UNICODE_STRING_BUFFER {
UNICODE_STRING String;
RTL_BUFFER ByteBuffer;
UCHAR MinimumStaticBufferForTerminalNul[sizeof(WCHAR)];
} RTL_UNICODE_STRING_BUFFER, * PRTL_UNICODE_STRING_BUFFER;
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_AMBIGUOUS (0x00000001)
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_UNC (0x00000002)
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_DRIVE (0x00000003)
#define RTL_NT_PATH_NAME_TO_DOS_PATH_NAME_ALREADY_DOS (0x00000004)
typedef NTSTATUS(WINAPI* pRtlNtPathNameToDosPathName)(__in ULONG Flags, __inout PRTL_UNICODE_STRING_BUFFER Path, __out_opt PULONG Disposition, __inout_opt PWSTR* FilePart);
#define RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE (0x00000001)
#define RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING (0x00000002)
#define RTL_DUPSTR_ADD_NULL RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
#define RTL_DUPSTR_ALLOC_NULL RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
typedef NTSTATUS(WINAPI* pRtlDuplicateUnicodeString)(_In_ ULONG Flags, _In_ PUNICODE_STRING StringIn, _Out_ PUNICODE_STRING StringOut);
导入功能:
pRtlAnsiStringToUnicodeString MyRtlAnsiStringToUnicodeString;
pRtlNtPathNameToDosPathName MyRtlNtPathNameToDosPathName;
pRtlDuplicateUnicodeString MyRtlDuplicateUnicodeString;
MyRtlAnsiStringToUnicodeString = (pRtlAnsiStringToUnicodeString)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAnsiStringToUnicodeString");
MyRtlNtPathNameToDosPathName = (pRtlNtPathNameToDosPathName)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlNtPathNameToDosPathName");
MyRtlDuplicateUnicodeString = (pRtlDuplicateUnicodeString)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlDuplicateUnicodeString");
辅助功能:
NTSTATUS NtPathNameToDosPathName(PUNICODE_STRING DosPath, PUNICODE_STRING NtPath)
{
NTSTATUS Status;
ULONG_PTR BufferSize;
PWSTR Buffer;
RTL_UNICODE_STRING_BUFFER UnicodeBuffer;
BufferSize = NtPath->MaximumLength + MAX_PATH * sizeof(WCHAR);
Buffer = (PWSTR)_alloca(BufferSize);
ZeroMemory(&UnicodeBuffer, sizeof(UnicodeBuffer));
UnicodeBuffer.String = *NtPath;
UnicodeBuffer.String.Buffer = Buffer;
UnicodeBuffer.String.MaximumLength = (USHORT)BufferSize;
UnicodeBuffer.ByteBuffer.Buffer = (PUCHAR)Buffer;
UnicodeBuffer.ByteBuffer.Size = BufferSize;
CopyMemory(Buffer, NtPath->Buffer, NtPath->Length);
MyRtlNtPathNameToDosPathName(0, &UnicodeBuffer, NULL, NULL);
return MyRtlDuplicateUnicodeString(RTL_DUPSTR_ADD_NULL, &UnicodeBuffer.String, DosPath);
}
功能用法:
UNICODE_STRING us;
UNICODE_STRING DosPath;
ANSI_STRING as;
as.Buffer = (char*)malloc(strlen(NT_PATH_FILE_OR_DIR) + 1);
strcpy(as.Buffer, NT_PATH_FILE_OR_DIR);
as.Length = as.MaximumLength = us.MaximumLength = us.Length = strlen(NT_PATH_FILE_OR_DIR);
MyRtlAnsiStringToUnicodeString(&us, &as, TRUE);
NtPathNameToDosPathName(&DosPath, &us);
如上所述,就我而言,我需要从ANSI转换为UNICODE,这可能不适用于您的情况,因此您可以将其删除。
与上述相同,可用于创建自定义函数并根据需要转换路径。