编写了一个 DLL,该 DLL 尝试将映射驱动器转换为其等效网络 UNC。但是,当作为提升的进程运行的安装程序调用 DLL 时,它会失败。作为潜在的修复程序,我修改了@RbMn提供的示例源,回答以下问题:使用提升的权限运行时如何正确检测网络驱动器
对GetLogicalDrives的调用就像它所说的那样工作。但是,当它使用映射的驱动器号调用 WNetGetConnection 时,返回的错误为 1222 (ERROR_NO_NETWORK(,因此未提供关联的 UNC。我相信问题源于我如何模拟登录。由于我对 UAC 事务的了解非常有限,因此我不确定为了正确获取所需信息,我必须对模拟登录进行哪些更改。
任何帮助将不胜感激。
下面是实际代码:
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);
}
使用LAN 管理器建立的连接是每个登录会话Microsoft更确切地说,它与登录会话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=%un", Drive, err);
}
else
{
DbgPrint("%S -> %Sn", 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);
}
}