Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #58, СЕНТЯБРЬ 2005 г.

Издевательство над окнами

nezumi

Спецвыпуск: Хакер, номер #058, стр. 058-024-2


Порядок перечисления окон всегда один и тот же, значит, определив назначение каждого из дочерних окон экспериментально (или с помощью шпионских средств типа Spyxx из комплекта SDK), ты можешь жестко прописать их номера в своей программе.

Жмем на чужие кнопки

Как видно, ввод/вывод текста в окно редактирования не вызывает больших проблем: WM_SETTEXT/WM_GETTEXT и все пучком. Нажать на кнопку "программно" несколько сложнее. Посылка сообщения BM_SETSTATE элементу управления типа "кнопка" еще не приводит к ее нажатию. Для корректной эмуляции ввода ты, во-первых, должен установить фокус (WM_SETFOCUS), а после перевода кнопки в состояние "нажато" убить этот фокус (WM_KILLFOCUS), так как кнопки срабатывают не в момент их нажатия, а в момент отпускания.

Кстати, если в роли убийцы фокуса выступает функция SendMessage, то поток, эмулирующий ввод, блокируется вплоть до того момента, пока обработчик нажатия кнопки не возвратит циклу выборки сообщений своего управления. Чтобы этого не произошло, следует использовать функцию PostMessage, которая посылает сообщение и, не дожидаясь ответа, как ни в чем не бывало продолжает выполнение.

Все это, конечно, хорошо, но внедрить код в чужой процесс намного интереснее! Традиционные способы с подключением собственной DLL, WriteProcessMemory или CreateRemoteThread тут не годятся, поскольку разработчики антивирусов и файрволов хорошо осведомлены о них и принимают целый комплекс защитных мер, справиться с которыми не так-то легко. Но мы все равно перехитрим их :).

Сообщение WM_TIMER позволяет передавать не только идентификатор таймера, но и адрес таймерной процедуры, вызываемой операционной системой независимо от того, был ли предварительно взведен таймер. Следующий бесхитростный код перехватывает управление у "Калькулятора" и передает его по адресу 401234h:

h=FindWindow(0, "Калькулятор");

SendMessage(h, WM_TIMER, 0, 0x401234);

Адрес 0x401234 выбран чисто для примера. Ничего интересного здесь нет. Калькулятор просто упадет. Для достижения осмысленного результата атакуемому приложению необходимо как-то передать зловредный shell-код. А как это можно сделать? Самое простое - найти любое окно редактирования и послать ему WM_SETTEXT, только вместо текста здесь будет shell-код. Если нет строки редактирования - не беда. На худой конец сгодится и заголовок главного или дочернего окна, правда, на сам shell-код в этом случае будут наложены жесткие ограничения. Остается лишь определить адрес буфера, в котором хранится содержимое окна. А хранится оно во вполне предсказуемых буферах: их местоположение легко подсмотреть под отладчиком.

Этот прием работает во всех операционных системах семейства Windows, включая непатченную XP. В начале 2003 года баг с таймером был исправлен, о чем можно прочитать в Microsoft Security Bulletin'е за номером MS02-071. На самом деле радикальной смены парадигмы так и не произошло. Разработчики так и не рискнули трогать систему сообщений, ограничившись парой дополнительных проверок в USER32.DLL. Теперь посылать сообщение WM_TIMER можно только своему собственному окну. Но USER32.DLL - это же всего лишь "обертка" поверх win32k.sys, и ее можно обойти! Достаточно немного потрассировать SendMessageA и в нужном месте перепрыгнуть через "левый" jxx, который можно найти по шаблону "cmp xxx,113h/jxx". К примеру:

Назад на стр. 058-024-1  Содержание  Вперед на стр. 058-024-3