我尝试使用以下代码从64位应用程序枚举32位处理模块名称:
if (EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL))
{
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH] = { 0 };
if (GetModuleFileNameEx(hProcess, hMods[i], szModName,
sizeof(szModName) / sizeof(TCHAR)))
{
printf("module name is: %S", szModName);
}
}
}
代码在Windows 7中按预期工作,结果的一部分是:
...
C:\Windows\**SysWOW64**\ntdll.dll
...
在Windows 10中,上面的代码返回完整路径,但使用System32而不是SysWOW64。 e.g,
...
C:\Windows\**System32**\ntdll.dll
...
深入了解原因,我注意到GetModuleFileNameEx读取远程进程PEB和LDR_TABLE_ENTRY,并且从Windows 10开始,LDR_TABLE_ENTRY包含System32的完整路径而不是SysWOW64 - 也适用于32位应用程序。
我也尝试过使用GetMappedFileName,但是将dos路径(\ device \ harddiskvolume)的路径转换为标准(c:\)路径并不是一件容易的事。
我想知道是否还有其他简单方法可以提取完整的syswow64路径。
答案 0 :(得分:3)
从文件nt-path获取有效的win32文件路径 - 最简单的方法 - 添加L"\\\\?\\globalroot"
( \\?\globalroot
)前缀。这是因为CreateFileW
来自 \??\
目录而 globalroot
是 \??\
中的符号链接,它允许跳转到nt名称空间的根目录。
- \Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
是绝对路径。并且 \\?\globalroot\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
是CreateFileW
的有效win32路径 - 此api将众所周知的前缀 \\?\
转换为nt前缀 {{ 1}} 并将名称 \??\
传递给内核。在解析此名称时 - 在指向命名空间根的进程符号链接 \??\globalroot\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
之后 - 我们再次得到 globalroot
- 正确的nt路径。
因此,如果我们需要在\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
中使用有效的win32路径 - 只需将此前缀附加到nt路径即可。但是有些shell32 api不接受这种形式的路径。用户界面看起来也不好看。如果我们想要DOS驱动器盘符表单路径(这是有效的win32路径的子集) - 我们可以使用 CreateFileW
将设备名称转换为驱动器号。此ioctl接受输入IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
(在 mountmgr.h 中声明),输出缓冲区为MOUNTDEV_NAME
。在MOUNTMGR_VOLUME_PATHS
缓冲区中必须是设备名称,没有文件路径。所以我们需要将返回的nt路径中断到2个组件。例如,在 MOUNTDEV_NAME
:
\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll
- 设备路径\Device\HarddiskVolume9
- 文件系统路径正确的方法首先打开文件并使用\Windows\SysWOW64\ntdll.dll
调用GetFileInformationByHandleEx
- 我们在输出中获得了文件系统路径。有了这个,我们可以使用FileNameInfo
作为单独的设备路径。如果我们打开文件句柄,我们也可以在调用wcsstr
中使用GetFinalPathNameByHandleW
。这个api正是我们要做的 - 查询文件路径,分离设备路径并调用VOLUME_NAME_DOS
。 +打开/关闭安装管理器。
但通常的nt文件路径从 IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
开始。这允许首先尝试快速方式 - 避免打开文件并查询它的路径。
所以首先我们需要开放式安装管理器:
\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);
}
}
}