В системах класса Win, одним из привлекательных направлений является программирование сервисов. Связано это с тем, что сервисы имеют приоритет над обычными приложениями, поскольку предназначены для обслуживания работы самой ОС и запускаются от имени системы. По этой причине, их ещё называют системными службами. Если провести аналогию с Linux, то сервисы Win можно сравнить с демонами, которые присутствуют всегда, но не выползая в свет работают в фоне. В данном треде попробуем разобраться с технической их стороной и посмотрим, какую они представляют угрозу безопасности. Материал получился обширным, а потому пришлось разделить его на две части.
Оглавление:
1. Введение (в заблуждение)
Работа сервисов тесно связана с такими понятиями как: сессии входа в систему, оконные\терминальные станции, и рабочие столы "Desktop". По сути, эта триада представляет собой рабочее окружение всей исполняемой среды Win, так-что для полноты картины имеет смысл дать ей определение. Здесь нужно отметить, что тема довольно мутная, а её разбор и понимание усугубляет то, что начиная с Висты внутренняя архитектура претерпела огромные изменения. Более того, некоторые сюрпризы в этом плане подвезли и в десятку (например виртуальные десктопы Win10), а значит и новшества Висты уже устарели.
Но не всё так плохо, поскольку общие принципы и фундамент остался прежним – из крана с идеями уже не бьёт как прежде струя, и нам будут подкидывать мелкие крапаля ещё довольно долго. Просто Microsoft в своём стиле навешивает на старый позвоночник никому не нужные аппендиксы, выдавая их за нечто новое (а как иначе продать товар?). Далее по тексту, отличительные особенности разных ОС будут выноситься в сноски, оставляя свободу основным моментам организации исполняемой среды.
2. Учётные записи пользователей
Windows изначально проектировалась как много-пользовательская ОС. Пользователь считается легальным, если в разделе реестра HKEY_USERS для него создана своя учётная запись. Отвечающий за безопасность компонент ядра LSASS не использует имена юзеров в привычном нам строковом виде, а при вводе данных аккаунта в окне WinLogon, назначает им идентификатор безопасности SID (Security Identifier), после чего формирует для данного SID маркер-доступа к различным объектам ACCESS_TOKEN (защищённые объекты ожидают пользовательский SID в своих списках DACL). Таким образом, каждый из прошедших проверку пользователей, должен иметь свою учётную запись, SID и токен.
В контексте данной статьи мы сконцентрируем своё внимание на токене, поскольку именно он определяет привилегии, а так-же служит мандатом при попытке доступа к буквально всем объектам системы, например службам, процессам, файлам, и т.д. Если повезёт утянуть токен у пользователя System, мы получим полную власть над системой, оставив даже админа нервно курить в сторонке. Для этого, открывается какой-либо системный процесс функцией OpenProcess(), далее запрашивается его маркер безопасности через OpenProcessToken(), и с полученного токена снимается ксерокопия DuplicateTokenEx() с флагом "TOKEN_PRIMARY". Поскольку дескрипторы процессов наследуются от родителей, теперь мы сможем запустить любой код от имени пользователя System функцией CreateProcessAsUser(), которая требует в первом аргументе именно токен юзверя.
Помимо знакомых большинству из нас учётных записей типа Admin, User, Guest (им назначается SID = S-1-5-21-x-y-z), в системе имеются ещё как-минимум 4 перечисленных ниже скрытых пользователя, которые заслужено привлекают к себе внимание (для них последние числа 7,18,19,21 и т.д. известны как RID, или относительный RelativeID):
Если зайти в раздел реестра HKEY_USERS, можно обнаружить там подразделы для этих учётных записей.
Что касается Win-10, то в ней к уже имеющимся, присавокупились ещё две учётки:
Более развёрнутую информацию по теме можно найти на сайте MSDN по
3. Сессии входа в систему
В силу того, что каждый зареганый пользователь имеет свой SID, привилегии, и права на доступ к объектам, подсистема безопасности Win не может стричь всех под одну гребёнку – ей обязательно нужен глобальный механизм разграничения прав. Для этого, с каждым пользователем связывается такое понятие как "Сессия входа в систему", которая помещает каждого юзера в свой запечатанный "пузырь". Иными словами сессия – это граница безопасности пользователя, его собственный периметр с каменной стеной.
Например когда при вкл.машины в окне WinLogon админ указывает данные своего аккаунта (логин\пароль), ему назначается сессия(1), обычному юзеру сессия(2), гостю сессия(3), и т.д. Вообще-то сессии нумеруются по правилу "кто первым встал, того и тапки". То-есть обладателем сессии(1) становится тот, кто первым вошёл в систему, и это не обязательно должен быть админ.
Windows организована так, что в любой момент только один из пользователей может быть активным, а остальные уходят в фон на скамейку запасных. Чтобы переключиться на другую сессию и сменить пользователя, необходимо нажать комбинацию клавиш
Однако начиная с Висты, в архитектуре ОС появилась изолированная от всех сессия(0).
При загрузке системы, процесс Wininit.exe сначала создаёт нулевую сессию, внутри которой запускает все системные службы с флагом "AutoRun". Она отводится для уже знакомых нам учётных записей: System, LocalService, NetworkService, и драйвера шрифтов UMFD. В доках сессию(0) называют ещё служебной, и доступ к ней имеют только системные процессы Win.
Далее создаётся сессия(1) и управление принимает процесс WinLogon.exe, для вывода окна-входа в систему и регистрации смертных пользователей. Таким образом, в Виста+ системные службы и драйвера полностью изолированы от наших приложений уровня Win32, поскольку находятся в недоступной нам сессии(0).
Когда требуется диалог Win32-приложений с работающей в сессии(0) службой или драйвером, нам доступны только три варианта – это использование именованных каналов
На рис.ниже представлен скрин программы "ProcessHacker" где видно, что на моей системе 3 зареганых пользователя, и соответственно 4 сессии, включая изолированную(0). Именно в неё загружаются все системные файлы от имени учётных записей System, Service и Network (чтобы просмотреть файлы последних двух учёток, раскройте диспетчер служб Services.exe). В столбце "UserName" указывается имя в формате Domain\User, где NT_AUTHORITY есть домен (для сессий 1,2,3 он будет совпадать с именем компьютера). Обратите внимание, что системные файлы WinLogon и Csrss.exe копируются из ядра в каждую сессию, а токен их принадлежит учётки System. Это даёт возможность продублировать токены через DuplicateTokenEx() и попытаться запустить свой процесс с их правами CreateProcessAsUser():
Для сбора информации о сессиях можно воспользоваться функцией LsaEnumerateLogonSessions() из либы secur32.dll, с последующим вызовом в цикле LsaGetLogonSessionData(). Последняя возвращает данные в структуру "SECURITY_LOGON_SESSION_DATA" с таким содержимым:
4. Оконные станции
Теперь мы знаем, что в иерархии среды исполнения Win первыми стоят "сессии входа в систему", нулевая из которых изолирована от всех остальных. Однако чтобы у юзера была возможность отображать консольные и графические окна, одной сессии недостаточно – сессия должна иметь хотя-бы одну "оконную станцию" Window Station. Её нужно воспринимать как бокс безопасности внутри сессии, куда помещаются рабочие столы "Desktop", а в десктопах исполняются уже процессы. Тогда получаем матрёшку – сессии (сеансы) содержат одну или несколько оконных станций, и каждая станция может иметь по несколько рабочих столов: сессия --> станция --> рабочий стол.
Во-всей линейке Win предусмотрены два типа станций:
К примеру, большинство сервисов и приложений загружаются под неинтерактивной станцией
Аналогичную картину можно наблюдать и в отладчике WinDbg, потянув за его расширение !object.
На скрине выше видно, что сначала нужно запросить объект корневого каталога \Windows, и по адресу просмотреть в нём единственно вложенный дир:
Теперь зададимся вопросом, что делает внутри изолированной сессии(0) интерактивная станция "WinSta0", которая способна выводить окна и обслуживать ввод? Дело в том, что некоторым (отбившимся от стада) службам может понадобится вывести инфу в диалоговое окно – такой поворот событий предусмотрен даже в аргументе "dwServiceType" функции CreateService(). Если у службы имеется веская причина для взаимодействия с пользователем, в этом аргументе нужно указать "SERVICE_INTERACTIVE_PROCESS". Тогда диспетчер загрузит службу как и прежде в станцию
Для работы с оконными станциями имеются стандартные функции из либы User32.dll типа Open\EnumWindowStations(). Нам позволено создавать доп.станции, переключаться между ними, и всё остальное (
5. Рабочие столы "Desktop"
Прихлопнем теорию разговором о десктопах..
Под оконной станцией "Winsta0" загружаются три рабочих стола – это Winlogon (экран входа в систему), Default (рабочий стол пользователя) и если включена защищённая экранная заставка, то ScreenSaver. Каждый из них имеет свой логический дисплей, в результате чего дефолтный стол исчезает, когда мы блокируем рабочую станцию комбинацией
Объекты типа "Desktop" являются защищаемыми (в дескрипторах), и содержат в себе: консольные\графические окна, меню ОС, перехватчики Hook, а так-же "кучу" виртуальной памяти Heap. Примечательным является то, что функцией CreateDesktop() мы можем создавать доп.рабочие столы, и переключаться между ними при надобности. Например на одном столе можно собрать все ярлыки для документов, на другом – связанные с Интернетом линки и т.д. Кстати после того-как рабочий стол создан, необходимо запустить на нём процесс Explorer.exe, иначе получим абсолютное пустое окно, без панели задач и любых признаков жизни.
При создании рабочего стола он привязывается к текущей оконной станции вызывающего процесса (как правило WinSta0). Мы не можем создавать их на соседних станциях, пока не перейдём в них. От сюда следует, что посылаемые функцией SendMessage() оконные сообщения могут гулять только между процессами, которые находятся на одном рабочем столе. Это-же касается и хуков.
В любое время может быть активным только один стол, а для прыжков на другой предусмотрена функция SwitchDesktop() из либы User32.dll. Запускать процессы на произвольных столах позволяет так-же CreateProcess(), ожидая его имя в поле "lpDesktop" структуры STARTUPINFO.
Рабочий стол Winlogon остаётся активным на время аутентификации пользователя, после чего система переключает дисплей на стол Default. Дескриптор безопасности стола Winlogon запрещает обращаться к себе буквально всем учётным записям, включая System, Service и Network. Соответственно из кода своих приложений мы не сможем вызвать окно входа в систему. Переключиться на него можно только комбинациями клавиш
Если рассматривать Desktop как системный объект (каковым он и является на самом деле), то для одного объекта выделяется одна куча Heap рабочего стола. В ней и хранятся основные элементы пользовательского интерфейса типа: окна, меню и хуки. Каждый из этих элементов требует ресурсов памяти из кучи.
В ветке реестра:
Базовые функции для работы с десктопами сосредоточены в библиотеке User32.dll.
В частности EnumDesktop() возвращает список всех рабочих столов на активной станции, а помещённая внутрь её колбека функция EnumDesktopWindows() перечисляет все окна на найденном десктопе.
6. Общая картина
Чтобы зрительно сформировать законченную фейс, посмотрим на два рисунка ниже..
Значит после загрузки ОС появляется окно входа в систему Winlogon, куда юзер вводит данные своего аккаунта (в данном случае админ). Если аутентификация проходит успешно, админ получает от системы свою сессию с номером >=1. Внутри этой сессии находится обязательная интерактивная оконная станция WinSta0, и могут быть ещё несколько доп.станций. Например все браузеры на базе Хрома, создают себе станции для песочниц "Sandbox", о чём свидетельствует имя её рабочего стола. На системах Виста+ нас не ограничивают в кол-ве рабочих столов, но у сессии(1) всегда присутствуют столы Winlogon и Default.
Немного иную картину получаем при просмотре организации изолированной сессии(0).
Как уже говорилось, она отводится исключительно для системных процессов и служб – штатными средствами, для пользовательских процессов она недоступна, хотя доступ к ней получить всё-таки можно. Для этого нужно просто написать свою службу, чем мы и займёмся в следующей части(2) данной статьи.
Значит SID и токен ограничивает доступ к сессии(0), которая имеет в своей тушке аж 5 терминальных станций. Каждая из них принадлежит своей учётной записи – это System(3e7$), Services(3e5$) и Network(3e4$). Интерактивная станция WinSta0 предусмотрена для исключительных случаев, когда службе приспичит взаимодействовать с пользователем. Плохо документированная станция "mswindowstation" (судя по названию её стола) является ограниченной Restricted, например для тех служб, которые доступны анонимным юзерам (входят по сети без логин\пароля).
7. Практика – вывод инфраструктуры
Теперь немного попрактикуемся и напишем софт, который соберёт всё вышеизложенное под один капот.
Для этого задействуем следующие функции:
1. LsaEnumerateLogonSessions() из либы Secur32.dll – в аргумент "sList" возвращает массив LUID всех активных "сессий входа в систему". В аргументе "sCount" получим общее кол-во элементов в массиве. Работает только под админом, поэтому..
2. IsUserAnAdmin() из Shell32.dll – проверяет нашу тушку на админа. Возвращает EAX=1, если мы являемся таковыми.
3. LsaGetLogonSessionData() – принимая LUID от предыдущей функции, в структуру "SECURITY_LOGON_SESSION_DATA" сбрасывает общую информацию о сессии (см.описание структуры выше). Требует организации цикла, кол-во итераций которого берём из аргумента "sCount".
4. OpenProcessToken() + GetTokenInformation() из Advapi32.dll – парсим токен на идентификатор сессии(1,2,N), и кому он принадлежит (User\System).
5. NetWkstaUserGetInfo() из Netapi32.dll – возвращает в буфер имя и домен юзера.
6. GetProcessWindowStation() + GetUserObjectInformation() из User32.dll – в данном случае предоставляет SID сессии (меняется при каждой перезагрузки системы), и размер кучи стола. Последняя требует указания типа запрашиваемой инфы:
7. EnumWindowStations() + EnumDesktops() из User32.dll – перечисляет оконные станции и десктопы внутри текущей сессии. Обе возвращают инфу в свои процедуры колбек.
Как видно из краткого описания функций, LsaEnumerateLogonSessions() не дружит с юзером, а потому чтобы получить полную информацию, код нужно запускать с правами админа. Вот собственно и пример возможной реализации:
Рассмотрим этот лог под микроскопом..
Значит на моей системе Win7-SP1 имеется три интерактивных пользователя – Админ, Юзер и Гость. А вот сессий входа уже 4, включая изолированную(0). В этой "обители зла" тусуются все служебные учётки, типа System, LocalService и NetworkService. Каждой сессии назначается локальный идентификатор LUID, последние три цифры в котором совпадают с именами служебных станций "Service-0x0-3e7$" и двух остальных (см.предыдущий скрин).
Во-втором и следующих столбцах видим RID учётных записей, метод входа в систему "LogonType", и дальше имя\домен пользователя. Обратите внимание как система обзывает своих\системных юзеров в столбце "UserName" – эти имена совпадают с названием домена, который сопровождается символом($) в конце.
Далее идёт "AuthPack", что подразумевает используемый пакет авторизации. На данный момент имеется всего два варианта – это NTLM и Kerberos. Если в этом поле указывается "Negotiate", то система сама выбирает из этих двух предпочтительный вариант, исходя из своей модели безопасности. Ну и в последнем столбце лежит время, когда юзер вошёл в свою сессию. Сначала подгружается сессия(0), а за ней и все остальные.
Теперь, внутри активной сессии(1) видим две оконные станции – в данном случае всегда присутствующая интерактивная "WinSta0", и станция браузера Хром с именем "Service-0x0-27f3d$" (последнее значение меняется при каждом ребуте). В свою очередь, к WinSta0 цепляются 4 рабочих стола, 2 из которых Default и Winlogon присутствуют всегда, а 2 остальных породил софт Марка Руссиновича "Desktops". Как видим, куча Heap выделяется системой всем столам в этой станции, кроме Winlogon. Это потому, что он не имеет меню, панели задач, и вообще никаких окон, кроме окна авторизации.
А вот картинка от Win10..
Тут уже появились ещё две учётки: UMFD-х и диспетчера окон DWM.
Обратите внимание на размер хипа, который вырос с 12-ти, до ~20 МБ. Причина тому - перегруженный интерфейс пользователя на рабочем столе:
8. Заключение
Знакомство с внутренней организацией подсистемы безопасности открывает огромные перспективы. На фоне рассмотренных здесь пользовательских сессий, наружу всплывают токены, а это уже абсолютно другой уровень взаимодействия с OC. В следующей части будет предпринята попытка грабежа этих токенов у системных процессов, с целью модификации их под себя. При удачных обстоятельствах, это позволит запускать свои процессы от имени системы, что откроет доступ к изолированной сессии(0). Не останутся в стороне и службы, на которые сделаем основную ставку. Держите руку на пульсе..
В скрепку кладу исполняемый файл для тестов, и необходимые для сборки исходника, пару инклудов.
Всем удачи, пока!
Оглавление:
1. Вводная часть
2. Учётные записи: System, LocalService, NetworkService
3. Сессии входа в систему
4. Оконные станции
5. Рабочие столы
6. Общая картина
7. Практика – вывод инфраструктуры
8. Заключение.
1. Введение (в заблуждение)
Работа сервисов тесно связана с такими понятиями как: сессии входа в систему, оконные\терминальные станции, и рабочие столы "Desktop". По сути, эта триада представляет собой рабочее окружение всей исполняемой среды Win, так-что для полноты картины имеет смысл дать ей определение. Здесь нужно отметить, что тема довольно мутная, а её разбор и понимание усугубляет то, что начиная с Висты внутренняя архитектура претерпела огромные изменения. Более того, некоторые сюрпризы в этом плане подвезли и в десятку (например виртуальные десктопы Win10), а значит и новшества Висты уже устарели.
Но не всё так плохо, поскольку общие принципы и фундамент остался прежним – из крана с идеями уже не бьёт как прежде струя, и нам будут подкидывать мелкие крапаля ещё довольно долго. Просто Microsoft в своём стиле навешивает на старый позвоночник никому не нужные аппендиксы, выдавая их за нечто новое (а как иначе продать товар?). Далее по тексту, отличительные особенности разных ОС будут выноситься в сноски, оставляя свободу основным моментам организации исполняемой среды.
2. Учётные записи пользователей
Windows изначально проектировалась как много-пользовательская ОС. Пользователь считается легальным, если в разделе реестра HKEY_USERS для него создана своя учётная запись. Отвечающий за безопасность компонент ядра LSASS не использует имена юзеров в привычном нам строковом виде, а при вводе данных аккаунта в окне WinLogon, назначает им идентификатор безопасности SID (Security Identifier), после чего формирует для данного SID маркер-доступа к различным объектам ACCESS_TOKEN (защищённые объекты ожидают пользовательский SID в своих списках DACL). Таким образом, каждый из прошедших проверку пользователей, должен иметь свою учётную запись, SID и токен.
В контексте данной статьи мы сконцентрируем своё внимание на токене, поскольку именно он определяет привилегии, а так-же служит мандатом при попытке доступа к буквально всем объектам системы, например службам, процессам, файлам, и т.д. Если повезёт утянуть токен у пользователя System, мы получим полную власть над системой, оставив даже админа нервно курить в сторонке. Для этого, открывается какой-либо системный процесс функцией OpenProcess(), далее запрашивается его маркер безопасности через OpenProcessToken(), и с полученного токена снимается ксерокопия DuplicateTokenEx() с флагом "TOKEN_PRIMARY". Поскольку дескрипторы процессов наследуются от родителей, теперь мы сможем запустить любой код от имени пользователя System функцией CreateProcessAsUser(), которая требует в первом аргументе именно токен юзверя.
Помимо знакомых большинству из нас учётных записей типа Admin, User, Guest (им назначается SID = S-1-5-21-x-y-z), в системе имеются ещё как-минимум 4 перечисленных ниже скрытых пользователя, которые заслужено привлекают к себе внимание (для них последние числа 7,18,19,21 и т.д. известны как RID, или относительный RelativeID):
1. Пользователь System с неограниченными правами (иногда LocalSystem):
SID = S-1-5-18
;2. LocalService, под которой исполняются все сервисы на локальном узле:
SID = S-1-5-19
;3. NetworkService, для обслуживания сети и удалённого доступа к системе:
SID = S-1-5-20
;4. Anonymous, анонимный вход по сети без указания логин\пароля, а потому ограниченный:
SID = S-1-5-7
;Если зайти в раздел реестра HKEY_USERS, можно обнаружить там подразделы для этих учётных записей.
Что касается Win-10, то в ней к уже имеющимся, присавокупились ещё две учётки:
5. DWM, компонент "диспетчера окон рабочего стола" и его системных служб (Desktop Window Manager,
SID = S-1-5-90
);6. UMFD, что подразумевает "User Mode Font Driver" (компонент среды разработки DriverFramework,
SID = S-1-5-96
).Более развёрнутую информацию по теме можно найти на сайте MSDN по
Ссылка скрыта от гостей
.
C-подобный:
lkd> dt _token
nt!_TOKEN
+0x000 TokenSource : _TOKEN_SOURCE
+0x010 TokenId : _LUID
+0x018 AuthenticationId : _LUID
+0x020 ParentTokenId : _LUID
+0x028 ExpirationTime : _LARGE_INTEGER
+0x030 TokenLock : Ptr32 _ERESOURCE
+0x034 ModifiedId : _LUID
+0x040 Privileges : _SEP_TOKEN_PRIVILEGES
+0x058 AuditPolicy : _SEP_AUDIT_POLICY
+0x074 SessionId : Uint4B
+0x078 UserAndGroupCount : Uint4B
+0x07c RestrictedSidCount : Uint4B
+0x080 VariableLength : Uint4B
+0x084 DynamicCharged : Uint4B
+0x088 DynamicAvailable : Uint4B
+0x08c DefaultOwnerIndex : Uint4B
+0x090 UserAndGroups : Ptr32 _SID_AND_ATTRIBUTES
+0x094 RestrictedSids : Ptr32 _SID_AND_ATTRIBUTES
+0x098 PrimaryGroup : Ptr32 Void
+0x09c DynamicPart : Ptr32 Uint4B
+0x0a0 DefaultDacl : Ptr32 _ACL
+0x0a4 TokenType : _TOKEN_TYPE
+0x0a8 ImpersonationLevel : _SECURITY_IMPERSONATION_LEVEL
+0x0ac TokenFlags : Uint4B
+0x0b0 TokenInUse : UChar
+0x0b4 IntegrityLevelIndex : Uint4B
+0x0b8 MandatoryPolicy : Uint4B
+0x0bc LogonSession : Ptr32 _SEP_LOGON_SESSION_REFERENCES
+0x0c0 OriginatingLogonSession : _LUID
+0x0c8 SidHash : _SID_AND_ATTRIBUTES_HASH
+0x150 RestrictedSidHash : _SID_AND_ATTRIBUTES_HASH
+0x1d8 pSecurityAttributes : Ptr32 _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION
+0x1dc SessionObject : Ptr32 Void
+0x1e0 VariablePart : Uint4B
3. Сессии входа в систему
В силу того, что каждый зареганый пользователь имеет свой SID, привилегии, и права на доступ к объектам, подсистема безопасности Win не может стричь всех под одну гребёнку – ей обязательно нужен глобальный механизм разграничения прав. Для этого, с каждым пользователем связывается такое понятие как "Сессия входа в систему", которая помещает каждого юзера в свой запечатанный "пузырь". Иными словами сессия – это граница безопасности пользователя, его собственный периметр с каменной стеной.
Например когда при вкл.машины в окне WinLogon админ указывает данные своего аккаунта (логин\пароль), ему назначается сессия(1), обычному юзеру сессия(2), гостю сессия(3), и т.д. Вообще-то сессии нумеруются по правилу "кто первым встал, того и тапки". То-есть обладателем сессии(1) становится тот, кто первым вошёл в систему, и это не обязательно должен быть админ.
Windows организована так, что в любой момент только один из пользователей может быть активным, а остальные уходят в фон на скамейку запасных. Чтобы переключиться на другую сессию и сменить пользователя, необходимо нажать комбинацию клавиш
Ctrl+Alt-Delete
(или Win+L), что пробудит процесс Winlogon.exe, и он тут-же отзовётся своим окном Logon. При этом активная сессия отправится на покой, а её место займёт сессия выбранной учётной записи.Однако начиная с Висты, в архитектуре ОС появилась изолированная от всех сессия(0).
При загрузке системы, процесс Wininit.exe сначала создаёт нулевую сессию, внутри которой запускает все системные службы с флагом "AutoRun". Она отводится для уже знакомых нам учётных записей: System, LocalService, NetworkService, и драйвера шрифтов UMFD. В доках сессию(0) называют ещё служебной, и доступ к ней имеют только системные процессы Win.
Далее создаётся сессия(1) и управление принимает процесс WinLogon.exe, для вывода окна-входа в систему и регистрации смертных пользователей. Таким образом, в Виста+ системные службы и драйвера полностью изолированы от наших приложений уровня Win32, поскольку находятся в недоступной нам сессии(0).
Примечание:
Изоляция сеанса(0) отсутствует в более ранних версиях ОС, включая Win-XP и сервер 2003.
В них до служб можно было дотянуться рукой, поскольку работали они внутри одной сессии с юзермодными приложениями.
Это было огромной дырой, и угрожало всей подсистеме безопасности Windows.
Когда требуется диалог Win32-приложений с работающей в сессии(0) службой или драйвером, нам доступны только три варианта – это использование именованных каналов
Ссылка скрыта от гостей
, системных сокетов, и глобальных событий "Event". Это означает, что при взаимодействии между сессиями, мы лишены возможности посылать привычные нам оконные сообщения при помощи SendMessage(). На Виста+ сами по себе отваливаются и меж-сессионные хуки, которые часто применялись в кейлогерах ХР, чтобы перехватить ввод паролей в окне WinLogon. Так-что от изоляции сеанса\сессии(0) одни плюсы, хотя это зависит от того, на чьей стороне мы воюем.На рис.ниже представлен скрин программы "ProcessHacker" где видно, что на моей системе 3 зареганых пользователя, и соответственно 4 сессии, включая изолированную(0). Именно в неё загружаются все системные файлы от имени учётных записей System, Service и Network (чтобы просмотреть файлы последних двух учёток, раскройте диспетчер служб Services.exe). В столбце "UserName" указывается имя в формате Domain\User, где NT_AUTHORITY есть домен (для сессий 1,2,3 он будет совпадать с именем компьютера). Обратите внимание, что системные файлы WinLogon и Csrss.exe копируются из ядра в каждую сессию, а токен их принадлежит учётки System. Это даёт возможность продублировать токены через DuplicateTokenEx() и попытаться запустить свой процесс с их правами CreateProcessAsUser():
Для сбора информации о сессиях можно воспользоваться функцией LsaEnumerateLogonSessions() из либы secur32.dll, с последующим вызовом в цикле LsaGetLogonSessionData(). Последняя возвращает данные в структуру "SECURITY_LOGON_SESSION_DATA" с таким содержимым:
C-подобный:
struct SECURITY_LOGON_SESSION_DATA
Size dd 0 ;// размер этой структуры (sizeof.SECURITY_LOGON_SESSION_DATA)
LogonId dq 0 ;// LUID (64-бит LocalUniqueID) сеанса входа в систему
UserName LSA_UNICODE_STRING ;// имя учетной записи, которому принадлежит сеанс входа в систему
LogonDomain LSA_UNICODE_STRING ;// имя домена, для аутентификации владельца сеанса
AuthenticationPackage LSA_UNICODE_STRING ;// имя пакета проверки подлинности, для проверки владельца сеанса
LogonType dd 0 ;// метод входа в систему (см.SECURITY_LOGON_TYPE)
Session dd 0 ;// идентификатор сеанса\сессии (0,1,2,3)
Sid dd 0 ;// указатель на SID пользователя
LogonTime dq 0 ;// время, когда владелец сеанса вошёл в систему (тип FILETIME)
LogonServer LSA_UNICODE_STRING ;// имя сервера, используемого для аутентификации владельца
DnsDomainName LSA_UNICODE_STRING ;// DNS-имя владельца сеанса
Upn LSA_UNICODE_STRING ;// имя участника-пользователя (UPN) для владельца сеанса
UserFlags dd 0 ;// пользователь отмечает сеанс входа
LastLogonInfo LSA_LAST_INTER_LOGON_INFO ;// прочая инфа
LogonScript LSA_UNICODE_STRING ;//
ProfilePath LSA_UNICODE_STRING ;//
HomeDirectory LSA_UNICODE_STRING ;//
HomeDirectoryDrive LSA_UNICODE_STRING ;//
LogoffTime dq 0 ;// время, когда владелец сеанса вышел из системы
KickOffTime dq 0 ;// время, в течение которого должен завершиться сеанс входа в систему.
PasswordLastSet dq 0 ;// время последней смены пользователем пароля
PasswordCanChange dq 0 ;// пароль можно изменить во время сеанса входа в систему
PasswordMustChange dq 0 ;// пароль должен быть изменен во время сеанса входа в систему
ends
4. Оконные станции
Теперь мы знаем, что в иерархии среды исполнения Win первыми стоят "сессии входа в систему", нулевая из которых изолирована от всех остальных. Однако чтобы у юзера была возможность отображать консольные и графические окна, одной сессии недостаточно – сессия должна иметь хотя-бы одну "оконную станцию" Window Station. Её нужно воспринимать как бокс безопасности внутри сессии, куда помещаются рабочие столы "Desktop", а в десктопах исполняются уже процессы. Тогда получаем матрёшку – сессии (сеансы) содержат одну или несколько оконных станций, и каждая станция может иметь по несколько рабочих столов: сессия --> станция --> рабочий стол.
Во-всей линейке Win предусмотрены два типа станций:
1. Интерактивные, которые могут отображать окна и прочий гуй на своём рабочем столе, а так-же принимать клавиатурный ввод от пользователя. Как правило, для неё всегда отводится статичное имя "WinSta0". Каждая сессия входа в систему получает в своё распоряжение одну WinSta0 - она содержит клавиатуру, мышь и устройство отображения.
2. Не интерактивные станции. Этот тип не способен отображать вообще никакие окна, и обрабатывать какой-бы то ни было пользовательский ввод. Попытка вывести, например, MessageBox() в неинтерактивную станцию заранее обречена на провал, т.к. диспетчер окон тут-же посылает окну сообщение ID_OK, и не успев даже сделать вздох окно закрывается. Так повелось, что клиентами подобного рода станций являются системные службы – они изначально не расположены на общение с юзером, и сосредоточены чисто на узкопрофильных своих задачах.
К примеру, большинство сервисов и приложений загружаются под неинтерактивной станцией
Service-0x0-3e7$
в изолированной сессии(0) учётной записи System. В то-же время для юзверя LocalService отводится своя станция Service-0x0-3e5$
в той-же сессии(0), а на растерзание службам сетевого аккаунта Network отдаётся Service-0x0-3e4$
. Тогда получается, что внутри служебной сессии(0) живут аж 5 самостоятельных станций, и лишь одна из них "WinSta0" интерактивна. Вот что думает на этот счёт вьювер объектов от крутого прогера Four-F (на сайте wasm.in можно найти массу его статей):Аналогичную картину можно наблюдать и в отладчике WinDbg, потянув за его расширение !object.
На скрине выше видно, что сначала нужно запросить объект корневого каталога \Windows, и по адресу просмотреть в нём единственно вложенный дир:
Код:
lkd> !object \Windows
Object: 85fad8d8 Type: (847ca778) Directory
ObjectHeader: 85fad8c0 (new version)
HandleCount : 1 PointerCount: 6
ObjectDir : 85e05f50 Name: Windows
Hash Address Type Name
---- ------- ---- ----
04 8665ead0 ALPC Port SbApiPort
09 8665ef00 ALPC Port ApiPort
14 91a68980 Section SharedSection
32 8b1a8f50 Directory WindowStations <----- Наш клиент
lkd> !object 8b1a8f50
Object: 8b1a8f50 Type: (847ca778) Directory
ObjectHeader: 8b1a8f38 (new version)
HandleCount : 1 PointerCount: 7
ObjectDir : 85fad8d8 Name: WindowStations
Hash Address Type Name
---- ------- ---- ----
01 86727390 WindowStation Service-0x0-3e4$
04 8674e690 WindowStation Service-0x0-3e5$
06 8a133db8 WindowStation msswindowstation
11 866a77c8 WindowStation Service-0x0-3e7$
27 86676c68 WindowStation WinSta0
Теперь зададимся вопросом, что делает внутри изолированной сессии(0) интерактивная станция "WinSta0", которая способна выводить окна и обслуживать ввод? Дело в том, что некоторым (отбившимся от стада) службам может понадобится вывести инфу в диалоговое окно – такой поворот событий предусмотрен даже в аргументе "dwServiceType" функции CreateService(). Если у службы имеется веская причина для взаимодействия с пользователем, в этом аргументе нужно указать "SERVICE_INTERACTIVE_PROCESS". Тогда диспетчер загрузит службу как и прежде в станцию
Service-0x0-3e7$
сессии зеро, но в момент отображения ею окна, переключит станцию на нашу интерактивную WinSta0 (для этого должен быть активным сервис UI0Detect.exe, см.ProcessHacker или диспетчер задач).Для работы с оконными станциями имеются стандартные функции из либы User32.dll типа Open\EnumWindowStations(). Нам позволено создавать доп.станции, переключаться между ними, и всё остальное (
Ссылка скрыта от гостей
), но только внутри своей сессии входа в систему. Штатными средствами, чужая сессия закрыта для нас на амбарный замок! Более того, Win комплектуется бронебойной библиотекой расширенных возможностей Winsta.dll, с порядка 140 функциями на борту. Правда на MSDN она не документирована от слова вообще, но в репозиториях ReactOS можно найти вполне вменяемый перечень аргументов её основных функций.5. Рабочие столы "Desktop"
Прихлопнем теорию разговором о десктопах..
Под оконной станцией "Winsta0" загружаются три рабочих стола – это Winlogon (экран входа в систему), Default (рабочий стол пользователя) и если включена защищённая экранная заставка, то ScreenSaver. Каждый из них имеет свой логический дисплей, в результате чего дефолтный стол исчезает, когда мы блокируем рабочую станцию комбинацией
Win+L
, или жмём аккорд Ctrl+Alt+Del
. Блокирование станций приводит к тому, что дисплей переключается с Default на Winlogon, катапультируя нас с одного измерения, в другое.Объекты типа "Desktop" являются защищаемыми (в дескрипторах), и содержат в себе: консольные\графические окна, меню ОС, перехватчики Hook, а так-же "кучу" виртуальной памяти Heap. Примечательным является то, что функцией CreateDesktop() мы можем создавать доп.рабочие столы, и переключаться между ними при надобности. Например на одном столе можно собрать все ярлыки для документов, на другом – связанные с Интернетом линки и т.д. Кстати после того-как рабочий стол создан, необходимо запустить на нём процесс Explorer.exe, иначе получим абсолютное пустое окно, без панели задач и любых признаков жизни.
Примечание:
Win10 принесла с собой виртуальные рабочие столы.
Они отличаются тем, что стол фактически не создаётся функцией CreateDesktop(),
а драйвер графической подсистемы Win32k.sys просто манипулирует видимостью окон.
В отличие от физ.десктопов Висты, бутафорские в Win10 предназначены не для обеспечения безопасности, а для удобства.
Инструмент под названием "Desktops" из пакета Sysinternals позволяет создавать до 4-х физ.столов.
При создании рабочего стола он привязывается к текущей оконной станции вызывающего процесса (как правило WinSta0). Мы не можем создавать их на соседних станциях, пока не перейдём в них. От сюда следует, что посылаемые функцией SendMessage() оконные сообщения могут гулять только между процессами, которые находятся на одном рабочем столе. Это-же касается и хуков.
В любое время может быть активным только один стол, а для прыжков на другой предусмотрена функция SwitchDesktop() из либы User32.dll. Запускать процессы на произвольных столах позволяет так-же CreateProcess(), ожидая его имя в поле "lpDesktop" структуры STARTUPINFO.
Рабочий стол Winlogon остаётся активным на время аутентификации пользователя, после чего система переключает дисплей на стол Default. Дескриптор безопасности стола Winlogon запрещает обращаться к себе буквально всем учётным записям, включая System, Service и Network. Соответственно из кода своих приложений мы не сможем вызвать окно входа в систему. Переключиться на него можно только комбинациями клавиш
Win+L
или Ctrl+Alt+Del
, которые перехватывает процесс подсистемы безопасности Lsass.exe.Если рассматривать Desktop как системный объект (каковым он и является на самом деле), то для одного объекта выделяется одна куча Heap рабочего стола. В ней и хранятся основные элементы пользовательского интерфейса типа: окна, меню и хуки. Каждый из этих элементов требует ресурсов памяти из кучи.
Примечание:
На системах ХР, для кучи стола отводилось в ядре фиксированное пространство размером 48 МБ.
Поскольку данная память была общим пулом для всех десктопов внутри одной станции,
это накладывало отпечаток на общее кол-во создаваемых рабочих столов функцией CreateDesktop().
В системах на ядре NT6 (от Виста до Win8) память для кучи столов выделяется динамически, и ограничения в 48 МБ уже нет.
В ветке реестра:
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems
присутствует ключ Windows, со-строковым параметром "SharedSection". Три значения в нём определяют, сколько памяти в КБайтах выделяется куче. На своей Win7 я получил следующий лимит: 1024,12288,512.• 1024 – это общий для всех столов размер кучи (внутри одной станции). Отводится под глобальную таблицу дескрипторов и общих настроек.
• 12288 – размер кучи рабочего стола Default в интерактивной станции "WinSta0". Здесь уже хранятся объекты юзера, типа хуки, меню, и окна.
• 512 – размер кучи для каждого стола в неинтерактивных оконных станциях, изолированной сессии(0).
Базовые функции для работы с десктопами сосредоточены в библиотеке User32.dll.
В частности EnumDesktop() возвращает список всех рабочих столов на активной станции, а помещённая внутрь её колбека функция EnumDesktopWindows() перечисляет все окна на найденном десктопе.
6. Общая картина
Чтобы зрительно сформировать законченную фейс, посмотрим на два рисунка ниже..
Значит после загрузки ОС появляется окно входа в систему Winlogon, куда юзер вводит данные своего аккаунта (в данном случае админ). Если аутентификация проходит успешно, админ получает от системы свою сессию с номером >=1. Внутри этой сессии находится обязательная интерактивная оконная станция WinSta0, и могут быть ещё несколько доп.станций. Например все браузеры на базе Хрома, создают себе станции для песочниц "Sandbox", о чём свидетельствует имя её рабочего стола. На системах Виста+ нас не ограничивают в кол-ве рабочих столов, но у сессии(1) всегда присутствуют столы Winlogon и Default.
Немного иную картину получаем при просмотре организации изолированной сессии(0).
Как уже говорилось, она отводится исключительно для системных процессов и служб – штатными средствами, для пользовательских процессов она недоступна, хотя доступ к ней получить всё-таки можно. Для этого нужно просто написать свою службу, чем мы и займёмся в следующей части(2) данной статьи.
Значит SID и токен ограничивает доступ к сессии(0), которая имеет в своей тушке аж 5 терминальных станций. Каждая из них принадлежит своей учётной записи – это System(3e7$), Services(3e5$) и Network(3e4$). Интерактивная станция WinSta0 предусмотрена для исключительных случаев, когда службе приспичит взаимодействовать с пользователем. Плохо документированная станция "mswindowstation" (судя по названию её стола) является ограниченной Restricted, например для тех служб, которые доступны анонимным юзерам (входят по сети без логин\пароля).
7. Практика – вывод инфраструктуры
Теперь немного попрактикуемся и напишем софт, который соберёт всё вышеизложенное под один капот.
Для этого задействуем следующие функции:
1. LsaEnumerateLogonSessions() из либы Secur32.dll – в аргумент "sList" возвращает массив LUID всех активных "сессий входа в систему". В аргументе "sCount" получим общее кол-во элементов в массиве. Работает только под админом, поэтому..
2. IsUserAnAdmin() из Shell32.dll – проверяет нашу тушку на админа. Возвращает EAX=1, если мы являемся таковыми.
3. LsaGetLogonSessionData() – принимая LUID от предыдущей функции, в структуру "SECURITY_LOGON_SESSION_DATA" сбрасывает общую информацию о сессии (см.описание структуры выше). Требует организации цикла, кол-во итераций которого берём из аргумента "sCount".
4. OpenProcessToken() + GetTokenInformation() из Advapi32.dll – парсим токен на идентификатор сессии(1,2,N), и кому он принадлежит (User\System).
5. NetWkstaUserGetInfo() из Netapi32.dll – возвращает в буфер имя и домен юзера.
6. GetProcessWindowStation() + GetUserObjectInformation() из User32.dll – в данном случае предоставляет SID сессии (меняется при каждой перезагрузки системы), и размер кучи стола. Последняя требует указания типа запрашиваемой инфы:
C-подобный:
UOI_FLAGS = 1 ;// см.структуру USEROBJECTFLAGS
UOI_NAME = 2 ;// имя объекта в виде строки
UOI_TYPE = 3 ;// имя типа-объекта в виде строки
UOI_USER_SID = 4 ;// SID пользователя, который в данный момент связан с указанным объектом
UOI_HEAPSIZE = 5 ;// размер кучи рабочего стола в КБ в виде значения ULONG
UOI_IO = 6 ;// TRUE, если станция\раб.стол интерактивный
7. EnumWindowStations() + EnumDesktops() из User32.dll – перечисляет оконные станции и десктопы внутри текущей сессии. Обе возвращают инфу в свои процедуры колбек.
Как видно из краткого описания функций, LsaEnumerateLogonSessions() не дружит с юзером, а потому чтобы получить полную информацию, код нужно запускать с правами админа. Вот собственно и пример возможной реализации:
C-подобный:
format pe console
include 'win32ax.inc'
entry start
;//----------
.data
logonTable dd lt00,lt01,lt02,lt03,lt04,lt05,lt06
dd lt07,lt08,lt09,lt10,lt11,lt12,lt13
lt00 db '0 (SYSTEM)',0
lt01 db '1 (Undefined)',0
lt02 db '2 (Interactive)',0
lt03 db '3 (Network)',0
lt04 db '4 (Batch)',0
lt05 db '5 (Service)',0
lt06 db '6 (Proxy)',0
lt07 db '7 (Unlock)',0
lt08 db '8 (NetworkCleartext)',0
lt09 db '9 (NewCredentials)',0
lt10 db '10 (RemoteInteractive)',0
lt11 db '11 (CachedInteractive)',0
lt12 db '12 (CachedRemoteInteractive)',0
lt13 db '13 (CachedUnlock)',0
align 16
userName rb 32
source rb 16
pcbBytesNeeded dd 0
sCount dd 0
sList dd 0
hToken dd 0
sessionId dd 0
buff db 0
;//----------
.code
;//*********************************************************
;//---------- CALLBACK ПРОЦЕДУРЫ ---------------------------
;//*********************************************************
proc WinStaCallback lpszWinSta,lParam
cinvoke printf,<10,10,' Station: %s',0>,[lpszWinSta]
invoke OpenWindowStation,[lpszWinSta], FALSE, READ_CONTROL + WINSTA_ENUMDESKTOPS
push eax
invoke EnumDesktops,eax,EnumDeskCallback,0
pop eax
invoke CloseWindowStation,eax
ret
endp
proc EnumDeskCallback lpszDesktop,lParam
cinvoke printf,<10,17 dup(' '),'|----> Desktop: \%-10s',0>,[lpszDesktop]
invoke OpenDesktop,[lpszDesktop],0,FALSE,GENERIC_READ
push eax
mov dword[buff],0
invoke GetUserObjectInformation,eax,UOI_HEAPSIZE,buff,4,pcbBytesNeeded
cinvoke printf,<' --> Heap: %d Kb',0>,dword[buff]
pop eax
invoke CloseDesktop,eax
ret
endp
;//*********************************************************
;//---------- ТОЧКА ВХОДА В ПРОГРАММУ ----------------------
;//*********************************************************
align 16
start: invoke SetConsoleTitle,<'*** Session info ***',0>
invoke LsaEnumerateLogonSessions,sCount,sList ;// EAX=1 ошибка
or eax,eax
je @f
cinvoke printf,<10,' ERROR LsaEnumerateLogonSession()...',0>
jmp @exit
@@: push [sList]
cinvoke printf,<10,' LUID SecurRID LogonType UserName ',\
' LogonDomain AuthPack LogonTime',\
10,14 dup(' '),105 dup('-'),0>
;//----- Тест на админа! -------------
invoke IsUserAnAdmin ;// админ: EAX=1
or eax,eax
jz @user
;//----- Запрашиваем данные очередной сессии ------------
@@: invoke LsaGetLogonSessionData,[sList],buff
mov esi,dword[buff]
mov eax,[esi + SECURITY_LOGON_SESSION_DATA.UserName+4]
cmp word[eax],0
je @fuck
push esi
invoke CharToOemW,eax,buff ;// для вывода кирилицы на консоль
pop esi
mov eax,[sList]
mov eax,[eax]
mov ebx,[esi + SECURITY_LOGON_SESSION_DATA.LogonType]
shl ebx,2
mov edi,logonTable
add edi,ebx
mov ebx,[edi]
mov ecx,[esi + SECURITY_LOGON_SESSION_DATA.Sid]
push esi esi eax ebx ecx
invoke ConvertSidToStringSid,ecx,ecx ;// SID в строку
pop ecx ebx eax esi
cinvoke printf,<10,' Session(%d): %08x %-8.8s %-16s %-20s %-20ls %-11ls',0>,\
dword[esi + SECURITY_LOGON_SESSION_DATA.Session],eax,dword[ecx],ebx,buff,\
dword[esi + SECURITY_LOGON_SESSION_DATA.LogonDomain+4],\
dword[esi + SECURITY_LOGON_SESSION_DATA.AuthenticationPackage+4]
pop esi
add esi,SECURITY_LOGON_SESSION_DATA.LogonTime
invoke FileTimeToSystemTime,esi,buff
movzx eax,word[buff+8]
movzx ebx,word[buff+10]
movzx ecx,word[buff+12]
cinvoke printf,<' %02d:%02d:%02d',0>,eax,ebx,ecx ;//<----- время входа в сессию
@fuck: add [sList],8 ;// следующий 64-бит LUID из массива..
dec [sCount] ;// весь массив обошли?
jnz @b
pop eax
invoke LsaFreeReturnBuffer,eax
cinvoke printf,<10,14 dup(' '),105 dup('-'),0>
;//----- Если нет админских прав, блок выше не отображается ---------
@user: mov ecx,128
mov edi,buff
xor eax,eax
rep stosd ;// Очистить служебный буфер
;//*********************************************************
;//---------- ИНФОРМАЦИЯ О ТЕКУЩЕЙ СЕССИИ ------------------
;//*********************************************************
invoke OpenProcessToken,-1,GENERIC_READ,hToken
invoke GetTokenInformation,[hToken],TokenSessionId,sessionId,4,pcbBytesNeeded
invoke GetTokenInformation,[hToken],TokenSource,source,16,pcbBytesNeeded
invoke NetWkstaUserGetInfo,0,1,buff
mov esi,dword[buff]
mov eax,[esi + WKSTA_USER_INFO_1.username]
invoke CharToOemW,eax,userName
mov ebx,[esi + WKSTA_USER_INFO_1.logon_domain]
cinvoke printf,<10,10,' Active session info...',\
10,' ID: %d',\
10,' Logon: %s \ %ls',0>,[sessionId],userName,ebx
invoke GetProcessWindowStation
invoke GetUserObjectInformation,eax,UOI_USER_SID,buff,128,pcbBytesNeeded
invoke ConvertSidToStringSid,buff,buff
cinvoke printf,< 10,' SID: %s',\
10,' Token: %s',0>,dword[buff],source
;//----- Перечисляем станции и их рабочие столы -----------------------
invoke EnumWindowStations,WinStaCallback,0
@exit: cinvoke _getch ;// клавиша
cinvoke exit,0 ;// выход!
;//----------
section '.idata' import data readable
library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',netapi32,'Netapi32.dll',\
user32,'user32.dll',secur32,'secur32.dll',advapi32,'advapi32.dll',shell32,'shell32.dll'
import shell32,IsUserAnAdmin,'IsUserAnAdmin'
import secur32,LsaEnumerateLogonSessions,'LsaEnumerateLogonSessions',\
LsaGetLogonSessionData,'LsaGetLogonSessionData',\
LsaFreeReturnBuffer,'LsaFreeReturnBuffer'
import netapi32,NetWkstaUserGetInfo,'NetWkstaUserGetInfo'
include 'api\msvcrt.inc'
include 'api\kernel32.inc'
include 'api\user32.inc'
include 'api\advapi32.inc'
include 'equates\scm.inc'
include 'equates\advapi32.inc'
Рассмотрим этот лог под микроскопом..
Значит на моей системе Win7-SP1 имеется три интерактивных пользователя – Админ, Юзер и Гость. А вот сессий входа уже 4, включая изолированную(0). В этой "обители зла" тусуются все служебные учётки, типа System, LocalService и NetworkService. Каждой сессии назначается локальный идентификатор LUID, последние три цифры в котором совпадают с именами служебных станций "Service-0x0-3e7$" и двух остальных (см.предыдущий скрин).
Во-втором и следующих столбцах видим RID учётных записей, метод входа в систему "LogonType", и дальше имя\домен пользователя. Обратите внимание как система обзывает своих\системных юзеров в столбце "UserName" – эти имена совпадают с названием домена, который сопровождается символом($) в конце.
Далее идёт "AuthPack", что подразумевает используемый пакет авторизации. На данный момент имеется всего два варианта – это NTLM и Kerberos. Если в этом поле указывается "Negotiate", то система сама выбирает из этих двух предпочтительный вариант, исходя из своей модели безопасности. Ну и в последнем столбце лежит время, когда юзер вошёл в свою сессию. Сначала подгружается сессия(0), а за ней и все остальные.
Теперь, внутри активной сессии(1) видим две оконные станции – в данном случае всегда присутствующая интерактивная "WinSta0", и станция браузера Хром с именем "Service-0x0-27f3d$" (последнее значение меняется при каждом ребуте). В свою очередь, к WinSta0 цепляются 4 рабочих стола, 2 из которых Default и Winlogon присутствуют всегда, а 2 остальных породил софт Марка Руссиновича "Desktops". Как видим, куча Heap выделяется системой всем столам в этой станции, кроме Winlogon. Это потому, что он не имеет меню, панели задач, и вообще никаких окон, кроме окна авторизации.
А вот картинка от Win10..
Тут уже появились ещё две учётки: UMFD-х и диспетчера окон DWM.
Обратите внимание на размер хипа, который вырос с 12-ти, до ~20 МБ. Причина тому - перегруженный интерфейс пользователя на рабочем столе:
8. Заключение
Знакомство с внутренней организацией подсистемы безопасности открывает огромные перспективы. На фоне рассмотренных здесь пользовательских сессий, наружу всплывают токены, а это уже абсолютно другой уровень взаимодействия с OC. В следующей части будет предпринята попытка грабежа этих токенов у системных процессов, с целью модификации их под себя. При удачных обстоятельствах, это позволит запускать свои процессы от имени системы, что откроет доступ к изолированной сессии(0). Не останутся в стороне и службы, на которые сделаем основную ставку. Держите руку на пульсе..
В скрепку кладу исполняемый файл для тестов, и необходимые для сборки исходника, пару инклудов.
Всем удачи, пока!