思路:获取所有使用的盘符,从26个字母中剔除这些使用的,剩下未使用的,可以进行挂载。
std::string TCHAR2STRING(TCHAR * STR)
{
int iLen = WideCharToMultiByte(CP_ACP, 0, STR, -1, NULL, 0, NULL, NULL);
char* chRtn = new char[iLen * sizeof(char)];
WideCharToMultiByte(CP_ACP, 0, STR, -1, chRtn, iLen, NULL, NULL);
std::string str(chRtn);
return str;
}
//获得所有使用的盘符
void getDrive(vector<string>& vsUse)
{
DWORD dwDriveStrLen;
TCHAR wDrivesName[0x100];
dwDriveStrLen = sizeof(wDrivesName);
GetLogicalDriveStrings(dwDriveStrLen, wDrivesName);
TCHAR *p = (TCHAR *)wDrivesName;
while (*p)
{
string strDrivePath = TCHAR2STRING(p);
transform(strTmp.begin(), strTmp.end(), strTmp.begin(), tolower);
vsUse.push_back(strDrivePath.substr(0,1));
char* pRet = TCHAR2char(p);
p += (_tcslen(TCHAR2char(p)) + 1);
delete[] pRet;
}
}
net use 盘符: \\服务器名\共享文件名 /user:用户名 "密码"
例如:
net use q: \\127.0.0.1\new /user:admin 12345
但是上述命令挂载成功后重启电脑需要手动再输入密码,不能记住密码,记住密码需要使用/SAVECRED /PERSISTENT:YES,但该字段与user字段不能同时使用,如果想既输入密码又记住密码,需要先建立一个windows凭据,然后使用/SAVECRED /PERSISTENT:YES字段,这样会使用已有的凭据来进行网络映射。
net use 盘符: \\服务器名\共享文件名 /SAVECRED /PERSISTENT:YES
例如:
net use q: \\127.0.0.1\new /SAVECRED /PERSISTENT:YES
建立windows凭据的命令为:
cmdkey /add:服务器名 /user:用户名 /pass:密码
例如:
cmdkey /add:127.0.0.1 /user:admin /pass:12345
使用时,先添加凭据,再输入net use记住密码的挂载命令。
执行挂载命令时,如果使用管理员权限,即便执行命令成功,计算机那里不会显示相应的盘,需要使用普通权限来运行cmd命令。
如果是程序中,程序是管理员权限运行,那么就需要降权来执行挂载的命令。
具体降权的做法是:获取Shell的桌面窗口的句柄,拿到Explorer的token,复制这个token,然后用这个token执行cmd命令,即目的是使用Explorer等级的权限(普通权限)来运行命令。
int excuteExplorerLevel(char* CommandLine)
{
int iRet = 1;
SECURITY_ATTRIBUTES sa;
HANDLE hRead, hWrite;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
//创建匿名管道,用例读执行完cmd命令的返回信息的
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
return FALSE;
}
STARTUPINFOW si;
PROCESS_INFORMATION pi;
SecureZeroMemory(&si, sizeof(si));
SecureZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
//si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
HANDLE hShellProcess = nullptr, hShellProcessToken = nullptr,
hPrimaryToken = nullptr;
HWND hwnd = nullptr;
DWORD dwPID = 0;
HRESULT hr = S_OK;
BOOL ret = TRUE;
DWORD dwLastErr;
//获取Shell的桌面窗口的句柄
hwnd = GetShellWindow();
if (nullptr == hwnd) {
::CloseHandle(hWrite);
::CloseHandle(hRead);
return 0;
}
GetWindowThreadProcessId(hwnd, &dwPID);
if (0 == dwPID) {
::CloseHandle(hWrite);
::CloseHandle(hRead);
return 0;
}
hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
if (!hShellProcess)
{
dwLastErr = GetLastError();
return 0;
}
bool retval = false;
//获取token
ret = OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken);
if (!ret) {
dwLastErr = GetLastError();
CloseHandle(hShellProcessToken);
CloseHandle(hPrimaryToken);
CloseHandle(hShellProcess);
::CloseHandle(hWrite);
::CloseHandle(hRead);
return 0;
}
// 复制token
const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID;
ret = DuplicateTokenEx(hShellProcessToken, dwTokenRights, nullptr,
SecurityImpersonation, TokenPrimary, &hPrimaryToken);
if (!ret) {
dwLastErr = GetLastError();
CloseHandle(hShellProcessToken);
CloseHandle(hPrimaryToken);
CloseHandle(hShellProcess);
::CloseHandle(hWrite);
::CloseHandle(hRead);
return 0;
}
int dwLen = strlen(CommandLine) + 1;
int nwLen = MultiByteToWideChar(CP_ACP, 0, CommandLine, dwLen, NULL, 0);//算出合适的长度
LPWSTR lpszPath = new WCHAR[dwLen];
MultiByteToWideChar(CP_ACP, 0, CommandLine, dwLen, lpszPath, nwLen);
//使用token执行cmd命令
ret = CreateProcessWithTokenW(hPrimaryToken, 0, nullptr, lpszPath, 0, nullptr,
nullptr, &si, &pi);
if (!ret) {
dwLastErr = GetLastError();
CloseHandle(hShellProcessToken);
CloseHandle(hPrimaryToken);
CloseHandle(hShellProcess);
::CloseHandle(hWrite);
::CloseHandle(hRead);
return 0;
}
//等待命令行执行完
::WaitForSingleObject(pi.hThread, INFINITE);
::WaitForSingleObject(pi.hProcess, INFINITE);
DWORD dwFileSize = GetFileSize(hRead, NULL);
char *buffer = new char[dwFileSize + 1]; //最后一位为'\0',C-Style字符串的结束符。
DWORD dwReadSize;
// 从匿名管道中读取结果到输出缓冲区
::ReadFile(hRead, buffer, dwFileSize, &dwReadSize, NULL);
if (strstr(buffer, _T("错误")) != nullptr)
{
if (strstr(buffer, _T("85")) != nullptr)
{
//85代表当前盘符已有网络映射
iRet = 85;
}
else if (strstr(buffer, _T("1219")) != nullptr)
{
//系统错误,不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接,需要全部端口再连接
iRet = 1219;
}
else
{
//其他一些错误
iRet = 0;
}
}
delete[] buffer;
//释放资源
if (pi.hThread != nullptr)
{
::CloseHandle(pi.hThread);
}
if (pi.hProcess != nullptr)
{
::CloseHandle(pi.hProcess);
}
::CloseHandle(hWrite);
::CloseHandle(hRead);
CloseHandle(hShellProcessToken);
CloseHandle(hPrimaryToken);
CloseHandle(hShellProcess);
return iRet;
}