| Вернуться на сайт |
Пример 4: Создание переборщика серийников
и работа с чужими окнами
Для данного примера нам потребуются следующие программы:
Рассмотрим защиту с применением серийного номера на примере программы Nero.
|
При входе в меню Help->Enter new serial number появляется окно для ввода серийного номера. Особенностью реализации данной защиты является неактивная кнопка OK при вводе неправильного серийника. Хорошей практикой набора на клавиатуре может стать ручной подбор серийника. Но мы этого делать не будем. А будем мы перебирать серийники автоматически и достаточно быстро. Для этого необходимо освоить некоторые механизмы, которые позволяют управлять чужими приложениями из своего. |
Поэтому немного длинной, но очень необходимой для понимания теории: почти все, что можно увидеть на экране графического интерфейса Windows, фактически является окнами. Окнами в Windows являются не только формы, но и кнопки, ListBox'ы, ComboBox'ы, некоторые картинки и надписи. Если говорить о программах на языках высокого уровня, то форма - это окно класса TMainWindow, кнопка - окно класса TButton, а поле редактирования в действительности является окном класса TEdit. Словом все компоненты, производные от класса TWinControl являются окнами.
Еще надо отметить, что работа Windows основана на сообщениях. Так Windows посылает любому окну такие сообщения как: WM_PAINT, WM_ACTIVATE, WM_LBUTTONCLICK и т.д. Каждое подобное сообщение имеет префикс WM_ (Window Message – оконное сообщение). Такая работа с окнами в Windows реализована на основе технологии "клиент-сервер", то есть глубоко в недрах ОС существует сервер сообщений, а в качестве клиентов выступают окна, элементы интерфейса, мышь и клавиатура. Соответственно, каждое простое перемещение мыши порождает поток из нескольких сотен сообщений WM_MOUSEMOVE, каждое из которых необходимо переслать клиентам (то есть окнам) и обработать.
Независимо от типа компонентов к ним можно применять стандартные функции WinAPI, для работы с окнами Windows предоставляет большое количество таких функций. Кроме того, в момент создания любого окна ему присваивается уникальный номер, по которому Windows это окно однозначно идентифицирует. Этот номер называется хэндлом окна (handle of window) и используется при вызове функций WinAPI, обращающихся к этому окну. Существует также специальный хэндл HWND_BROADCAST, который позволяет посылать сообщения всем окнам сразу.
Все управляющие элементы в Windows объединены в иерархические древовидные структуры, то есть управляющие элементы, размещенные в окне, являются потомками (childs) этого окна. В то же время окно само может быть потомком другого окна (обычно такое случается в MDI приложениях). Наглядно все это можно изучить при помощи утилиты Microsoft Spy++. С ее помощью очень легко можно отслеживать сообщения окон в какой-нибудь программе.
Этим мы и займемся при написании собственного переборщика серийников, и, как обычно, воспользуемся для этого средой разработки Builder.
|
Создаем новый проект, на форму вытаскиваем элемент Memo1, кнопку Button1 и поле ввода Edit1. Сразу оговорюсь, что примерный вид серийного номера для программы Nero я знал, для Ultra-edition он имеет вид: 1A23-xxxx-xxxx-xxxx-xxxx-xxxx, где х – циферка. Поэтому для начала напишем подпрограмму, выполняющую генерацию случайного серийника данного вида. Случайного, потому что шансы при полном переборе от 0000 до 9999 во всех знакоместах гораздо ниже, чем при случайном подборе цифр. |
Разберем этот участок кода, матерые программисты могут этот кусок пропустить. В переменной index хранится количество попыток перебора серийника, при каждом вызове значение инкрементируется. Это глобальная переменная, нам не особенно нужная, использовалась мной только в отладочных целях. В переменной KEY хранится строка типа AnsiString, в которой в конечном итоге окажется сгенерированный серийник. Мы задали для этой переменной известное начальное значение, дальше необходимо заполнить еще 5 групп по 4 цифры, разделенных знаком '-'. Для этого в цикле получаем случайное число от 0 до 9999 и добавляем к нему недостающие нули в начале (к примеру число 35 должно выглядеть как 0035). Не забываем после каждой группы добавлять к переменной KEY разделитель '-'. В итоге возвращается переменная KEY, содержащая в себе случайно сгенерированный серийный номер. Возможная модификация данной процедуры может идти в следующем направлении – не генерировать на основе случайного числа целую группу, а подставлять случайное число на каждое знакоместо. |
|
С генерацией серийного номера разобрались, теперь необходимо отдать его в другую программу, а именно Ahead Nero в нашем примере. Как раз для этого нам и понадобятся навыки работы с окнами.
Итак, задача - найти нужное нам окно для ввода и вставить в него текст. Для этого необходимо найти окно верхнего уровня, а потом просканировать все его дочерние окна. Традиционно поиск окна верхнего уровня (а это все окна приложений) по тексту в заголовке окна выполняется при помощи функции
hWnd FindWindow (LPCTSTR lpClassName, LPCTSTR lpWindowName), где lpClassName - указатель на строку с именем класса, lpWindowName - указатель на имя (заголовок) окна. Данная функция возвращает хэндл найденного окна или 0 в случае неудачи.
Переходим, собственно, к написанию программы. Объявляем переменную Window типа HWND и в цикле пытаемся найти окно с именем класса #32770 и заголовком "Enter new serial number". Откуда мы это взяли? Конечно, из утилиты Spy++. Там в меню для этого соответствующая функция есть, так и называется "Find window". Наводим Finder tool на окно с вопросом о серийнике и получаем следующее:
Как раз отсюда и берем название класса и точный заголовок окна. Кстати, если не закрывать окно, то функция FindWindow вернет тот же хэндл окна, что показывает Spy++. В иных случаях хэндл меняется, для этого мы его и получаем. |
|
Находим 2 дочерних окна, а именно поле ввода серийника и кнопку ОК. Для этого используем функцию FindWindowEx, в которую передаем хэндл родительского окна. Их названия и классы также подсматриваем Spy'ем, наводя его на соответствующие элементы. Также для закрепления знаний заодно ищем хэндл поля ввода TEdit на своей форме. Нашли – отлично. Теперь в поле ввода своей формы пишем сгенерированный серийник. А дальше пошли чудеса техники (шутка) – посылаем соответствующим окнам сообщения функцией SendMessage. Назначение каждого по порядку:
Вот таким трудным путем мы прошли, чтобы занести серийник из своей программы в чужую. А теперь осталось только посмотреть, активна ли кнопка "ОК" в окне ввода серийника. Для этого используем функцию IsWindowEnable, которой в качестве параметра передается хэндл окна кнопки. Соответственно, если она активна, значит серийник валидный и его можно поместить в TMemo и записать в файл.
При запуске на быстрой машине серийник находится за первые 4-5 минут. При этом все очень красиво бегает и меняется, можно снимать на видео и вставлять в фильмы про хакеров ;-)