Невозможно отучить людей изучать самые ненужные предметы.
Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3
    
    
Надо знать обо всем понемножку, но все о немногом.
Идентификаторы
Контекстные селекторы
Соседние селекторы
    
Дочерние селекторы
    
Селекторы атрибутов
 
Универсальный селектор
    
Псевдоклассы
  
Псевдоэлементы
    
Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)
Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода
    
Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
   
Списки
                                          
Ссылки
                                          
Дизайны сайтов
    
Формы
  
Таблицы
    
CSS3
                                         
HTML5
                                       
									Блог для вебмастеров
									Новости мира Интернет
                                    Сайтостроение
    
									Ремонт и советы
	
                                    Все новости
                                        
									
                                    Справочник от А до Я
    
									HTML, CSS, JavaScript
									
									
									Афоризмы о учёбе
									Статьи об афоризмах
									Все Афоризмы
									
									
| Помогли мы вам | 
Токен же хранит внутри себя множество различных SID, среди которых можно выделить основные:
Достаточно сложно, правда ведь? Но можно провести простую аналогию. Токен — карточка сотрудника компании. SID пользователя — имя на этой карточке, SID группы — напечатанная должность. Система смотрит на эту карточку каждый раз, когда мы начинаем с ней взаимодействовать.
В Windows есть процессы, а есть потоки. Говоря простыми словами, это некие объекты, обладающие собственным виртуальным адресным пространством. Потоком называют ход выполнения программы. Поток выполняется в рамках владеющего им процесса, или, как говорят, в контексте процесса. Любое запущенное приложение представляет собой процесс, в контексте которого выполняется по крайней мере один поток.
У процесса есть токен. Чаще всего используется токен пользователя, запустившего процесс. Когда процесс порождает другие процессы, все они используют этот же токен.
Если нам требуется выполнить одну задачу с токеном одного пользователя, а другую с токеном другого пользователя, запускать новый процесс как‑то не очень удобно. Поэтому токен можно применить и к определенному потоку процесса.
Существует несколько функций для получения токена. Для работы с процессами и потоками можно использовать следующие варианты.
Вариант 1: получить токен определенного процесса.
BOOL OpenProcessToken( [in] HANDLE ProcessHandle, [in] DWORD DesiredAccess, [out] PHANDLE TokenHandle);Вариант 2: получить токен определенного потока.
BOOL OpenThreadToken( [in] HANDLE ThreadHandle, [in] DWORD DesiredAccess, [in] BOOL OpenAsSelf, [out] PHANDLE TokenHandle);Переписывать MSDN и объяснять каждый параметр как‑то неправильно. Если вдруг ты незнаком с WinAPI, то можешь написать мне, скину материал для изучения. Предлагаю обратить внимание лишь на второй параметр — DesiredAccess.
Здесь ты должен указать, какой тип доступа к токену хочешь получить. Это значение преобразуется в маску доступа, на основе которой Windows определяет, можно выдавать токен или нельзя. WinAPI предоставляет для такой маски некоторые стандартные значения.
Обрати внимание, что просто так засунуть TOKEN_ALL_ACCESS нельзя: система банально не выдаст токен, так как в эту маску входит и TOKEN_ADJUST_SESSIONID, который требует наличие привилегии SeTcbPrivilege. Такой привилегией обладает лишь система.
При этом данную ошибку допускают очень часто. Например, лишь в версии 4.7 инструмента Cobalt Strike был исправлен этот недочет.
Чаще всего для наших задач мы будем указывать привилегию TOKEN_DUPLICATE, чтобы использовать функцию DuplicateTokenEx(, которую мы разберем позже.
Вариант 3: запросить токен пользователя, если мы знаем его логин и пароль.
BOOL LogonUserA( [in]LPCSTR lpszUsername, [in, optional] LPCSTR lpszDomain, [in, optional] LPCSTR lpszPassword, [in]DWORD dwLogonType, [in]DWORD dwLogonProvider, [out]PHANDLE phToken);Токен также содержит информацию о привилегиях пользователя. У самих привилегий в Windows есть два представления:
Act as part of the operating system      ;SE_TCB_NAME.Для проверки можно использовать следующую функцию:
BOOL PrivilegeCheck( [in]HANDLEClientToken, [in, out] PPRIVILEGE_SET RequiredPrivileges, [out] LPBOOLpfResult);Сам код может быть примерно следующий (принимает токен, в котором надо проверить наличие привилегии, и ее имя. Допустим, SE_DEBUG_NAME):
bool IsPrivilegeEnabled(HANDLE hToken, PCWSTR name) { PRIVILEGE_SET set{}; set.PrivilegeCount = 1; if (!::LookupPrivilegeValue(nullptr, name, &set.Privilege[0].Luid)) return false; BOOL result; return ::PrivilegeCheck(hToken, &set, &result) && result;}Допустимые изменения делятся на две группы:
Для большинства ситуаций можно воспользоваться этой функцией:
BOOL SetTokenInformation( [in] HANDLETokenHandle, [in] TOKEN_INFORMATION_CLASS TokenInformationClass, [in] LPVOIDTokenInformation, [in] DWORDTokenInformationLength);Конечно же, в токене возможно изменить далеко не все параметры. Ниже описаны допустимые классы информации для SetTokenInformation(, а также привилегии и маски доступа, которые для этого требуются.
Например, чтобы включить виртуализацию UAC, используй следующий код:
// hProcess имеет PROCESS_QUERY_INFORMATIONHANDLE hToken;OpenProcessToken(hProcess, TOKEN_ADJUST_DEFAULT, &hToken);ULONG enable = 1;SetTokenInformation(hToken, TokenVirtualizationEnabled,&enable, sizeof(enable));При этом мы можем изменить и привилегии, содержащиеся в токене! Но требуется знать, как получить из программного имени привилегии ее LUID. Это позволяет сделать следующая функция:
BOOL LookupPrivilegeValueA( [in, optional] LPCSTR lpSystemName, [in]LPCSTR lpName, [out]PLUID lpLuid);Следующим шагом мы должны вызвать AdjustTokenPrivilege(:
BOOL AdjustTokenPrivileges( [in]HANDLETokenHandle, [in]BOOLDisableAllPrivileges, [in, optional] PTOKEN_PRIVILEGES NewState, [in]DWORDBufferLength, [out, optional] PTOKEN_PRIVILEGES PreviousState, [out, optional] PDWORDReturnLength);Эта функция может как включить привилегии, так и отключить их. Не знаю, почему Microsoft не реализовала что‑нибудь подобное:
BOOL EnableTokenPrivilege(HANDLE hToken, LPTSTR szPriv, BOOL bEnabled) { TOKEN_PRIVILEGES tp; LUID luid; BOOL bRet = FALSE; __try {// Ищем уникальный для системы LUID привилегииif (!LookupPrivilegeValue(NULL, szPriv /*SE_DEBUG_NAME*/, &luid)) {// Если имя фиктивное__leave;}// Создаем массив привилегий нашего маркера (в данном случае массив из одного элемента)tp.PrivilegeCount = 1;tp.Privileges[0].Luid = luid;tp.Privileges[0].Attributes = bEnabled ? SE_PRIVILEGE_ENABLED : 0;// Изменяем состояние привилегий маркера, включая или отключая привилегии из нашего массиваif (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {__leave;}bRet = TRUE; } __finally {}; return(bRet);}Этой функции требуется передать токен, программное имя привилегии и булево значение, TRUE или FALSE, то есть включить привилегию или выключить ее. При этом токен должен иметь маску TOKEN_ADJUST_PRIVILEGES.
| 
 | 
    
			
 | 
