windows下服务或SYSTEM权限读取当前用户注册表HKEY_CURRENT_USER

最近一直在给一个程序增加一个功能,需要修改注册表 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 说明具体尝试

   


你可能感兴趣的:(windows)