2016-10-30 2 views
0

С правами администратора, мне нужно перечислить всех пользователей в системе Windows 7+ (даже те, которые вышли из системы). Затем мне нужно загрузить куст реестра для каждого пользователя и установить ключ.Как загрузить куст реестра для всех пользователей в цикле

NetUserEnum дает мне SID (я думаю, LsaEnumerateLogonSessions тоже). WTSEnumerateSessions, за которым следует WTSQueryUserToken (для получения токена), было бы неплохо, но оно не работает для пользователей, которые не активно вошли в систему.

Итак, мой вопрос, после вызова NetUserEnum, как использовать SID для загрузки реестра для этого пользователя? Любой рекомендуемый способ сделать это?

+1

'NetUserEnum()' может возвращать имена пользователей. Не совпадают ли эти имена пользователей с подпапками в вашей папке «Пользователи»? В этом случае вы можете просто перечислить подпапки 'Users' и не использовать' NetUserEnum() 'вообще. Или даже перечислите разделы «HKEY_USERS» в реестре напрямую. –

+0

Если профиль не загружен, он не отображается в HKEY_USERS, поэтому требуется RegLoadKey или LoadUserProfile. Я не хочу использовать пароль, поэтому LogonUser не работает. – pcunite

ответ

2

Информация о локальных профилях пользователей хранятся в этом ключе реестра:

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

Можно перечислить его подразделов, где каждый подключ имеет ProfileImagePath, что указывает на папку, где находится ntuser.dat.

Но, непосредственно загружая профиль пользователя RegLoadKey(), очень плохо. Во-первых, профиль уже может быть загружен. Во-вторых, возможно, что после загрузки профиля самостоятельно система может также попробовать загрузить профиль. Обратите внимание на значение RefCount. Система использует это значение для загрузки профиля, если он еще не загружен, приращение RefCount. И UnloadUserProfile() уменьшается RefCount и выгружает профиль, только когда он становится 0, вызывая RegUnLoadKey(). Поэтому все операции загрузки/выгрузки профиля должны быть синхронизированы.

Существует только один правильный способ загрузки профиля - звонок LoadUserProfile(). (внутренне он выполняет вызов RPC до profsvc.LoadUserProfileServer в svchost.exe -k netsvcs, где выполняется вся синхронизация).

Итак, как вы получаете токен пользователя для LoadUserProfile()? Я думаю, звоните LogonUser(), о котором вы сказали, что не хотите делать (и не можете, если у вас нет пароля пользователя).

Но существует другой способ, который работает (я тестировал это), но это недокументированный. LoadUserProfile используется только пользователь Sid из маркеров (запроса для TOKEN_USER информации с TokenUser классом iformation), а затем работать с

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

ключ

Можно создать маркер, вызвав ZwCreateToken() с любой заданной SID, но для этого звонка вам нужно SE_CREATE_TOKEN_PRIVILEGE. Эта привилегия существует только в процессе lsass.exe. Таким образом, возможным решением является:

  1. открыть lsass.exe и получить свой токен или выдавать себя за нить.
  2. позволяет SE_CREATE_TOKEN_PRIVILEGE в маркере, после того, как олицетворения
  3. перечислить HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList, и для каждого запроса подключ его значение Sid, или (если Sid не существует) преобразовать имя подраздела в SID с помощью ConvertStringSidToSid()
  4. создать токен что SID
  5. и, наконец, называют LoadUserProfile()

-------------- EDIT пример кода по запросу --------------- -------------

код, используемый Ntdll экспорт (что кто-то здесь очень не нравится), но как

  1. нам нужно есть SE_CREATE_TOKEN_PRIVILEGE создать маркер самостоятельно в будущем

перечислений процессы в система, открытый токен для каждого процесса, посмотрите: 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); 
    } 
} 
+0

C++ версия этого будет приятной? https://micksmix.wordpress.com/2012/01/13/update-a-registry-key-for-all-users-on-a-system/ – pcunite

+0

Мне нравятся звуки Варианта 2, запрос для Token_user. Можете ли вы подробнее рассказать об этом? Какие шаги? – pcunite

+1

@pcunite - хорошо. Я вставляю полный рабочий код, но не уверен, что вы можете использовать его как есть или изменить для себя – RbMm

 Смежные вопросы

  • Нет связанных вопросов^_^