Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Альтернативное детектирование терминальной сессии


Rouse_ ©   (05.03.19 10:17

Приветствую, задача такая, необходимо как-то надежно задетектировать что приложение находится под терминальной сессией.
Как это делается штатным способом: через вызов GetSystemMetrics(SM_REMOTESESSION).

Что происходит в этом случае:
Windows проверяет наличие данных в PEB->SharedData, если эти эти данные есть, то берет ID сессии оттуда, если нет, то берет ID текущей сессии из PEB->SessionId. Далее проверяется - если ID равен нулю, то терминальной сессии нет.
Если получен ID сессии отличный от нуля, то это число сверяется с тем, которое записано в KE_USER_SHARED_DATA -> ActiveConsoleId. Если значения двух чисел совпали, то терминальной сессии нет.

Проблема в том что такой детект отключается легко, т.к. PEB доступен на перезапись извне и достаточно обнулить PEB->SharedData + PEB->SessionId получив его адрес через NtQueryInformationProcess с флагами ProcessWow64Information/ProcessBasicInformation и считав поле PebBaseAddress, а потом произвести вызов WriteProcessMemory.

Соответственно вопрос: кто какие еще знает способы детектирования терминальной сессии?


Rouse_ ©   (05.03.19 10:21[1]

Пока что единственный альтернативный вариант приходящий в голову, это найти любой сторонний процесс в рамках текущей WinStaX и считать эти поля оттуда. Но что-то мне кажется что есть еще какие либо изменения с системных структурах, куда можно подсмотреть, в которых происходят изменения в случае работы под терминалом.


dmk ©   (05.03.19 22:13[2]

Может энвироменты висят какие или атомы?


Rouse_ ©   (06.03.19 06:54[3]

Енвиронменты тоже в памяти сидят и доступны на перезапись, а вот с атомами мысль. Спасибо - гляну.


han_malign ©   (06.03.19 16:15[4]

драйвер экрана?

TokenSessionId, TokenGroups:SECURITY_TERMINAL_SERVER_RID/SECURITY_LOGON_IDS_RID, etc. - судя по PEB - не вариант(SE_TCB_NAME)...

И ни разу не интересовался - откуда WTSQuerySessionInformation берёт WTS_CURRENT_SESSION, но судя по примечанию не из того же...
To retrieve the session ID for the current session when Remote Desktop Services is running, call WTSQuerySessionInformation and specify WTS_CURRENT_SESSION for the SessionId parameter and WTSSessionId for the WTSInfoClass parameter. The session ID will be returned in the ppBuffer parameter. If Remote Desktop Services is not running, calls to WTSQuerySessionInformation fail. In this situation, you can retrieve the current session ID by calling the ProcessIdToSessionId function.

To determine whether your application is running on the physical console, you must specify WTS_CURRENT_SESSION for the SessionId parameter, and WTSClientProtocolType as the WTSInfoClass parameter. If ppBuffer is "0", the session is attached to the physical console.


Rouse_ ©   (07.03.19 06:37[5]

С токеном интересная идея, спасибо!


Eraser ©   (08.03.19 15:33[6]

Не уверен, насчет защищенности, но возможен вариант
WTSEnumerateSessions
WTSQuerySessionInformation с параметром WTSClientProtocolType, по которому можно узнать RDP это или консоль.
ну и сравнить WTSGetActiveConsoleSessionId

вообще, например, в XP терминальный API внутри во многом завязан на namep pipe'ах, например \\.\Pipe\TerminalServer\SystemExecSrvr\
но, видимо, в каждой версии ОС там свой протокол, нужно серьезно реверсить, чтобы понять что к чему.
мне такой подход только один раз пригодился для XP, да и то, реализацию нашел, а не сделал сам, ибо самому не по зубам. но твоих знаний, в принципе, должно хватить, чтобы самостоятельно реверс протокола сделать.


Тимохов ©   (09.07.19 23:31[7]

Саш, ну расскажи, что придумал в итоге))) Интересно же. Ибо etSystemMetrics(SM_REMOTESESSION) я тоже использую.

ЗЫ Я мож что-то забыл уже в WinAPI, а чисто через Mutex нельзя понять, что копия уже запущена?


brother ©   (14.08.19 14:35[8]

скоро Ваш софт будудет работать ТОЛЬКО с консоли? ((((
бедаааа)


Rouse_ ©   (17.08.19 11:46[9]


> Саш, ну расскажи, что придумал в итоге)))


Да чего, времени не хватило чтобы вариант от han_malign протестировать, срочно нужно было релиз собирать, поэтому оставил так + проверка через глобальный мютекс.

function CheckServerRDP: Boolean;
asm
{$IFDEF TERMINAL}
 nop
 nop
 xor eax, eax
 nop
 nop
{$ELSE}
 // проверяем KE_USER_SHARED_DATA -> NtProductType
 mov eax, $7FFE0264
 mov eax, [eax]
 cmp eax, VER_NT_WORKSTATION // если равен VER_NT_WORKSTATION - выходим
 je @exit_false

 // получаем адрес сессии из PEB (это похоже актуально только для Windows 10 и не нужно)
//  {$IFDEF WIN32}
//  mov eax, fs:[30h]       // получаем PEB
//  mov eax, [eax + 50h]    // читаем значние SharedSessionData
//  test eax, eax           // если пустое на выход
//  jz @no_shared_data
//  mov eax, [eax]          // ID сессии будет лежать там
//  jmp @GetPEBSessionID
//  {$ELSE}
//  mov rax, gs:[60h]       // получаем PEB
//  mov rax, [rax + 90h]    // читаем значние SharedSessionData
//  test rax, rax           // если пустое на выход
//  jz @no_shared_data
//  mov eax, [rax]          // ID сессии будет лежать там
//  jmp @GetPEBSessionID
//  {$ENDIF}

@no_shared_data:
 mov eax, $7FFE02D8      // а если SharedSessionData нет
 mov eax, [eax]          // то читаем напрямую из KE_USER_SHARED_DATA -> ActiveConsoleId

 // получаем адрес сессии из Shared данных
@GetPEBSessionID:
 {$IFDEF WIN32}
 mov ecx, fs:[30h]       // получаем PEB
 mov ecx, [ecx + 1D4h]   // читаем значение SessionId
 {$ELSE}
 mov rcx, gs:[60h]       // получаем PEB
 mov ecx, [rcx + 2C0h]   // читаем значение SessionId
 {$ENDIF}

 // если ID сессий равны, то терминальной сессии нет
 cmp eax, ecx
 je @exit_false

 // еще проверяется вариант что PEB->SessionId равен нулю
 test ecx, ecx
 jz @exit_false

 // в противном случае - мы под терминалом
 mov eax, 1
 ret

@exit_false:
 xor eax, eax

{$ENDIF ~TERMINAL}
end;


Rouse_ ©   (17.08.19 11:52[10]

ЗЫ: код соответственно проверяет работу терминальной сессии на серверных ОС. Если терминальная сессия на обычной пользовательской системе, то возвращает False т.к. там самой системой блокируется одновременная работа нескольких пользователей под разными сессиями.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо