2017-08-24 224 views
0

编写了一个试图将映射驱动器转换为其等效网络UNC的DLL。但是,当安装程序作为高级进程运行DLL时,它会失败。作为一个潜在的修复程序,我修改了@RbMn提供的示例源,以回答以下问题:How to correctly detect Network drive when running with elevated privileges无法获取映射驱动器的关联网络UNC C/C++

对GetLogicalDrives的调用与它声明的一样工作。但是,当它使用映射的驱动器号对WNetGetConnection进行调用时,返回的错误是1222(ERROR_NO_NETWORK),因此不会提供关联的UNC。我相信问题源于我如何去冒充登录。由于我对UAC事务的知识非常有限,因此我不确定我为了正确获取所需信息而冒用登录方式必须改变什么。

任何帮助,非常感谢。

下面是实际的代码:使用Microsoft LAN Manager按登录会话

BOOL ConvertToMappedFolder(LPSTR pUncPath, LPSTR pMappedDrive) 
{ 
    BOOL bRet = 0; 

if (1) 
{ 
    HANDLE hToken = NULL; 
    ULONG rcb = 0; 
    TOKEN_ELEVATION_TYPE tet = 0; 
    TOKEN_LINKED_TOKEN tlt = { 0 }; 
    ULONG err = BOOL_TO_ERR(OpenProcessToken(GetCurrentProcess() /* NtCurrentProcess() */, TOKEN_QUERY, &hToken)); 

if (err == NOERROR) 
{ 
    err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb)); 

    if (err == NOERROR) 
    { 
    if (tet == TokenElevationTypeFull) 
    { 
    err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb)); 

    if (err == NOERROR) 
    { 
     if (NOERROR == (err = BOOL_TO_ERR(SetThreadToken(0, tlt.LinkedToken)))) 
     { 
     bRet = ConvertToMappedFolderEx(pUncPath, pMappedDrive); 
     SetThreadToken(0, 0); 
     } 

     CloseHandle(tlt.LinkedToken); 
    } 
    } 
} 
} 
} 

BOOL ConvertToMappedFolderEx(LPSTR pUncPath, LPSTR pMappedDrive) 
{ 
int nPos = 0; 
UINT nType = 0; 
char strDrive[MAX_PATH+1] = "?:\\"; 
DWORD dwDriveList = GetLogicalDrives(); 
BOOL bRet = FALSE; 

(*pMappedDrive) = 0; 

// Check each drive letter determining if it is a mapped drive... 
while (dwDriveList) 
{ 
if (dwDriveList & 1) 
{ 
strDrive[0] = 0x41 + nPos; 

nType = GetDriveType(strDrive); 

// If drive unknown do not attempt to determine if its UNC matches up... 
if (DRIVE_UNKNOWN != nType) 
{ 
char szDeviceName[MAX_PATH+1] = ""; 
char szDriveLetter[4] = " :"; 
DWORD dwResult = 0; 
DWORD cchBuff = MAX_PATH; 

szDriveLetter[0] = strDrive[0]; 
dwResult = WNetGetConnection(szDriveLetter, (LPSTR) szDeviceName, &cchBuff); 


if (NO_ERROR == dwResult) 
{ 
LPSTR pPath = _stristr(pUncPath, szDeviceName); 

if (NULL != pPath) 
{ 
strcpy(pMappedDrive, szDriveLetter); 
strcat(pMappedDrive, (pUncPath + strlen(szDeviceName))); 

bRet = TRUE; 
break; 
} 
} 
} 
} 

dwDriveList >>= 1; 
nPos++; 
} 

return (bRet); 
} 
+1

@HarryJohnston - 不,'WNetGetConnection'或更好的'NetUseGetInfo'全力支持模拟。只是它不支持'SecurityIdentification'模拟级别。几乎没有人接受这个水平。 'GetLogicalDrives'这里很少例外。但对于'WNetGetConnection'则需要'SecurityImpersonation'级别。所以在进程查询中需要更多的代码实现 – RbMm

+1

请记住,提升的令牌可能有自己的一组驱动器映射 - 例如,如果用户打开了提升的命令窗口并使用了net use,那么您需要确定哪些你想要的两个。 (安装程序首先关心驱动器映射是相当奇怪的。) –

回答

1

连接制成。更准确地说,它与登录会话LUID相关联。这存储在令牌中,可以从TOKEN_STATISTICS.AuthenticationId中读取。所以任何网络驱动器函数的结果都取决于您当前的令牌 - 线程(如果您模拟)或进程。使用不同的令牌 - 可以给出不同的结果。升级和未升级的进程始终运行在不同的登录会话中(进程令牌中具有不同的AuthenticationId)。

所以没有任何意义在说windows的网络驱动器。需要在登录会话中谈论网络驱动器。和不同的登录会话有不同的网络驱动器组。我们可以做下一步 - 枚举所有当前正在运行的进程,为每个进程打开它的令牌并查询AuthenticationId - 然后我们可以一次模拟和查询每个新的AuthenticationId或者说我们可以查询AuthenticationId未提升的令牌,与我们的提升链接,然后尝试找到具有此标记的进程,模拟它并使用此标记进行查询。

代码示例:

void CheckDrives() 
{ 
    LONG dwDriveList = GetLogicalDrives(); 

    WCHAR Drive[] = L"Z:"; 

    ULONG n = 1 + 'Z' - 'A'; 

    do 
    { 
     if (_bittest(&dwDriveList, --n)) 
     { 
      if (DRIVE_REMOTE == GetDriveTypeW(Drive)) 
      { 
       PUSE_INFO_0 pui; 

       if (NET_API_STATUS err = NetUseGetInfo(0, Drive, 0, (BYTE**)&pui)) 
       { 
        DbgPrint("%S error=%u\n", Drive, err); 
       } 
       else 
       { 
        DbgPrint("%S -> %S\n", pui->ui0_local, pui->ui0_remote); 
        NetApiBufferFree(pui); 
       } 
      } 
     } 

     --*Drive; 

    } while (n); 
} 

BOOL ImpersonateNotElevated(LUID AuthenticationId) 
{ 
    BOOL fOk = FALSE; 

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

    if (hSnapshot != INVALID_HANDLE_VALUE) 
    { 
     PROCESSENTRY32W pe = { sizeof(pe) }; 

     ULONG rcb; 

     BOOL fFound = FALSE; 

     if (Process32First(hSnapshot, &pe)) 
     { 
      do 
      { 
       if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID)) 
       { 
        HANDLE hToken, hNewToken;     

        if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken)) 
        { 
         TOKEN_STATISTICS ts; 

         if (GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &rcb)) 
         { 
          if (ts.AuthenticationId.LowPart == AuthenticationId.LowPart && ts.AuthenticationId.HighPart == AuthenticationId.HighPart) 
          { 
           fFound = TRUE; 

           if (DuplicateToken(hToken, SecurityImpersonation, &hNewToken)) 
           { 
            fOk = SetThreadToken(0, hNewToken); 

            CloseHandle(hNewToken); 
           } 
          } 
         } 
         CloseHandle(hToken); 
        } 

        CloseHandle(hProcess); 
       } 

      } while (!fFound && Process32Next(hSnapshot, &pe)); 
     } 

     CloseHandle(hSnapshot); 
    } 

    return fOk; 
} 

void CheckDrivesNotElevated() 
{ 
    HANDLE hToken; 

    if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken)) 
    { 
     union { 
      TOKEN_ELEVATION_TYPE tet; 
      TOKEN_LINKED_TOKEN tlt; 
     }; 

     ULONG rcb; 

     if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb)) 
     { 
      if (tet == TokenElevationTypeFull) 
      { 
       if (GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb)) 
       { 
        TOKEN_STATISTICS ts; 

        BOOL fOk = GetTokenInformation(tlt.LinkedToken, ::TokenStatistics, &ts, sizeof(ts), &rcb); 

        CloseHandle(tlt.LinkedToken); 

        if (fOk) 
        { 
         if (ImpersonateNotElevated(ts.AuthenticationId)) 
         { 
          CheckDrives(); 
          SetThreadToken(0, 0); 
         } 
        } 
       } 
      } 
      else 
      { 
       CheckDrives(); 
      } 
     } 
     CloseHandle(hToken); 
    } 
} 
+0

感谢您的代码示例。在审查之后,我对LUID有了更好的理解。 – user8507966

相关问题