HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   Форум АНТИЧАТ > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Безопасность и Анонимность > Защита ОС: вирусы, антивирусы, файрволы.
   
 
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 30.12.2025, 13:24
Marylin
Постоянный
Регистрация: 01.09.2019
Сообщений: 378
Провел на форуме:
145166

Репутация: 0
По умолчанию

Оконная подсистема Win хранит в себе много тайн и загадок, некоторые из которых мутируют в огромные дыры безопасности. Её можно сравнить с "Марианской впадиной", которая начиная с пользовательского пространства в лице библиотеки User32.dll, и уходит глубоко в ядро к драйверу win32k.sys. На системах WinXP передачей окон юзеру занималась подсистема клиент-сервера csrss.exe, а начиная с Win7 появился диспетчер "Desktop Window Manager" dwm.ехе, для реализации графического интерфейса "Windows Aero" с такими фишками как прозрачность, различные 3D-эффекты и прочее. В данной статье мы рассмотрим методы управления чужими окнами - по сути ничего новаторского, но полезно знать.

1. Модель оконных сообщений
2. Практика - дефейс калькулятора
3. Проблемы сообщений таймера
4. Постскриптум

1. Модель оконных сообщений

GUI составляющая Win полностью построена на оконных сообщениях "Window Message", которые отождествляются константами с префиксом WM_xx. У любой программы с граф.интерфейсом имеется собственная процедура обратного вызова
Код:
WindowProc()
- она отвечает за обработку всех сообщений, отправляемых системой окну. Процедура в бесконечном цикле должна идентифицировать поступающие мессаги, и выполнять с ними все необходимые действия. Прототип
Код:
WindowProc()
выглядит так (4 указанных ниже аргумента передаёт графическая подсистема):

C-подобный:


Код:
CALLBACK
WindowProc
(
HWND    hWnd
,
UINT    uMsg
,
WPARAM  wParam
,
LPARAM  lParam
)
--
--
--
--
--
--
--
--
--
--
-
hWnd
=
дескриптор окна
,
кому адресовано сообщение
uMsg
=
сама мессага WM_xx
wParam
=
основной параметр сообщения
lParam
=
доп
.
параметр
(
зависит от типа WM_xx
)
В результате различных событий в системе генерируются сотни сообщений (в доках зарезервированы первые 400h констант), а из этого пула приложение юзера выбирает и обрабатывает только нужные себе. Но архитектура окон построена так, что если есть сообщение, оно обязательно должно быть кем-то обработано, иначе хаос и бардак. Чтобы гарантировать обработку буквально всех поступающих сообщений, Win предоставляет дефолтную свою процедуру
Код:
DefWindowProc()
для обработки мессаг, которые наш юзерский колбек пропустил между ног. Как правило в системную процедуру мы передаём управление в конце своей
Код:
WindowProc()
, чтобы необработанные сообщения могли быть переданы в процедуру по умолчанию.

Разрабатывая подсистему управления окнами майки преследовали основную цель - надёжность подсистемы, чтобы ни один поток не мог нарушить работу других потоков. В дефолте передача сообщения в окно всегда осуществляется синхронно чз
Код:
SendMessage()
: отправитель ждёт, пока окно получателя не обработает его сообщение и не вернёт ответ. Но если на обработку потребуется длительное время (или окно адресата вообще зависнет), напрочь заморозится и отправитель, а значит такая ОС не вправе называться надёжной. Так появились асинхронные сообщения
Код:
PostMessage()
, когда отправитель послав мессагу не дожидается ответа, и сразу продолжает заниматься своими делами.

Каждому потоку с графическим интерфейсом система выделяет свою собственную очередь сообщений "Message Queue", которая независит от других потоков. Как результат потоки выполняются в такой среде, где они считают себя единственными. Изначально, создавая какой-либо поток система предполагает, что он не будет работать с графическим интерфейсом - это позволяет уменьшить объём выделяемых ему системных ресурсов. Но, как только поток обратится к той или иной GUI-функции (например создание окна), система на автомате выделит ему нужные ресурсы для поддержки оконных сообщений. Эти ресурсы заворачиваются в структуру
Код:
THREADINFO
драйвера win32k.sys, которая сопоставляется с данным потоком.

Код:
THREADINFO
- это фундамент всей подсистемы передачи сообщений. Каждый поток имеет не одну, а целых три очереди - указатели на них прописываются именно в данной структуре. Первая - это очередь синхронных Sent-мессаг, куда выстроившись в ряд оседают сообщения от функции
Код:
SendMessage()
. Вторая очередь для асинхронных
Код:
PostMessage()
, и третья для ответных сообщений "Reply-Message Queue" (реализована как ReceiveList). Помимо того в структуре имеется и переменная под флаги пробуждения потока "Wake Flags". Фрагмент этой структуры с перечисленными выше полями представлен ниже:

Код:


Код:
0: kd> dt win32k!tagTHREADINFO
.....
   +0x198  TIF_flags       : Uint4B
   +0x1a0  pstrAppName     : Ptr64 _UNICODE_STRING
   +0x1a8  psmsSent        : Ptr64 tagSMS
   +0x1b0  psmsCurrent     : Ptr64 tagSMS
   +0x1b8  psmsReceiveList : Ptr64 tagSMS
   +0x1d0  exitCode        : Int4B
.....
Если поток вызывает синхронную
Код:
SendMessage()
для посылки сообщения своему окну, то функция просто обращается к своей оконной процедуре
Код:
WindowProc()
, и в ответ получает некое значение (зависит от типа мессаги). Но если поток посылает сообщение чужому окну, всё значительно усложняется.

Во-первых, переданное сообщение присоединяется к очереди приёмника, и для него устанавливается флаг
Код:
QS_SENDMESSAGE
. Во-вторых, если поток приёмника в данный момент чем-то занят, система не прервёт его работу для немедленной обработки поступившего сообщения. Если-же поток свободен и сообщений в его очереди больше нет, флаг
Код:
QS_SENDMESSAGE
сбрасывается. Пока приёмник обрабатывает мессагу, отправивший
Код:
SendMessage()
поток простаивает, ожидая ответа в своей очереди ответных сообщений Reply. С этого момента поток-отправитель просыпается и возобновляет работу в обычном режиме.

Поскольку Win обрабатывает межпоточные мессаги описанным выше образом, в ожидании ответа наш поток может заснуть навсегда. Задумаемся, что произойдёт с вызвавшим
Код:
SendMessage()
потоком, если по каким-либо причинам получатель войдёт в бесконечный цикл? Значит-ли это, что ошибка в одном приложении уронит другое? Ответ - да, и это является дырой в подсистеме безопасности! Выход из этой непростой ситуации один - использовать безопасные функции типа
Код:
SendMessageTimeout()
, последний аргумент которой ограничивает время ожидания ответа. Можно использовать асинхронную
Код:
PostMessage()
, но тогда мы не узнаем, обработал получатель наш запрос или нет, что не всегда удобно.

2. Практика - дефейс калькулятора

Чтобы дефейснуть любую форточку мастдая много ума не надо, хотя на системах Win7+ имеется одно ограничение - наш уровень доверенности "Integrity Level" должен быть не меньше жертвы. Узнать свои полномочия можно в программе "Process Hacker", а для их повышения достаточно зайти в систему под админом. На скрине ниже я атакую текстовый редактор "AkelPad" своим софтом WinDeface.exe, и как видно в столбце "Integrity" наши уровни совпадают, хотя до System я уже не дотянусь:

Рассмотрим такой пример, где я нахожу окно калькулятора функцией
Код:
FindWindow()
, и на всю его рабочую зону вывожу произвольную надпись, не забыв изменить и заголовок окна с "Калькулятор" на "Happy New Year!". Если для смены заголовка окна достаточно через
Код:
SendMessage()
отправить потоку калькулятора сообщение
Код:
WM_SETTEXT
, то с выводом самой надписи не всё так просто.

Здесь нужно задействовать функции из либы gdi32.dll, чтобы сначала рассчитать позицию для вывода в клиентскую область окна
Код:
GetClientRect()
, далее создать шрифт требуемого размера
Код:
CreateFont()
, активировать его посредством
Код:
SelectObject()
, задать цвет и атрибут прозрачности
Код:
SetTextColor()
+
Код:
SetBkMode()
, и только потом напечатать в окно
Код:
TextOut()
. Более того, нужно предварительно захватить контекст устройства вывода "Device Context" через
Код:
GetDC()
и на выходе освободить его
Код:
ReleaseDC()
. Вот код и что в итоге из этого получилось:

C-подобный:


Код:
format   pe64 console
include
'win64ax.inc'
entry    start
;
//----------
.
data
rect     RECT
hWnd     dd
0
dc       dd
0
font     dq
0
;
//sTxt     db  'Hello World!',0
;
//sTxt     db  'Hackerlab!',0
sTxt     db
'Codeby.net'
,
0
txtLen
=
$
-
sTxt
;
//----------
section
'.code'
code readable executable
start
:
push    rbp

         invoke  FindWindow
,
0
,

or      eax
,
eax
         jnz     @ok
        cinvoke  printf
,

jmp     @exit

@ok
:
mov
[
hWnd
]
,
eax
         invoke  GetClientRect
,
eax
,
rect
         invoke  GetDC
,
[
hWnd
]
mov
[
dc
]
,
eax
;
// Рассчитываем размер шрифта по размеру окна
mov     ecx
,
[
rect
.
bottom
]
shr     ecx
,
1
mov     eax
,
[
rect
.
right
]
mov     ebx
,
txtLen
         xor     edx
,
edx
         div     ebx
         xchg    eax
,
edx
         invoke  CreateFont
,
rcx
,
rdx
,
0
,
0
,
600
,
0
,
0
,
0
,
\
                            ANSI_CHARSET
,
0
,
0
,
0
,
\
                            FF_MODERN
,

mov
[
font
]
,
rax

         invoke   SelectObject
,
[
dc
]
,
[
font
]
invoke   SetBkMode
,
[
dc
]
,
TRANSPARENT
;
// Цвет текста будем выбирать рандомом
rdtsc
         and      eax
,
0xffffff
invoke   SetTextColor
,
[
dc
]
,
eax
         mov      eax
,
[
rect
.
bottom
]
shr      eax
,
3
invoke   TextOut
,
[
dc
]
,
0
,
eax
,
sTxt
,
txtLen
;
// Сменить заголовок окна, и освободить контекст девайса
invoke   SendMessage
,
[
hWnd
]
,
WM_SETTEXT
,
0
,

invoke   ReleaseDC
,
[
hWnd
]
,
[
dc
]
cinvoke  printf
,

,
[
hWnd
]
@exit
:
cinvoke  _getch
        cinvoke  exit
,
0
;
//----------
section
'.idata'
import data readable
library  msvcrt
,
'msvcrt.dll'
,
kernel32
,
'kernel32.dll'
,
\
         user32
,
'user32.dll'
,
gdi32
,
'gdi32.dll'
include
'api\msvcrt.inc'
include
'api\kernel32.inc'
include
'api\user32.inc'
include
'api\gdi32.inc'
Если изменить аргумент
Код:
FindWindow()
, можно аналогичным образом дефейснуть любое окно, как в примере ниже "AkelPad". Отметим, что это просто безобидный мод активного на данный момент окна, чтобы навести на юзера жути - при следующем перезапуске "Calc" и "AkelPad" всё восстанавливается в дефолт, и никаких надписей уже не будет. Это не фотошоп, и всё реально выглядит так:

3. Проблемы сообщений таймера

Среди всех оконных сообщений притаилось в засаде одно из интересных (и в то-же время опасных) мессаг - это
Код:
WM_TIMER=0113h
с его собратом
Код:
WM_SYSTIMER=0118h
. Согласно описанию на MSDN, они имеют привязанные функции обратного вызова "Callback". То-есть мы определяем в своём коде процедуру с любым содержимым (например шелл-код), и по истечении указанного нами времени в таймере, она получает управление. Красота!

Только вот всю малину портит то, что начиная с Висты инженеры ограничили возможности этого сообщения - теперь его можно посылать исключительно своему окну, и функция терпит крах, если мы отправляем мессагу таймера чужой форточке. При хороших обстоятельствах
Код:
WM_TIMER
могла-бы послужить отличной альтернативой традиционным способам внедрения шелл-кодов в чужой процесс, через давно уже палённую
Код:
CreateRemoteThread()
с последующим
Код:
WriteProcessMemoryEx()
. Например такой бесхитростный код наглым образом забирает управление у "Калькулятора", и передает его по адресу
Код:
0x004060Е8
.

C-подобный:


Код:
invoke FindWindow
,
0
,

invoke SendMessage
,
eax
,
WM_TIMER
,
0
,
0x4060E8
Запреты такого рода только разжигают интерес хакеров, и конечно-же они нашли выход из этого положения. По сути запреты и создаются, чтобы их нарушать. Если мыслить логически, то раз уж есть ограничение, значит где-то должна быть проверка типа сообщения, и если обнаружится, что это таймер, то секьюрити тут-же должен проводить нас на выход. И такая проверка действительно существует, причём ни где-то в нёдрах системы, а прямо у нас под носом в библиотеке user32.dll, которая проецируется системой в адресное пространство нашего процесса.

Как уже упоминалось выше, все мессаги из оконной процедуры
Код:
WindowProc()
диспетчеризуются в user32.dll, где и происходит их фактическая обработка внутренней функцией
Код:
DispatchMessageWorker()
. На скрине ниже фрагмент из листинга этой функции, с тестом мессаги на
Код:
WM_TIMER
. Здесь достаточно изменить адрес перехода с
Код:
0x7DC6792D
на адрес чуть ниже
Код:
0x7DC67740
(у вас он может быть другим) и всё.. таймер "пойдёт танцевать в пьяную", захватывая в свои объятия абсолютно любые окна:


4. Постскриптум

Подсистема графических окон Win дырява как сито, и что особенно важно, инженеры ничего не могут с этим поделать. Для ускорения отрисовки окон, компонент ядра в лице драйвера win32k.sys отображает большую часть своих структур в пространство пользователя, от куда мы можем их без проблем читать, но не модифицировать. Однако для разведки и этого достаточно, а дальше уже по обстоятельствам. В промапленной в наш процесс либе user32.dll есть куча уязвимых мест, и нам остаётся лишь использовать их в своих корыстных (и не очень) целях. В скрепку кладу исполняемый файл для тестов (запускать при активном калькуляторе), всех с наступающим, пока!
 
Ответить с цитированием
 





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.