GUI & Kernel Mode

Тема в разделе "WASM.NT.KERNEL", создана пользователем Dian, 4 дек 2008.

  1. Dian

    Dian Member

    Публикаций:
    0
    Регистрация:
    19 июн 2008
    Сообщения:
    222
    Как выводить своё изображение на экран из ядра?
    Вместо того, что выводит туда система...
     
  2. katrus

    katrus New Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    612
    Можно манипулировать драйвером дисплея. Естественно, нужна документация по нему ...
     
  3. Dian

    Dian Member

    Публикаций:
    0
    Регистрация:
    19 июн 2008
    Сообщения:
    222
    Из доков - только MSDN/хелп от DDK.
    Кстати, там есть разрозненная информация: некий DxApi, десятка 4 IOCTL, которые вроде как должны обрабатываться video miniport'ом... однако, получить целостную картину пока не удалось.

    В моём случае интересен не только режим нормальной работы винды, но и этап начальной загрузки (bootvid.dll и всё такое), в т.ч. текстовый режим. Плюс нужно поймать переход в графический режим

    P.S. SoftIce спокойно рисуется из ядра... насколько я слышал, там как-то завязан DirectX...
     
  4. SysProger

    SysProger New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2007
    Сообщения:
    127
    а как (с помощью каких функций) можно из драйвера создать обычную консоль и выводить туда текст?
     
  5. Dian

    Dian Member

    Публикаций:
    0
    Регистрация:
    19 июн 2008
    Сообщения:
    222
    Зачем??
     
  6. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Довольно непростая вещь. Я сейчас решил с нуля писать свой отладчик, который писал год назад, по разным причинам и столкнулся с проблемой вывода.
    Выводить своё изображение можно :
    1) прямым выводом в фреймбуффер. На некоторых видеокартах изображение идет подряд - пиксель за пикселем, строчка за строчкой в фреймбуффере. На некоторых - новые строчки могут выравниваться по границе страницы или же вообще фреймбуффер может иметь блочную структуру.
    2) манипуляциями с win32k и драйвером дисплея.
    Если ты почитаешь MSDN, то найдешь там функции Eng** от win32k graphics engine. Увидишь, что есть много функции рисования на виртуальных "поверхностях" (surface objects, struct _SURFOBJ*). Например, EngLineTo.
    Они производят построение изображения. Поверхность можно создать через EngCreateBitmap. Можно даже загрузить с диска готовое изображение bmp. и сделать из него поверхность.
    Проблема в том, что этими функциями ты можешь создать виртуальное изображение на виртуальной поверхности (типа hdc в юзермоде), но тебе в конце концов потребуется перенести свое изображение на поверхность физического дисплея. Этим занимается функция видеодрайвера DrvCopyBits. Как найти ее - писать здесь и сейчас я сомневаюсь, что следует, поскольку хоть один человечек (PROFi, привеееет :lol: ) скидывал мне год назад технологию вывода свою, которую я если честно год назад нифига не понял, поскольку по этой теме нифига не знал, а сейчас все проделал самостоятельно и просто ради интереса вспомнил про тот случай. Та технология хоть и не имеет ничего общего с поиском DrvCopyBits, который я затеял сейчас, но некоторые люди все равно могут усмотреть аналогию и обвинить меня в плагиате.
    Ну да ладно, все равно отладчик я планирую делать OpenSource и в принципе исходнеы коды доступны и сейчас в http://code.google.com/p/ngdbg/source/browse/trunk/.
    Задача заключается в следующем: видеодрайвер реализует функции, которые отвечают за физическое рисование и копирование бит на физическую поверхность дисплея, производя необходимые преобразования в случае нелинейности фреймбуффера и в конце концов делает memmove, поэтому нам нужен указатель на его DrvCopyBits, так же нам нужен SURFOBJ* физической поверхности.

    С выводом графики в Windows связаны два драйвера:
    1) драйвер минипорта видео, который является стандартным драйвером, драйвером видеопорта его делает лишь импорт из videoprt.sys и вызов VideoPortInitialize
    2) драйвер дисплея .dll, который на самом деле никакой не dll, а самый настоящий драйвер режима ядра, но не обычный - его загружает подсистема win32 в момент загрузки системы или в рантайме при установке нового видеоадаптера и он может импортировать только из win32k.sys. Драйвер минипорта ничем не примечателен - он отвечает за фактическую работу с аппаратной частью - собственно видеокартой, а драйвер дисплея представляет некоторый интерес - он предоставляет подсистеме win32 функции, в которых заложена логика того, как работать с фреймбуффером, который можно получить от драйвера минипорта запросом IOCTL_VIDEO_MAP_VIDEO_MEMORY. Далеко не на всех видеокартах фреймбуффер содержит подряд пиксели экрана, например у меня на ноутбуке фреймбуффер содержит scan-lines (так Windows называет горизонтальную линию пикселей), выровненные на границу страницы. То есть если разрешение стоит 1280x800, то каждая новая строчка начинается не со смещения nLine * 1280 * sizeof(PIXEL), а со смещения ALIGN_UP (nLine*1280*sizeof(PIXEL), PAGE_SIZE). На других видеокартах могут быть свои причуды. Всем этим управляет драйвер дисплея, фунция DrvCopyBits
    которого как раз копирует пиксели с win32-поверхности (SURFOBJ) на поверхность экрана, производя, при необходимости, нужные преобразования (как минимум, нужно преобразовать обратный порядок бит, который используется в Windows и в bmp файлах в прямой порядок на экране). Поэтому для корректного вывода нам потребуется две вещи - адрес DrvCopyBits драйвера дисплея и указатель на поверхность экрана SURFOBJ*. Драйвер основного дисплея загружается при старте системы, инициализация win32 подсистемы csrss.exe вызывает функцию win32k!NtUserInitialize, которая делает
    NtUserChangeDisplaySettings, а она вызывает win32k!ldevLoadDriver:
    fa0f2980 bf8ba311 vmx_fb!DrvEnableDriver+0x11
    fa0f29ac bf8ba3c6 win32k!ldevLoadDriver+0x71
    fa0f29c4 bf8bd52d win32k!ldevGetDriverModes+0x1b
    fa0f29f4 bf8b8cde win32k!DrvBuildDevmodeList+0xa4
    fa0f2a7c bf8b3221 win32k!DrvProbeAndCaptureDevmode+0x408
    fa0f2bf4 bf8b9423 win32k!DrvCreateMDEV+0x42d
    fa0f2ce8 bf8b624e win32k!DrvChangeDisplaySettings+0x2e5
    fa0f2d28 bf8b61bc win32k!InitVideo+0x3e
    fa0f2d48 bf8b71fe win32k!UserInitialize+0x14d
    fa0f2d50 8053c808 win32k!NtUserInitialize+0x87
    fa0f2d50 7c90eb94 nt!KiFastCallEntry+0xf8
    0015fd80 75b3a68e ntdll!KiFastSystemCallRet
    0015fdb0 75b13472 winsrv!NtUserInitialize+0xc
    0015fe20 75b1301b CSRSRV!CsrLoadServerDll+0x1a0
    0015ff74 75b130f3 CSRSRV!CsrParseServerCommandLine+0x2d6
    0015ff88 4a68115d CSRSRV!CsrServerInitialization+0x95
    0015ffa8 4a6818d7 csrss!main+0x4f
    0015fff4 00000000 csrss!NtProcessStartup+0x1d2
    (не спрашивайте откуда у меня символы для дллек вмвари, это на самом деле мой собственный mirror-драйвер, которым я подменил оригинальный в вмваре и все запросы он транслировал в оригинальный - мне так легче было изучить как работает драйвер дисплоея)

    Этот стек вызовов показан с VMWare, где драйвер дисплея - vmx_fb.dll. Точка входа драйвера дисплея называется DrvEnableDriver, она имеет следующий прототип:
    BOOLEAN NTAPI DrvEnableDriver(
    ULONG iEngineVersion,
    ULONG cj,
    PDRVENABLEDATA pded
    );
    Эта функция производит много полезных вещей, но на выходе она обязана записать в PDRVENABLEDATA массив Callback'ов драйвера (для примера как работает драйвер дисплея - посмотри \WINDDK\2600.1106\src\video\displays\mirror\disp\enable.c и другие файлы из этой директории). Нам нужен этот массив каллбеков.
    Я сделал следующим образом (см. http://code.google.com/p/ngdbg/source/browse/trunk/ngvid.cpp и функцию REINITIALIZE_ADAPTER()):
    я подгружаю себе копию видеодрайвера функцией EngLoadImage (как мне удается использовать Eng* в обычном драйвере с такой легкостью - другой вопрос:) это тоже можно найти в сорцах, у меня используется фишка с ложным импортом и его динамической подменой) и просто вызываю ее ентри. Она не производит никаких действий по инициализации видеокарты, поскольку драйвер дисплея обычно подгружается несколько раз. Поэтому я могу смело ее вызвать и получить себе массив каллбеков. После этого драйвер выгружается. Я ищу в массиве каллбеков DrvCopyBits, считаю её RVA относительно базы копии видеодрайвера. После этого я добавляю VA загруженного нормального видеодрайвера и получаю реальный адрес DrvCopyBits.
    Первая часть задачи решена. Начинаем решать вторую часть - чтобы получить SURFOBJ* поверности экрана, я ставлю сплайсинговый хук на DrvCopyBits. Не думаю, что юзеры во время загрузки моего драйвера будут интенсивно водить мышкой, поэтому вряд ли функция будет вызываться часто. DrvCopyBits имеет такой прототип:
    BOOLEAN
    NTAPI
    DrvCopyBits(
    OUT _SURFOBJ *psoDst,
    IN _SURFOBJ *psoSrc,
    IN VOID *pco,
    IN VOID *pxlo,
    IN VOID *prclDst,
    IN VOID *pptlSrc
    );
    Нас интересует значение psoDst - функция обычно занимается копированием НА поверхность экрана. Поэтому в обработчике хука мы делаем некоторые проверки на psoDst (я делаю проверки на размер поверхности - если она больше или равна, чем 640х480, очевидно это главная поверхность) и записываю себе её как главную поверхность. После этого хук снимается.

    Задача решена. Теперь для вывода нужно создать себе поверхность через EngCreateBitmap, рисовать там через Eng*** функции, а потом скопировать изображение на первичную главную поверхность экрана через DrvCopyBits.
    Как это все происходит можно посмотреть в http://code.google.com/p/ngdbg/source/browse/trunk/worker.cpp - там содержатся функции, отвечающие за интерфейсную часть отладчика (в отличие от http://code.google.com/p/ngdbg/source/browse/trunk/gui.cpp, где содержится небольшой набор GDI-аналогов для вывода текста на экран и других шалостей с собственным форматом шрифтов). Достаточно посмотреть на функцию DisplayBuffers или WR_ENTER_DEBUGGER (нет, не все функции у меня называются заглавными буквами - только две, уже не помню почему :lol: ).

    Если есть какие-то вопросы, я отвечу.
     
  7. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    выше бл довольно развернутый ответ на один из вопросов, поскольку это перекликается с моим отладчиком %)
    видео минипорт тебе нафиг не нужен. он занимается маппированием фреймбуффера и переключением режимов. чисто физическая аппаратная работа. как я уже говорил, если видеобуффер нелинейный, то это не поможет.

    Начальный этап загрузки - я тоже это реализовал в своем отладчике. смотри файл bootgui.cpp - он на случай старта отладчика при загрузке винды. Используются функции Inbv** (inline bootvideo driver в ядре), которые транслируются в Vid** из bootvid.dll
    У меня происходит переключение в режим 640x480 VGA, как это делает KeBugCheckEx при показе синего экрана смерти, экран закрашивается зеленым и там рисуются буковки просто через InbvDisplayString =)

    инжектнуться, например, в CSRSS.EXE и выполнить там AllocConsole. Получить хендл консоли. И вызывать WriteConsole.


    Вообще, я хотел заморочиться с такой еще темой - хочу переключать режим в 640x480 через InbvResetDisplay или черещ видеодрайвер и иоконтрол IOCTL_VIDEO_RESET_DISPLAY переключатся вообще в текстовый режим, а потом переключаться обратно. Я долго интересовался тем, как это делает csrss/win32k, когда консоль переводится в фуллскрин, но так и не выяснил. В результате придумал лишь только сохранить старый видеорежим, сделать reset display, выводить текст прямым выводом в текстовую видеопамять (что кстати не везде почемуто работает %(), а потом сделать set current mode на старый режим. На вмваре работает, на реальном компе - нет. Видеорежим при выходе восстанавливается, но на экране полная ерунда. Помогает только вслепую набрать Win+R, cmd, и нажать Alt-Enter чтобы переключить консоль в текстовый режим и выйти обратно. Вообщем, криво и вообще :dntknw: Я забил
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Great
    Хорошее это дело, надеюсь ты не забудешь переписать ту часть ядра, которая отвечает за возврат в юзермод(Kei386EoiHelper, KiServiceExit, KiServiceExit2 etc.), а то на сегодня трассировщика выполняющего это должным образом нет.
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Пока что у меня нет завязки на сервисы, но есть завязка на завершение прерывания по Kei386EoiHelper: отладчик может всплывать так же и по нажатию Ctrl-Alt-Shift-F12 и хук на это ставится через IOCTL_INTERNAL_I8042_HOOK_KEYBOARD, поэтому трассировка этой части, полагаю, будет затруднительна. Правда, самой трассировки и явных отладочных действий в отладчике пока нет - команды в основном информационные типа дизасма или дампа памяти или вывода PRCB, но он уже умеет всплывать на исключения. наприме, юзермодный Xor eax, eax / mov [eax], eax поймает
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Great
    Я не про то, каждый кто трассировал программы, где используются антиотладочные фичи связанные с RF в флажках знает какой это ад, сисер с этим не справляется.
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    можно. надо подумать. :lol:
    PS. если хочешь обсудить отладку - я могу создать отдельную тему про отладчик
     
  12. Medstrax

    Medstrax Забанен

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    673
    Насчет отдельной темы - неплохо бы. А по поводу вывода на экран из отладчика - глубоко убежден, что самое рациональное решение это отладка на двух машинах через сетевуху. Все-таки чем меньше отладчик влияет на отлаживаемую среду тем лучше.
     
  13. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Medstrax
    само собой. но меня здесь и kd/windbg вполне устраивает

    PS. про отладчик писать тута: https://www.wasm.ru/forum/viewtopic.php?id=30224
     
  14. Dian

    Dian Member

    Публикаций:
    0
    Регистрация:
    19 июн 2008
    Сообщения:
    222
    Именно вывод в видеопамять?
    Я когда ковырял, сталкивался со случаем, когда отображалось начиная с 0xb8100 вместо стандартных 0xb8000
     
  15. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Dian
    какие b8000 ? это текстовая. а я про графическую. которая может отображаться по любому адресу, это зависит от видеокарты и получается через IOCTL_VIDEO_MAP_VIDEO_MEMORY
     
  16. SysProger

    SysProger New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2007
    Сообщения:
    127
    Для понимания базовых механизмов работы ядра NT.

    Great
    инъект - крекерская фишка. Официально это никак нельзя сделать?
     
  17. baga

    baga New Member

    Публикаций:
    0
    Регистрация:
    26 сен 2007
    Сообщения:
    16
  18. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Где инъект?
    PS. официально никак не рассчитывалось рисовать из ядра
    большая часть там посвящена прямому выводу в фреймбуффер, что не катит, я уже объяснял почему
     
  19. Dian

    Dian Member

    Публикаций:
    0
    Регистрация:
    19 июн 2008
    Сообщения:
    222
    Тогда не удивительно, что не везде работает.
    Адрес, видимо, ещё и по ходу дела меняется

    P.S. b8000 - это к тому, что с текстовой тоже косяки бывают
     
  20. nabl3

    nabl3 New Member

    Публикаций:
    0
    Регистрация:
    30 янв 2009
    Сообщения:
    17
    хм.. попробовал через фрэймбуфер как тут описано http://www.rootkit.com/vault/c0de90e7/lkd.c
    не фурычит :dntknw:
    А как реализовать универсальный способ, что-то не очень понятно
    Great, у тебя сделано также как в SoftIce'е ?