最近一直在给一个程序增加一个功能,需要修改注册表 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2 下的值,刚开始自认为很简单,就调用修改注册表的API函数,但是各种尝试之后一直返回错误码2,自己纠结了很久。研究了两天才找到原因,我的程序是个服务权限是 SYSTEM,读取不到 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2 下的值。原因如下(自己这么想的,对不对也不确定):
1. 服务运行在系统权限之下,而不是任何一个用户
2. HKEY_CURRENT_USER存储的是当前用户的信息
3. HKEY_CURRENT_USER的部分注册表写操作被重定向到HKEY_USERS下面去了;
经过各种大神的指导,终于解决了该问题。
有两种方法:
(一)模拟一个普通用户登陆,可以操作 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2
(二) 获取 SID,操作HKEY_CURRENT_USER被重定向到 HKEY_USERS 的值。
方法一:
(1) 获取sessionId
DWORD cursessionid;
cursessionid = WTSGetActiveConsoleSessionId();
(2)根据 seesionid 获取用户令牌
HANDLE hToken
WTSQueryUserToken(cursessionid, &hToken)
(3) 模拟用户登陆
ImpersonateLoggedOnUser(hToken)
(4)获取用户名
TCHAR szUsername[MAX_PATH];
DWORD dwUsernameLen = MAX_PATH;
GetUserNameGetUserName(szUsername, &dwUsernameLen);
(5)保存当前模拟用户的信息并终止当前用户标识的模拟
PROFILEINFO cuProfileInfo;
cuProfileInfo.dwSize = sizeof(cuProfileInfo);
cuProfileInfo.lpUserName = szUsername;
cuProfileInfo.dwFlags = 1;
RevertToSelf();
(6) 根据保存的普通用户信息加载环境变量,加载完之后我们就可以用作普通用户操作注册了,要特别注意红字部分,否则还是操作失败
LoadUserProfile(hToken, &cuProfileInfo)
regedit = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MountPoints2\\";
RegOpenKeyExA((struct HKEY__ *)cuProfileInfo.hProfile, regedit.c_str(), NULL, KEY_ALL_ACCESS , &hkey);
操作完成之后记得卸载环境变量
UnLoadUserProfile(hToken);
方法二:
既然我们知道注册表被重定向到 HKEY_USER 下了,那我们就可以找到具体重定向那里了。
同 方法一的前 五步骤一样的,只是我们不加载普通用户的环境变量而是获取 用户的 SID。获取到 SID 我们就可以查找到重定向的位置
PSID pSID = NULL;
DWORD cbSid = 0;
LPTSTR DomainName = NULL;
DWORD cbDomainName = 0;
SID_NAME_USE SIDNameUse;
BOOL bDone = FALSE;
if(!LookupAccountName(NULL,
szUsername,
pSID,
&cbSid,
DomainName,
&cbDomainName,
&SIDNameUse))
{
pSID = (PSID)malloc(cbSid);
DomainName = (LPTSTR)malloc(cbDomainName * sizeof(TCHAR));
if(!pSID || !DomainName)
{
log_error("malloc memery is failed\s");
}
if(!LookupAccountName(NULL,
szUsername,
pSID,
&cbSid,
DomainName,
&cbDomainName,
&SIDNameUse))
{
log_error("%s LookupAccountName is failed\s", __FUNCTION__);
}
}
LPTSTR strsid;
ConvertSidToStringSid(pSID, &strsid);
FreeSid(pSID);
log_printf("%s\n", strsid);
if(strsid)
{
std::string regedit = strsid(这里不对的话可能是编码原因,注意编码的转换);
(在我们需要打开的子键前面再加上获取到的 SID, 就是 HKEY_CURRENT_USER 下注册表被重定向到 HKEY_USER 下的位置)
regedit += "\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MountPoints2\\
RegOpenKeyExA(HKEY_USER, regedit.c_str(), NULL, KEY_ALL_ACCESS , &hkey);
我们打开 HEKY_USER 下的子键。
}
以上的步骤只是我自己操作的简单说明,可能有不对的地方,大家可以根据 MSDN 说明具体尝试