如何在循环中为所有用户加载注册表配置单元

时间:2016-10-30 02:18:30

标签: c++ windows winapi registry

使用管理员权限,我需要枚举Windows 7+系统上的所有用户(即使是已注销的用户)。然后我需要为每个用户加载注册表配置单元并设置密钥。

NetUserEnum给了我SID(我猜LsaEnumerateLogonSessions也是如此)。 WTSEnumerateSessions后跟WTSQueryUserToken(获取令牌)会很好,但对于未主动登录的用户不起作用。

所以,我的问题是,在调用NetUserEnum后,如何使用SID为该用户加载注册表?有没有推荐的方法呢?

1 个答案:

答案 0 :(得分:2)

有关本地用户配置文件的信息存储在此注册表项中:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

可以枚举子键,其中每个子键都有一个ProfileImagePath,指向ntuser.dat所在的文件夹。

但是,通过RegLoadKey()直接加载用户个人资料非常糟糕。首先,可能已经加载了配置文件。其次,在您自己加载配置文件后,系统也可能会尝试加载配置文件。请注意RefCount值。系统使用该值加载配置文件(如果尚未加载),递增RefCount。并且UnloadUserProfile()递减RefCount并仅在通过调用RegUnLoadKey()变为0时卸载配置文件。因此,必须同步所有配置文件加载/卸载操作。

加载个人资料只有一种正确方法 - 致电LoadUserProfile()。 (在内部,它在profsvc.LoadUserProfileServer中对svchost.exe -k netsvcs执行RPC调用,完成所有同步。)

那么如何获得LoadUserProfile()的用户令牌?我想打电话LogonUser(),你说你不想做(除非你有用户的密码,否则不能)。

但是,确实存在另一种有效的方式(我对此进行了测试),但它是未记录的LoadUserProfile仅使用来自令牌的用户Sid(使用TOKEN_USER iformation类查询TokenUser信息),然后使用

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\<Sid>

可以通过使用任何给定的SID调用ZwCreateToken()来创建令牌,但是对于此调用,您需要SE_CREATE_TOKEN_PRIVILEGE。此权限仅存在于lsass.exe进程中。所以可能的解决方案是:

  1. 打开lsass.exe并获取其令牌,或模拟其主题。
  2. 在模拟
  3. 后在令牌中启用SE_CREATE_TOKEN_PRIVILEGE
  4. 枚举HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList,对于每个子项查询,其Sid值或(如果Sid不存在)使用ConvertStringSidToSid()将子项名称转换为SID
  5. 使用该SID
  6. 创建令牌
  7. 最后致电LoadUserProfile()
  8. --------------按要求编辑代码示例------------------------- ---

    代码使用了ntdll export(这里有人非常不喜欢)但是按原样

    1. 我们需要SE_CREATE_TOKEN_PRIVILEGE来自己创建令牌 将来
    2. 在系统中枚举进程,为每个进程打开令牌,在令牌中看起来是SE_CREATE_TOKEN_PRIVILEGE,如果是,则复制此令牌,如果需要在其中启用SE_CREATE_TOKEN_PRIVILEGE。最后冒充重复的令牌

      BOOL g_IsXP;// true if we on winXP, false otherwise
      static volatile UCHAR guz;
      static OBJECT_ATTRIBUTES zoa = { sizeof(zoa) };
      
      NTSTATUS ImpersonateIfConformToken(HANDLE hToken)
      {
          ULONG cb = 0, rcb = 0x200;
          PVOID stack = alloca(guz);
      
          union {
              PVOID buf;
              PTOKEN_PRIVILEGES ptp;
          };
      
          NTSTATUS status;
          do 
          {
              if (cb < rcb)
              {
                  cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
              }
      
              if (0 <= (status = ZwQueryInformationToken(hToken, TokenPrivileges, buf, cb, &rcb)))
              {
                  if (ULONG PrivilegeCount = ptp->PrivilegeCount)
                  {
                      PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
                      do 
                      {
                          if (Privileges->Luid.LowPart == SE_CREATE_TOKEN_PRIVILEGE && !Privileges->Luid.HighPart)
                          {
                              static SECURITY_QUALITY_OF_SERVICE sqos = {
                                  sizeof sqos, SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
                              };
      
                              static OBJECT_ATTRIBUTES soa = { sizeof(soa), 0, 0, 0, 0, &sqos };
      
                              if (0 <= (status = ZwDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, &soa, FALSE, TokenImpersonation, &hToken)))
                              {
                                  if (Privileges->Attributes & SE_PRIVILEGE_ENABLED)
                                  {
                                      status = STATUS_SUCCESS;
                                  }
                                  else
                                  {
                                      static TOKEN_PRIVILEGES tp = {
                                          1, { { { SE_CREATE_TOKEN_PRIVILEGE }, SE_PRIVILEGE_ENABLED } }
                                      };
      
                                      status = ZwAdjustPrivilegesToken(hToken, FALSE, &tp, 0, 0, 0);
                                  }
      
                                  if (status == STATUS_SUCCESS)
                                  {
                                      status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hToken, sizeof(HANDLE));
                                  }
      
                                  ZwClose(hToken);
                              }
      
                              return status;
                          }
                      } while (Privileges++, --PrivilegeCount);
                  }
      
                  return STATUS_PRIVILEGE_NOT_HELD;
              }
      
          } while (status == STATUS_BUFFER_TOO_SMALL);
      
          return status;
      }
      
      NTSTATUS GetCreateTokenPrivilege()
      {
          BOOLEAN b;
          RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
      
          ULONG cb = 0, rcb = 0x10000;
          PVOID stack = alloca(guz);
      
          union {
              PVOID buf;
              PBYTE pb;
              PSYSTEM_PROCESS_INFORMATION pspi;
          };
      
          NTSTATUS status;
          do 
          {
              if (cb < rcb)
              {
                  cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
              }
      
              if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb)))
              {
                  status = STATUS_UNSUCCESSFUL;
      
                  ULONG NextEntryOffset = 0;
                  do 
                  {
                      pb += NextEntryOffset;
      
                      if (pspi->InheritedFromUniqueProcessId && pspi->UniqueProcessId)
                      {
                          CLIENT_ID cid = { pspi->UniqueProcessId };
      
                          NTSTATUS s = STATUS_UNSUCCESSFUL;
                          HANDLE hProcess, hToken;
      
                          if (0 <= ZwOpenProcess(&hProcess, g_IsXP ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION, &zoa, &cid))
                          {
                              if (0 <= ZwOpenProcessToken(hProcess, TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
                              {
                                  s = ImpersonateIfConformToken(hToken);
      
                                  NtClose(hToken);
                              }
      
                              NtClose(hProcess);
                          }
      
                          if (s == STATUS_SUCCESS)
                          {
                              return STATUS_SUCCESS;
                          }
                      }
      
                  } while (NextEntryOffset = pspi->NextEntryOffset);
      
                  return status;
              }
      
          } while (status == STATUS_INFO_LENGTH_MISMATCH);
      
          return STATUS_UNSUCCESSFUL;
      }
      

      如果我们有SE_CREATE_TOKEN_PRIVILEGE - 我们可以创建令牌!

      NTSTATUS CreateUserToken(PHANDLE phToken, PSID Sid)
      {
          HANDLE hToken;
          TOKEN_STATISTICS ts;
          NTSTATUS status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken);
      
          if (0 <= status)
          {
              if (0 <= (status = ZwQueryInformationToken(hToken, TokenStatistics, &ts, sizeof(ts), &ts.DynamicCharged)))
              {
                  ULONG cb = 0, rcb = 0x200;
                  PVOID stack = alloca(guz);
      
                  union {
                      PVOID buf;
                      PTOKEN_PRIVILEGES ptp;
                  };
      
                  do 
                  {
                      if (cb < rcb)
                      {
                          cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                      }
      
                      if (0 <= (status = ZwQueryInformationToken(hToken, TokenPrivileges, buf, cb, &rcb)))
                      {
                          TOKEN_USER User = { { Sid } };
      
                          static TOKEN_SOURCE Source = { {' ','U','s','e','r','3','2', ' '} };
      
                          static TOKEN_DEFAULT_DACL tdd;// 0 default DACL
                          static TOKEN_GROUPS Groups;// no groups
      
                          static SECURITY_QUALITY_OF_SERVICE sqos = {
                              sizeof sqos, SecurityImpersonation, SECURITY_DYNAMIC_TRACKING
                          };
      
                          static OBJECT_ATTRIBUTES oa = { 
                              sizeof oa, 0, 0, 0, 0, &sqos
                          };
      
                          status = ZwCreateToken(phToken, TOKEN_ALL_ACCESS, &oa, TokenPrimary, 
                              &ts.AuthenticationId, &ts.ExpirationTime, &User, &Groups, ptp, (PTOKEN_OWNER)&Sid,
                              (PTOKEN_PRIMARY_GROUP)&Sid, &tdd, &Source);
      
                          break;
                      }
      
                  } while (status == STATUS_BUFFER_TOO_SMALL);
              }
      
              ZwClose(hToken);
          }
      
          return status;
      }
      

      最后枚举并加载/卸载用户配置文件

      void EnumProf()
      {
          PROFILEINFO pi = { sizeof(pi), PI_NOUI };
          pi.lpUserName = L"*";
      
          STATIC_OBJECT_ATTRIBUTES(soa, "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList");
      
          HANDLE hKey;
          if (0 <= ZwOpenKey(&hKey, KEY_READ, &soa))
          {
              PVOID stack = alloca(sizeof(WCHAR));
      
              union
              {
                  PVOID buf;
                  PKEY_BASIC_INFORMATION pkbi;
                  PKEY_VALUE_PARTIAL_INFORMATION pkvpi;
              } u = {};
      
              DWORD cb = 0, rcb = 64;
              NTSTATUS status;
              ULONG Index = 0;
      
              do 
              {
                  do 
                  {
                      if (cb < rcb)
                      {
                          cb = RtlPointerToOffset(u.buf = alloca(rcb - cb), stack);
                      }
      
                      if (0 <= (status = ZwEnumerateKey(hKey, Index, KeyBasicInformation, u.buf, cb, &rcb)))
                      {
                          *(PWSTR)RtlOffsetToPointer(u.pkbi->Name, u.pkbi->NameLength) = 0;
      
                          PSID Sid;
                          if (ConvertStringSidToSidW(u.pkbi->Name, &Sid))
                          {
                              HANDLE hToken;
      
                              if (0 <= CreateUserToken(&hToken, Sid))
                              {
                                  if (LoadUserProfile(hToken, &pi))
                                  {
                                      UnloadUserProfile(hToken, pi.hProfile);
                                  }
      
                                  NtClose(hToken);
                              }
                              LocalFree(Sid);
                          }
                      }
      
                  } while (status == STATUS_BUFFER_OVERFLOW);
      
                  Index++;
      
              } while (0 <= status);
      
              ZwClose(hKey);
          }
      }