Основы GetTokenInformation

Я пытался получить этот призыв к сотрудничеству, но безуспешно.

Я пытаюсь получить значение SID для текущего пользователя, чтобы получить права учетной записи пользователя (используя LsaEnumerateAccountRights). Хотя я заблудился, почему Мой вызов GetTokenInformation возвращает false. Нет ошибки при получении токена процесса.

Вот моя работа на эту тему:

    HANDLE h_Process;
HANDLE h_Token;
HANDLE h_retToken;

TOKEN_USER tp;
DWORD cb = sizeof(TOKEN_USER);
PDWORD ret;

DWORD dw_TokenLength;

h_Process = GetCurrentProcess();

if (OpenProcessToken(h_Process, TOKEN_READ, &h_Token) == FALSE)
{
printf("Error: Couldn't open the process token\n");
return -1;
}

if (GetTokenInformation(h_Token, TokenUser, &tp, cb, &dw_TokenLength) == FALSE)
{
printf("Error: Could not retrieve Token User information");
return -1;
}

И наряду с этим я мог бы также задать дополнительный вопрос, с которым я еще не сталкивался, как извлечь SID из сформированной структуры TOKEN_USER?

Я заранее прошу прощения за такой простой вопрос, я просто озадачен и хотел бы продолжить помощь. Все вопросы, связанные с этим вопросом, намного сложнее и дают мало понимания моей нынешней проблемы.

Заранее спасибо,
Джон

0

Решение

Согласно документация для GetTokenInformation, в случае сбоя функции вы можете получить дополнительную информацию, позвонив GetLastError.

Возвращаемое значение

Если функция завершается успешно, возвращаемое значение отлично от нуля.

Если функция не работает, возвращаемое значение равно нулю. Чтобы получить расширенную информацию об ошибке, позвоните GetLastError.

Таким образом, вам нужно реализовать некоторую проверку для расширенной ошибки:

if (!GetTokenInformation(h_Token, TokenUser, &tp, cb, &dw_TokenLength))
{
int lastError = GetLastError();

// Should be a switch, of course. Omitted for brevity
if (lastError == ERROR_INSUFFICIENT_BUFFER)
{
//
}
}

Как правило, при использовании функций WinAPI, которые имеют различные требования к буферу, вы обычно

  • Вызовите функцию с буфером NULL, чтобы определить необходимый размер буфера (в этом случае возвращается в ReturnLength параметр)
  • Выделить буфер указанного размера
  • Вызовите функцию снова, передав выделенный буфер, чтобы получить информацию
1

Другие решения

Первое, что нужно понять, это то, что Win32 UM (пользовательский режим) API, которые приводят к системным вызовам, обычно требуют предоставления буфера заранее. Это связано с тем, что ядро ​​может получить доступ к выделениям кучи единой системы обмена сообщениями, а единой системе обмена сообщениями не может получить доступ к выделениям KM.

Эти вызовы обычно следуют соглашению, когда вы вызываете один раз, чтобы получить требуемый размер буфера, а затем вызываете снова с выделенным буфером, который достаточно велик. Тем не менее, даже лучше, если вы можете заранее создать буфер разумного размера. Системные вызовы могут быть дорогими из-за переключения контекста, которое оно вызывает, поэтому переход от 2 вызовов к 1 может быть большим улучшением производительности, если это горячий путь.

Вот образец того, что вам нужно. У этого есть цикл, который будет пытаться вечно, но также распространено просто попробовать дважды. Если необходимый буфер <= 128, он будет звонить только один раз.

DWORD bytesReturned = 128;
LPVOID tokenUser = nullptr;
auto cleanup = ScopeExit([&]()
{
LocalFree(tokenUser);
});
for (;;) {
tokenUser = LocalAlloc(LMEM_FIXED, bytesReturned);
THROW_HR_IF_NULL(E_OUTOFMEMORY, tokenUser);
if (!GetTokenInformation(token.get(), TokenUser, &tokenUser, bytesReturned, &bytesReturned))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
LocalFree(tokenUser);
tokenUser = nullptr;
continue;
}
THROW_HR(HRESULT_FROM_WIN32(GetLastError()));
}
break;
}

Другая большая проблема с вашим кодом заключается в том, что вы передаете ссылку на TOKEN_USER tp. API на самом деле просто берет PVOID. Буфер SID будет просто в буфере tokenUser. Вам нужно будет привести его к TOKEN_USER *, чтобы правильно получить доступ к памяти.

0

По вопросам рекламы [email protected]