Скелет для программы пересылки экрана.

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Привет всем, хочу предложить вашему вниманию результаты моего эксперимента с интерфейсом IDXGIOutputDuplication. Из описания в MSDN интерфейс просто волшебный, однако пришлось повозиться для того чтобы приспособить его для пересылки экрана. В результате получилась пародия на RDP или маленький скелетик удаленного управления. Маленький в прямом смысле – неупакованный сервис с сервером в ресурсах весить 50 кбт, если его упаковать, то получится 30 кбт. Выложить это все я решил потому, что я удовлетворил свое любопытство и мне надоело возиться с этим проектом.

Итак, получилось три модуля:

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

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

Логика работы предельно простая: при помощи интерфейса IDXGIOutputDuplication делаются скриншоты, являющиеся кадрами видеопоследовательности. Для уменьшения трафика изменил цветовую палитру каждого кадра, и на сервер отправляю разницу между кадрами, которая сжимается zlib. Мышь и клавиатура пересылается асинхронно через UDP сокет. Сервис запускает сервер от имени системы при помощи дублирования токена winlogon. Также, сервис перезапускает сервер если изменяется пользователь. Для установки сервиса нужны права админа. Можно сервер использовать и без сервиса. У Сервера есть три режима работы: первый - сервер слушает торт 443 и периодически ищет возможность соединиться с клиентом через порт 7788: второй – сервер не слушает порт и только делает попытки соединиться с клиентом; третий – сервер только слушает порт и все. UDP, порт для пересылки, ввода выбирается произвольно. Обратный вызов работает так: нужно сделать акк. на freedns.afraid.org и связать DNS имя с IP адресом компа на котором запущен клиент для примера: serg.chickenkiller.com связан с 127.0.0.1. ДНС имя серверу известно, через него сервер узнает ИП. В результате, если вы запустите на своем компе сервер и клиент, то через минуту сервер подключится к клиенту и вы увидите копию экрана своего компа. Авторизация между клиентом и сервером происходит автоматически типа примитивный handshake.

В архиве есть исходник и три бинарика. Возможно кому-нибудь все это пригодиться. Нпример пошпионить за кем-нибудь :)
 

Вложения

  • RC.zip
    81 КБ · Просмотры: 895
  • 1.jpg
    1.jpg
    9,6 КБ · Просмотры: 557
  • 2.jpg
    2.jpg
    92,8 КБ · Просмотры: 239

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Маленькое дополнение для тех кого интересует тема пересылки изображения десктопа. Програмка для провкрки разлияных способов захвата и воспроизведения изображения экрана. В ней есть 4 способа захвата экрана это: D3d09, D3d11, Magnify, GDI; и два варианта воспроизведения D3d11 и GDI. Прога может записть и воспроизвести все что происходит на экране дефолтового монитора. В принципе можно записывать и весь десктоп в смысле все мониторы. Файл который получается в результате - это что-то типа дампа трафика который передается между клиентам и сервером в проге из первого поста. Для примера в архиве есть файл test.vid. Интерфеис убогий - для начала записи нужно нажать кнопку "Write" в появвшемся диалоге указать название файл, потом указать размер файла в мегабайтах и время задержки между кадрами, и снова нажать на эту кнопку чтобы запись началась. Для воспроизведения выбираем файл и давим "Play".
 

Вложения

  • 3.jpg
    3.jpg
    156,1 КБ · Просмотры: 102
  • SC.zip
    7,1 МБ · Просмотры: 120
  • 4.jpg
    4.jpg
    20,5 КБ · Просмотры: 104
  • Нравится
Реакции: Evgeny D и WithoutIrony

Evgeny D

Green Team
04.07.2021
31
6
BIT
225
В исходниках встречаются include:
oaidl.inc
DXGI.inc
d3d.inc
ScreenCap.inc
Если не сложно можете докинуть?
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
В архиве исходники вместе с компилятором, инклудами и либами. Директорию masm32 нужно сделать в корне диска. Чтобы собрать нужно запустить makeit.bat.
 

Вложения

  • masm32_2.zip
    1,2 МБ · Просмотры: 146
  • Нравится
Реакции: Evgeny D и WithoutIrony

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Вот описание алогритма персылки экрана которое там используется. Это на случай если кому-нибудь захочется что-нибудь подправить в коде.


Одной из ключевых проблем при пресылке изображения является уменьшение количества данных передаваемых по сети между клиентом и сервером. В задачи сервера входит делать клпии экрана и отправлять их клиенту по сети. Например если разрешение вашего монитора 1920х1200 то при глубне цветовой палитры 32 бита размер кадра будет весить больше 8 мегабайт. Есть много различных вариантов решения этой проблемы я решил использовать самый простой вариант.
Все происходит в пять этапов:
во-первых, захват изображения экрана делается при помощи интерфейса IDXGIOutputDuplication графической технологии Direct3D 11. Эта технология позволяет использовать шейдеры для переноса нагрузки на GPU - это очень ускоряет процес захвата изображения экана. Однако, я использую простую реализацию поскольку вариант с шейдерами очень капризный в плане синхронзации. Последовательность действий такая: создаем D3D11 устройство, от него, через различные интерфейсы, получаем IDXGIOutputDuplication для монитора по умолчанию, если мониторов несколько, то выбирается с 0 индексом; затем, создается две текстуры по размеру экрана, для обеспечения пересылки данных от GPU к CPU, с одной из этих текстур забирается массив пикселей для дальнейшей обработки; у этого интерфейса есть свойство терять связь при изменении типа изображения - если, например, вы нажимаете Ctrl+Alt+Del или заблокируете экран, в этом случае интерфейс нужно перезагузить; все кадры полученные при помощи этого интерфейса будут имять 32 битные пиксели.
во-вторых, в каждом кадре уменьшается цветавая палитра - количество цветов используемых в изображении. Цель этого действия уменьшить "величину разнообразия" в кадрах чтобы разница между кадрами была как можно меньше. Происходит это так: снимок экрана делается 24 битными пикселями - это три байта, каждый из которых может иметь значение от 0 до 255. Таким образом, пиксель может иметь значение от 0 до 16581375. Здесь имеется ввиду формат RGB, где каждый цвет предствлен одим байтом и имеет палитру от 0 до 255, именно эту палитру я уменьшаю. Хочу уточнить, что на этом этапе уменьшается не количество бит предсталяющих цвет, а иммено количество оттенков цвета. Эксперментально я выяснил, что при уменьшении количества оттенков до 11 качество изображения уменьшается до состояния приемлемого для пересылки экрана. Цель программы не показывать кино, а управлять окнами на рабочем столе компьютера. Итак, делим шкалу от 0 до 255 на 11 делаем таблицу для подстановки и функцию замены цветов в 24 битном пикселе. Этим я добился того, что теперь каждый писксель имет значение от 0 до 1331 - это в любом случае уменьшит разницу между кадрами.
в-третих, после изменнея палитры размер пикселя остался тем же - (RGB+A) - 4 байта. Чтобы уменьшить размер пикселя я конвертирую его в 16 битный формат и получаю размер 2 байта на пиксель.
в-четвертых, вариантов межкадрового сжатия очень много, на мой взгляд самый крутой вариант - это сделать асинхронный конвеер с 1 секундной задержкой. В смысле делать 30 кадров сжимать их в MP4 отправлять клиенту для показа, пока этот кусок летит по сети и показывается создавать следующий кусок и т.д. Однако, я сделал все грубее и проще, хотя это не очень эффективно, но вполне приемлемо для этой задачи. Итак, делаем опорный кадр - первый снимок экрана - затем второй, вычитаем разницу между мини и второй кадр занимает место первого по отношению к следующему. Разница между кадрами это массив всех пикселей второго кадра которые отличатся от пикселей в первом в соответсвующих координатах. Таким образом, нужно передать два массива данных - данные самих пикселей и данные координат этих пикселей. У меня есть вариант с использование функции ExtCreateRegion и т.д. однако в данном случае я исползовал простую битовую маску с кадра. Каждому пикселю в кадре соответсвует один бит в массиве заголовка. Сравниваем два массива с пикселями, если пиксели одинаковы в массиве заголовка ставим нулевой бит, а в массиве пикселей нулевое значение пикселя, если пиксели разные ставим единичный бит в массиве заголовка, и сохраняем пиксель из второго кадра в массиве пикселей. В результате, каждый раз, для передачи клиенту, мы получаем массив по размерам равный кадру и плюс к нему масив с заголовком. Однако, все это хорошо пакутется поскольку сотоит в основном из нулей. Такой вариант вполне премлем для пересылки оконного интерфейса, стримить видосы таким способом явно негодится :)
в-пятых, Еще одна проблема это отправка данных клиенту. Дело в том, что процесс вычисление разницы, упаковка и пересылка по сети занимает время и вычислительные ресурсы. Необходимо сделать палавность передачи данных, чтобы следующий кадр создавался пока показывается предидущий. Двигаясь в этом направлении, я сделал многопоточное вычисление разницы между кадрами - 16 потоков, каждый из которых вычисляет свой фрагмент кадра. Упаковка массива происходит маленькими фрагментами которые сразу отправляются клиенту. Весь процесс отправки данных кленту делается двумя потоками по ходу обработки кадров.

При всех моих хитростях для нормальной работы нужна хорошая связь.
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Еще в догонку описание пересылки мыши с клавой. Мало ли кому-то нужно персылать команду наклона колесика мышки :)

Для управления удаленным копьютером нужно организовать персылку команд мыши и клавиатуры. Тут варианты тоже есть, например установить хуки. Но я использую для сбора данных о командах мыши и клавиатуры сообщения окна на котором воспроизводится изображение удаленного дисплея. Все предельно просто, на стороне клиента содается окно в клиантской части которого рисуются полученные от сервера кадры, когда вы водите мышью по поверхности клиентской части окна, что рано экрану удаленного компьютера, это окно посылает в оконную процедуру сообщения WM_MOUSEMOVE, WM_MBUTTONDBLCLK, WM_MOUSEWHEEL и т.д. , для клавиатуры есть свои сообщения WM_SYSKEYUP, WM_KEYUP, WM_KEYDOWN, WM_SYSKEYDOWN. Эти сообщения дают иформацию и координатх в которых находится мышь по отношению к окну на клиентской стороне, размеры монитра удаленного компа вы знаете - персчитываем координаты пропорционально и отправляем серверу, сервер получает и имитирует мышь. Тоже самое с клавиатурой. Для того чтобы не мешеть пересылке изображения я отправляю информацию о мыше и клавиатуре по отдельному каналу через UDP соединение.
 

Evgeny D

Green Team
04.07.2021
31
6
BIT
225
Приветствую! На win 7 x32 сервер отваливается при подключении с ошибкой c000005 adress 401f22
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
У меня нет под руками компа с 7 виндой может там тоже можно заставить сервер работать, однако вот что пишут в MSDN. Если использовать захват экрана при помощи GDI, от это будет работать везде.

Requirements​

Minimum supported clientWindows 8 [desktop apps only]
Minimum supported serverWindows Server 2012 [desktop apps only]
Target PlatformWindows
Headerdxgi1_2.h
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Возможно не для всех понятно как это все работает. Сервер по умолчанию при запусае пытается привязаться к 443 порту. Если он у вас занят или фаервол его не разрешает, то клиет к нему не подключиться. Если сервер не сможет привязаться к 443 порту, то он будет работать только на обратый вызов т.е будет искать соединение с клиентом и если найдет то подключится.
 

Evgeny D

Green Team
04.07.2021
31
6
BIT
225
Да исходники без комментариев, на дворе 3 ночи сижу разбираюсь 😁 , всё отбой спать тоже нужно
 

Evgeny D

Green Team
04.07.2021
31
6
BIT
225
Сервер бывает тупит и не коннектится с клиентом. К примеру процесс клиента глушишь, а сервер работает, то через некоторое время если клиент запустить, то к серверу не подключишься.
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Сервер работает потому что подключился к другому клиенту, кторый он определил по ДНС имени. Поспи потом разберешся.
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
Можно ускорить пересылку кадров если изменить алгоритм.
 

Вложения

  • algo.zip
    1,7 КБ · Просмотры: 89
  • Нравится
Реакции: Evgeny D

Evgeny D

Green Team
04.07.2021
31
6
BIT
225
Проект для меня сложноват, но читая описания MSDN разбираюсь потихоньку, как сервер общается с клиентом и т.д. Я знаю чего в проекте не хватает; ) Скелета модуля пересылки записи микрофона )) Изучаю ф-ции waveIn.
 

ser3gun

Green Team
10.03.2023
12
9
BIT
0
В MSDN есть такая штука как Microsoft Media Foundation. При ее помощи можно организовать пересылку и звука, и видео. Меня звук не интересовал, а вот запись видео в формате mp4 интересовала. В архиве рекордер и плейер для мп4. Для пересылки по сети нужно совсем мало - придумать протокол передачи данных и реализовать его. В waveIn, я не вникал, но судя по дате Microsoft Media Foundation новее.
 

Вложения

  • mediafoundation.zip
    992,6 КБ · Просмотры: 97
  • Нравится
Реакции: Evgeny D

Evgeny D

Green Team
04.07.2021
31
6
BIT
225
Спасибо за совет и код 👍 будем посмотреть )
Думаю стоит продублировать тему на васме, там асм коллективу ближе к сердцу, может кто и подключится к пректу
 
Последнее редактирование:

ser3gun

Green Team
10.03.2023
12
9
BIT
0
На васме где-то валяется старая версия. Вариант который я запорстил тут более эффективный - работает быстрей и потребляет меньше ресурсов.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!