无法获取映射驱动器C/C的关联网络UNC++
编写了一个DLL,试图将映射驱动器转换为其等效的网络UNC。但当DLL被作为提升进程运行的安装程序调用时,它会失败。作为一种潜在的修复方法,我修改了@RbMn提供的示例源代码,对以下问题进行了回答: 对GetLogicalDrives的调用就像声明的那样工作。但是,当它使用映射的驱动器号调用WNetGetConnection时,返回的错误是1222 error_NO_NETWORK,因此不会给出相关的UNC。我相信这个问题源于我如何假装登录。由于我对UAC事务的了解非常有限,我不确定为了正确获取所需信息,我必须对模拟登录进行哪些修改 非常感谢您的帮助 以下是实际代码:无法获取映射驱动器C/C的关联网络UNC++,c,windows,uac,unc,mapped-drive,C,Windows,Uac,Unc,Mapped Drive,编写了一个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);
}
每个登录会话使用Microsoft LAN Manager进行连接。更确切地说,它与登录会话LUID关联。这存储在令牌中,可以从中读取。所以,若您模拟或处理,任何网络驱动器函数的结果都取决于您当前的令牌线程。使用不同的标记-可以得到不同的结果。提升进程和未提升进程始终在不同的登录会话中运行,进程令牌中的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);
}
}
@HarryJohnston-否,WNetGetConnection或更好的NetUseGetInfo完全支持模拟。只是它不支持SecurityIdentification模拟级别。几乎没有人接受这个水平。GetLogicalDrives在这里很少例外。但对于WNetGetConnection,需要SecurityImpersonation级别。因此,需要更多的代码来实现进程内查询keep,记住提升的令牌可能有自己的一组驱动器映射(例如,如果用户打开了提升的命令窗口并使用了net use),因此您需要确定这两个令牌中的哪一个是您想要的。对于一个安装程序来说,一开始就关心驱动器映射是很奇怪的。感谢您提供的代码示例。复习之后,我对路易斯有了更好的了解。