爲得到文件NT-路徑有效的Win32文件路徑 - 最簡單的方法 - 添加L"\\\\?\\globalroot"
(\\?\globalroot
)前綴。這是因爲從CreateFileW
\??\
目錄一看,globalroot
是\??\
符號鏈接,這讓作爲跳轉到NT命名空間的根。
例如 - \Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
是nt絕對路徑。和\\?\globalroot\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
是CreateFileW
有效的win32路徑 - 這個API轉換衆所周知的前綴\\?\
新臺幣前綴\??\
並通過名稱\??\globalroot\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
內核。當解析這個名字 - 後處理符號鏈接globalroot
哪個指向命名空間的根 - 我們再次得到\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
- 正確的nt路徑。
所以如果我們需要在CreateFileW
中使用有效的win32路徑 - 只需將此前綴追加到nt路徑。但是有些shell32 api不接受這種形式的路徑。在UI中看起來也不好看。如果我們想要得到DOS驅動器的信件形式路徑(這是有效的win32路徑的子集) - 我們可以使用IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
將設備名稱轉換爲驅動器號。此ioctl以輸入MOUNTDEV_NAME
(在mountmgr.h中聲明)和輸出緩衝區爲MOUNTMGR_VOLUME_PATHS
。在MOUNTDEV_NAME
緩衝區必須是完全設備名稱,沒有文件路徑。所以我們需要break返回2個組件的路徑。例如在\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
:
\Device\HarddiskVolume9
- 設備路徑
\Windows\SysWOW64\ntdll.dll
- 文件系統路徑
正確這裏第一次打開文件,並調用GetFileInformationByHandleEx
與FileNameInfo
方式 - 我們得到了文件系統路徑輸出。有了這個,我們可以使用wcsstr
作爲單獨的設備路徑。此外,如果我們打開的文件句柄 - 我們可以在通話GetFinalPathNameByHandleW
與VOLUME_NAME_DOS
使用它。這個API做我們將要做的 - 查詢文件路徑,單獨的設備路徑和呼叫IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
。 +打開/關閉安裝管理器。
但通常的NT文件路徑從\Device\HarddiskVolumeX
開始。這允許先嚐試快速的方式 - 避免打開文件並查詢它的路徑。
所以首先我們需要打開安裝管理器:
#include <mountmgr.h>
HANDLE hMountManager = CreateFile(MOUNTMGR_DOS_DEVICE_NAME,
0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
然後我們可以運行下面的代碼:
void dumpModules(HANDLE hMountManager, HANDLE hProcess)
{
ULONG cb = 0, cbNeeded = 16;
volatile static UCHAR guz;
PVOID stack = alloca(guz);
HMODULE *hMods, hmod;
__continue:
// cumulative allocate memory in stack, not need free it
cb = RtlPointerToOffset(hMods = (HMODULE*)alloca(cbNeeded - cb), stack);
if (EnumProcessModulesEx(hProcess, hMods, cb, &cbNeeded, LIST_MODULES_32BIT))
{
if (cb < cbNeeded)
{
goto __continue;
}
if (cbNeeded /= sizeof(HMODULE))
{
//i use hard coded size buffers, for reduce code and show main idea
#define FILE_NAME_INFO_buffer_size FIELD_OFFSET(FILE_NAME_INFO, FileName[MAX_PATH])
#define MOUNTDEV_NAME_buffer_size FIELD_OFFSET(MOUNTDEV_NAME, Name[MAX_PATH])
#define MOUNTMGR_VOLUME_PATHS_buffer_size FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz[64])
// + space for 0 at the end
PFILE_NAME_INFO pfni = (PFILE_NAME_INFO)alloca(FILE_NAME_INFO_buffer_size + sizeof(WCHAR));
PMOUNTMGR_VOLUME_PATHS pmvp = (PMOUNTMGR_VOLUME_PATHS)alloca(MOUNTMGR_VOLUME_PATHS_buffer_size);
PMOUNTDEV_NAME pmdn = (PMOUNTDEV_NAME)alloca(MOUNTDEV_NAME_buffer_size);
static WCHAR globalroot[] = L"\\\\.\\globalroot";
alloca(sizeof(globalroot));
PWSTR win32Path = pmdn->Name - RTL_NUMBER_OF(globalroot) + 1;
memcpy(win32Path, globalroot, sizeof(globalroot));
USHORT NameLength = pmdn->NameLength;
do
{
hmod = *hMods++;
if (GetMappedFileNameW(hProcess, hmod, pmdn->Name, MAX_PATH))
{
DbgPrint("%p %S\n",hmod, pmdn->Name);
PWSTR c = 0;
static const WCHAR HarddiskVolume[] = L"\\Device\\HarddiskVolume";
// fast way
if (!memcmp(pmdn->Name, HarddiskVolume, sizeof(HarddiskVolume) - sizeof(WCHAR)))
{
c = wcschr(pmdn->Name + RTL_NUMBER_OF(HarddiskVolume) - 1, '\\');
}
// else - for demo
{
pmdn->NameLength = NameLength;
HANDLE hFile = CreateFile(win32Path, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
//++ just for demo
WCHAR DosPath[MAX_PATH];
if (GetFinalPathNameByHandleW(hFile, DosPath, RTL_NUMBER_OF(DosPath), VOLUME_NAME_DOS))
{
DbgPrint("%S\n", DosPath);
}
RtlGetLastNtStatus();
//-- just for demo
BOOL fOk = GetFileInformationByHandleEx(hFile, FileNameInfo, pfni, FILE_NAME_INFO_buffer_size);
CloseHandle(hFile);
if (fOk)
{
// FileName not 0 terminated
pfni->FileName[pfni->FileNameLength/sizeof(WCHAR)] = 0;
c = wcsstr(pmdn->Name, pfni->FileName);
}
}
}
if (c)
{
pmdn->NameLength = (USHORT)RtlPointerToOffset(pmdn->Name, c);
if (DeviceIoControl(hMountManager, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
pmdn, MOUNTDEV_NAME_buffer_size,
pmvp, MOUNTMGR_VOLUME_PATHS_buffer_size, &cb, NULL))
{
DbgPrint("%S%S\n", pmvp->MultiSz, c);
}
}
}
} while (--cbNeeded);
}
}
}
和演示輸出記事本:
0000000000170000 \Device\HarddiskVolume9\Windows\SysWOW64\notepad.exe
\\?\C:\Windows\SysWOW64\notepad.exe
C:\Windows\SysWOW64\notepad.exe
0000000077A90000 \Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
\\?\C:\Windows\SysWOW64\ntdll.dll
0000000075460000 \Device\HarddiskVolume9\Windows\SysWOW64\kernel32.dll
\\?\C:\Windows\SysWOW64\kernel32.dll
C:\Windows\SysWOW64\kernel32.dll
0000000074A30000 \Device\HarddiskVolume9\Windows\SysWOW64\KernelBase.dll
\\?\C:\Windows\SysWOW64\KernelBase.dll
C:\Windows\SysWOW64\KernelBase.dll
00000000749B0000 \Device\HarddiskVolume9\Windows\SysWOW64\advapi32.dll
\\?\C:\Windows\SysWOW64\advapi32.dll
這可能是一個超跛腳的建議,但是你有沒有檢查過你的目標/檢查過程實際上是Windows 10中的一個32位程序? –
哈哈,當然..... – AK87
我檢查 - 這真是系統錯誤。當你使用'LIST_MODULES_ALL'時 - 系統真的像你設置'LIST_MODULES_32BIT'一樣工作。你需要調用'EnumProcessModulesEx'兩次:一次用'LIST_MODULES_64BIT'(你有4個64位模塊 - ntdll,wow64,wow64win,wow64cpu),一次用'LIST_MODULES_32BIT' – RbMm