2017-09-25 139 views
4

我尝试使用下面的代码来枚举从64位应用的32位程序的模块名称:GetModuleFileNameEx对32位进程从Windows 64位进程10

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

这可能是一个超跛脚的建议,但是你有没有检查过你的目标/检查过程实际上是Windows 10中的一个32位程序? –

+0

哈哈,当然..... – AK87

+1

我检查 - 这真是系统错误。当你使用'LIST_MODULES_ALL'时 - 系统真的像你设置'LIST_MODULES_32BIT'一样工作。你需要调用'EnumProcessModulesEx'两次​​:一次用'LIST_MODULES_64BIT'(你有4个64位模块 - ntdll,wow64,wow64win,wow64cpu),一次用'LIST_MODULES_32BIT' – RbMm

回答

3

为得到文件NT-路径有效的Win32文件路径 - 最简单的方法 - 添加L"\\\\?\\globalroot"\\?\globalroot)前缀。这是因为从CreateFileW\??\目录一看,globalroot\??\符号链接,这让作为跳转到NT命名空间的根。

例如 - \Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dll是nt绝对路径。和\\?\globalroot\Device\HarddiskVolume9\Windows\SysWOW64\ntdll.dllCreateFileW有效的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 - 文件系统路径

正确这里第一次打开文件,并调用GetFileInformationByHandleExFileNameInfo方式 - 我们得到了文件系统路径输出。有了这个,我们可以使用wcsstr作为单独的设备路径。此外,如果我们打开的文件句柄 - 我们可以在通话GetFinalPathNameByHandleWVOLUME_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 
+0

你不断地发布带有未定义或未初始化的神秘变量的代码。什么是'guz'? –

+0

@JonathanPotter - 忘记复制它的定义。 'volatile static UCHAR guz;'我用它来获得堆栈指针。如果使用优化编译器写入'stack = alloca(0)',则放弃该指令。但是当我使用'alloca(guz)'而不是 - 这是工作正常,因为我声明'guz'为'volatile'。当然我们可以使用'alloca(1)'。但是当'guz == 0'时我更喜欢'alloca(guz)' – RbMm

+1

这只适用于工具帮助'TH32CS_SNAPMODULE32'快照。它调用'RtlQueryProcessModuleInformation',它使用'RtlGetNtSystemRoot'和'RtlReplaceSystemDirectoryInPath'等函数来重写使用SysWOW64而不是System32的路径。 – eryksun

相关问题