Академический Документы
Профессиональный Документы
Культура Документы
Благодарности
В самом начале любой книги авторы любят кого-нибудь благодарить. Чест-
но сказать, я никогда не понимал этих вещей, но решил не отступать от
данной традиции и поблагодарить.
Своих родителей за то, что они произвели меня на свет. Если бы не они, не
было бы этой книги, по крайней мере в моем исполнении.
Своего кота Партизана (так его зовут) за то, что разбил раковину в ванной
комнате, и мне пришлось оторваться от дел, чтобы поставить новую. Благо-
даря этому происшествию я на короткое время отдохнул от компьютера, за
которым провожу как минимум 10 часов в сутки.
Свою дочь за то, что регулярно залазила ко мне на колени и беспорядочно
била по клавиатуре (когда я начинал писать эту книгу, ей еще не было
2 лет). Этим она сбивала меня с мысли, и приходилось снова настраиваться
на работу. Если бы не она, книга вышла бы намного раньше.
Свою жену. За что? Да за все.
Давыдова Дениса — главного редактора "Игромании". Когда-то он был ре-
дактором игровой части в журнале "Хакер", и мне повезло, что я начинал
свою писательскую деятельность в журнале именно с ним. Журнал тогда
только начинал свое развитие, и Денис уделял мне достаточно много време-
ни. Я программист и выжать из себя пару литературных строк в то время
вообще не мог (да и сейчас я в этом деле не гений, у меня в школе по рус-
скому и литературе всегда было 3 с большим минусом), а Денис мне дал
пинок, от которого я, можно сказать, начал свою карьеру.
Покровского Сергея aka SINtez — главного редактора журнала "Хакер". По-
сле того как Давыдов Денис ушел из журнала, я какое-то время стал меньше
публиковаться, но потом меня, можно так сказать, взял под крыло Сергей.
Сначала я стал вести рубрику "Hack-Faq", а потом и "Кодинг", которая
очень быстро развилась и получила популярность.
2_ Введение
О книге
Как вы наверно уже поняли, я заядлый программист и в течение всей книги
не буду блистать литературным стилем. Зато я постараюсь поделиться свои-
ми знаниями и надеюсь рассказать вам что-то новое.
В течение всей книги я буду рассказывать вам про программирование для
хакера. Я буду достаточно часто использовать один термин — "кодинг ". Что
это такое? Под этим словом мы будем как и все подразумевать слово про-
граммирование. А вот под словом "хакер" лично я подразумеваю немного
другой смысл, чем другие. Я считаю, что хакер — это профессионал в ком-
пьютерной сфере, но не обязательно доставляющий много неприятностей
другим людям своими знаниями. Так вот, в этой книге я постарался пока-
зать много интересных вещей с точки зрения сетевого программиста-
профессионала, а не взломщика. Более подробно о понятии "хакер" расска-
зано в следующем разделе.
Я попробовал привести как можно больше нестандартных приемов про-
граммирования, недокументированные функции и возможности, а глав-
ное — продемонстрирую вам приемы работы с сетью в операционной сис-
теме Windows.
В книге приведено максимальное количество примеров на языке програм-
мирования Delphi. Для этого я написал множество шуточных программ
и сетевых приложений. Чистой теории будет мало, зато практических заня-
тий — хоть отбавляй.
Для понимания книги вам понадобятся хотя бы начальные знания среды
Delphi и сносное умение общаться с компьютером и мышкой. Что касается
сетевого программирования, то его я опишу полностью, начиная от основ и
закачивая сложными примерами. Так что тут начальные знания желательны,
но не обязательны. Если вы начинающий программист, то могу посовето-
вать для получения основ прочитать мою книгу по Delphi и посетить мой
сайт www.cydsoft.com/vr-online, где выложено достаточно много полезной
информации.
Если вы ожидали увидеть в данной книге примеры и описания вирусов, то
вы сильно ошиблись. Ничего разрушительного я делать и рассказывать не
буду. Я занимаюсь созиданием, а не разрушением. Чего и вам советую.
Введение 3_
Минимизация
и невидимость
Что самое главное при написании программ-приколов? Ну конечно же, не-
видимость. Программы, созданные в этой и следующих главах, будут неза-
метно сидеть в системе и выполнять нужные действия при наступлении оп-
ределенного события. Это значит, что программа не должна появляться на
панели задач или в списке запущенных программ в окне, выдаваемом при
нажатии <Ctrl>+<Alt>+<Del>. Так что прежде чем начать что-то писать,
нужно узнать, как спрятать свое творение от чужого глаза.
Помимо этого, программы-при колы должны иметь маленький размер. При-
ложения, создаваемые Delphi, достаточно "весомые". Даже простейшая
программа, выводящая одно окно, отнимет более 200 Кбайт на диске. Если
вы захотите отослать такую шутку по электронной почте, то отправка и по-
лучение письма с вашей программой отнимет лишнее время у вас и получа-
теля. Это не очень приятно, поэтому в этой главе я познакомлю вас с тем,
как можно уменьшить размер программ, создаваемых в Delphi,
П Options;
• About;
• Help.
S)ASPack2.11
i Project! еке
На вкладке Open File есть только одна кнопка — Open. Нажмите на нее и
выберите файл, который вы хотите сжать. Как только вы выберете файл,
программа перейдет на вкладку Compress и начнет сжатие (рис. 1.2).
Registered to:
UNREGISTERED
Versign 2L11 30 days
Compression Progress
Go!
Project1.exe
Vetiion 2.11
Open File j Compe i ss Opto
i ns | About | Help |
, f? C
' ompress resoucesj use Wnidows DLLol edei
I P Deate backup copy [ bak He] Г Preserve extra data
17 Auto run after loading г Add into content menu
Г ' ' м ', • Secto
i ns' name
Г - ч-п, I ,71,1 Language
! Unregistered veision Options aie not javed
Proe
i c1
l .exe
Рис. 1.З. Настройки ASPack
Давайте разберемся, как работает сжатие. Сначала весь код программы сжи-
мается архиватором. Если вы думаете, что он какой-то "навороченный", то
сильно ошибаетесь. Для сжатия используется обычный архиватор, только
оптимизированный для сжатия двоичного кода. После этого в конец сжа-
того кода добавляется код разархиватора, который будет программу разжи-
мать обратно. И в самом конце ASPack изменяет заголовок исполняемого
файла так, чтобы при старте сначала запускался разархиватор.
Теперь, когда вы запускаете сжатую программу, сначала заработает разархи-
ватор, который разожмет бинарный код программы и аккуратно разместит
его в памяти компьютера. Как только этот процесс закончится, разархиватор
передаст управление вашей программе.
Некоторые считают, что из-за расходов на распаковку программа будет ра-
ботать медленней!!! Я бы сказал, что вы не заметите разницу. Даже если и
будут какие-то потери, то они будут неощутимы (по крайней мере, на со-
временных компьютерах). Это происходит потому, что архивация хорошо
оптимизирована под двоичный код. И по сути дела, распаковка происходит
только один раз и в дальнейшем никакого влияния на работу программы не
оказывает. В результате потери в скорости из-за сжатия будут неощутимы.
При нормальном программировании с использованием всех "наворочен-
ных" возможностей типа визуальности и объектного программирования код
16 Глава 1
Второй метод мы уже обсудили выше, поэтому стается только описать пер-
вый вариант.
Если вы хотите создать программу действительно маленького размера, то
должны забыть про все удобства. Вы не сможете подключать визуальные
формы или другие удобные модули, написанные фирмой Borland для упро-
щения жизни программиста. Только API-функции самого Windows и ничего
больше.
Для того чтобы создать маленькую программу в Delphi, нужно создать но-
вый проект (по умолчанию Delphi при открытии сама создаст новый файл
проекта, но вы всегда можете создать новое приложение, выбрав File\New\
Application), и зайти в менеджер проектов (меню View\Project Manager).
Здесь нужно удалить все модули и формы (пункт Unit, он выделен на
рис. 1.4), чтобы остался только файл самого проекта (по умолчанию его имя
Projectl.exe). Никаких модулей в проекте не должно быть. Более подробно
о создании шаблона см. в разд. 1.3.
I Project Manager
(Ptojecti. zl New Remove ' Adiwrfe
Files Path
Щ ProjectGroupi D: \Program FilesVB orland\D elpN6\Piojects
H--JP Project! .exe D: \Progr am FilesVB orland\D elpN6\Piojeds
D:\Program Files\BotlandM}elphi6\Projecls
uses
Forms;
18 Глава 1
($R *.res}
begin
Application.Initialize;
Application-Run;
end.
Теперь можно скомпилировать абсолютно пустой проект. Для этого надо
выбрать в меню Project пункт Compile Project или нажать сочетание клавиш
<Ctrl>+<F9>. После компиляции выберите в меню Project команду
Information for Projectl. Появится окно с информацией о проекте. Окно, ко-
торое появилось передо мной, вы можете увидеть на рис. 1.5.
Help
В правой части окна должны быть описаны используемые пакеты. Так как
вы все удалили, значит, там должна красоваться надпись None. А вот с ле-
вой стороны должна быть описана информация о скомпилированном коде.
Самая последняя строка показывает размер файла, и у меня он равен
370 688 байт. Ничего себе "пустая программа"!!! Мы же ничего еще не напи-
сали. Откуда же тогда такой большой код?
Давайте разберемся, что осталось в нашем проекте, чтобы обрезать все то,
что еще не обрезано. Сразу обратите внимание, что в разделе uses подклю-
чен модуль Forms. Это объектный модуль, написанный "дядей Борландом",
а значит, его использовать нельзя, потому что именно он увеличивает раз-
мер нашей программы. Между командами begin и end используется объект
Application. Этот объект тоже использовать не надо, так как он не заботит-
ся о "фигуре" программы.
Большой объем, который появляется даже у пустой программы, как раз и
связан с объектом Application, который объявлен в модуле Forms. Хотя мы
Минимизация и невидимость 19
program Projectl;
uses Windows;
begin
end.
Снова откомпилируйте проект. Откройте окно информации и посмотрите
на размер получившегося файла. У меня получилось 8 192 байта (рис. 1.6).
Вот это уже по-человечески.
Packages Used •
-Program-' - - - (None]
S ошсе compiled: 22 ines
Code size: 3696 bytes
Data size: 1945 bytes
Initial stack size: 16384 bytes
File size 8192 bytes
Status' — -~
Pfojecti Successfully Compiled.
ж
Рис. 1.6. Окно информации о проекте
uses Windows;
var
Msg : TMsg;
Begin
Чтобы вызвать эту процедуру, нужно написать следующий код в любом мес-
те программы (желательно в начале):
asm
push I
push 0
call RegisterServiceProcess;
end;
В Delphi есть встроенный ассемблер, вы можете прямо среди кода на Пас-
кале писать код на ассемблере. В примере, показанном выше, использован
ассемблер для вызова процедуры RegisterServiceProcess. Инструкции
языка ассемблера нужно заключать между словами asm и and;. В примере
используется три инструкции. В первой в стек поднимается число i с по-
мощью операции push. Во второй строке в стек поднимается значение о.
Эти два числа, поднятые в стек, являются переменными для процедуры
RegisterServiceProcess. To же самое можно было бы сделать и с помощью
вызова функции Паскаля RegisterServiceProcess (О, 1), но мне захотелось
показать вам, как работает встроенный ассемблер. Да и тогда пришлось бы
изменить описание процедуры RegisterServiceProcess, которая регистри-
рует программу как процесс и в Windows 9x делает программу невидимой
в списке запущенных программ, который вы вызываете нажатием
<Ctrl>+<Alt>+<Del>. В последней инструкции ассемблера вызывается про-
цедура RegisterServiceProcess С ПОМОЩЬЮ оператора c a l l .
Теперь наша программа не будет видна и в Windows 9x Только вы долж-
ны учитывать, что этот код прекрасно работает в Windows 9x, но выдаст
ошибку в Windows 2000/XP, потому что в его ядре нет функции
RegisterServiceProcess. Поэтому вы должны знать, в какой системе будет
запускаться программа и можно ли использовать процедуру
RegisterServiceProcess.
Ь Delphi Б - Project2
|Рго|ес(2. 3 X
New Remove
Files Path
Щ ProiectGtoupi D APiogiam FilesSB otland'xD elphi6\Ptojects
В ЩЗ Project2.eKe D: \Program FilesSB orlandSD elphi6\Projects
Ш, •%$ Urriti DAPtogramFilesVBoilandSDelphiG^Projects
["""jj!gEZ]| Np
Теперь выбираем в меню Project пункт View Source. Если все в норме, то
в редакторе кода вы увидите код вашего проекта. Оставляем только первую
строчку program Projecti, а все остальное удаляем и вместо этого пишем
24 Глава 1
Листинг 4$ ;\}Щ1К>НмпЩ
uses
f$R *.RES}
var
Instance: HWnd;
WindowClass: TWndClass;
Handle: HWnd;
msg: TMsg;
//Процедура выхода из программы
procedure DoExit;
begin
Halt;
end;
if msg=wm__KeyDown then
if wpr-VK_ESCAPE then
poExit;
end;
//Создаем окно
Handle:=CreateWindowEx (0,'DX', " ,WS_POPUP, 1,1, 200, 200,0, 0,Instance,
nil) ;
ShowWindow(Handle, SW_SHOW);
UpdateWindow (Handle);
Теперь давайте подробно разберем листинг 1.1. После старта программа на-
чинает выполнение с первого begin (это место обозначено соответствую-
щим комментарием). Первой строкой кода идет вызов WinAPI-функции
GetModuieHandie. Она возвращает указатель модуля, который сохраняется
в переменной instance. Этот указатель нам пригодится немного позже.
Далее заполняется структура WindowClass. Эта структура используется при
создании нового класса окна. Для минимального приложения нам понадо-
биться заполнить следующие поля:
• style — стиль окна;
• Lpfnwndproc — сюда нужно записать указатель на процедуру, которая
будет вызываться на все пользовательские или системные события;
26 Глава 1
Как всегда я постараюсь давать как можно больше реальных примеров, что-
бы вы смогли убедится в том, что вам не вешают очередную лапшу на уши,
и смогли применить все сказанное на практике.
Начну с законов, которые работают не только в программировании, но
и в реальной жизни. Ну а напоследок я оставлю только то, что может при-
годиться при оптимизации кода.
ЗАКОН № 1
Оптимизировать можно все. Даже там, где вам кажется, что все и так ра-
ботает быстро, можно сделать еще быстрее.
Это действительно так. И этот закон очень сильно проявляется в програм-
мировании. Идеального кода не существует. Даже простую операцию сло-
жения 2 + 2 тоже можно оптимизировать. Чтобы достичь максимального
результата, нужно действовать последовательно и желательно в том порядке,
в котором описано ниже.
Помните, что любую задачу можно решить хотя бы двумя способами (или
больше), и ваша задача — выбрать наилучший метод, который обеспечит
желаемую производительность и универсальность.
ЗАКОН № 2
Первое, с чего нужно начинать, — это с поиска самых слабых и медленных
мест. Зачем начинать оптимизацию с того, что и так работает достаточно
быстро/ Если вы будете оптимизировать сильные места, то можете нарваться
на неожиданные конфликты. Да и эффект будет минимален.
Тут же я вспоминаю пример из своей собственной жизни. Где-то в 1995 году
меня посетила одна невероятная идея — написать собственную игру в стиле
Doom. Я не собирался ее делать коммерческой, а хотел только потрениро-
вать свои мозги на сообразительность. Четыре месяца невероятного труда, и
нечто похожее на движок уже было готово. Я создал один голый уровень, по
которому можно было перемещаться, и с чувством гордости побежал по ко-
ридорам.
Никаких монстров, дверей и атрибутики на нем не было, а тормоза ощуща-
лись достаточно значительные. Тут я представил себе, что будет, если доба-
вить монстров и атрибуты, да еще и наделить все это AI.... Вот тут чувство
собственного достоинства поникло. Кому нужен движок, который при раз-
решении 320x200 (тогда это было круто!) в голом виде тормозит со страшной
силой? Вот именно....
Понятное дело, что мой виртуальный мир нужно было оптимизировать.
Целый месяц я бился над кодом и вылизывал каждый оператор моего движка.
Минимизация и невидимость 31_
ЗАКОН № 3
Следующим шагом вы должны разобрать все операции по косточкам и выяс-
нить, где происходят регулярно повторяющиеся операции. Начинать оптимиза-
цию нужно именно с них.
Опять начнем рассмотрение этого закона с программирования. Допустим,
что у вас есть следующий код (приведена просто логика, а не реальная
программа):
1. А:=А*2;
2. Б:=1|
3. Х:=Х+М[Б];
4. Б:=Б+1;
5. Если Б<100 то перейти на шаг 3.
Любой программист скажет, что здесь слабым местом является первая стро-
ка, потому что там используется умножение. Это действительно так. Умно-
жение всегда выполняется дольше, и если заменить его на сложение
(А:=А+А) ИЛИ еще лучше на сдвиг, то вы выиграете пару тактов процессорного
времени. Но только пару тактов, и для процессора это будет незаметно.
Теперь посмотри еще раз на наш код. Больше ничего не видишь? А я вижу.
В этом коде используется цикл: "Пока Б<100, будет выполняться операция
Х:=Х+М[Б|". Это значит, что процессору придется выполнить 100 переходов
с шага 5 на шаг 3. А это уже немало. Как можно здесь что-то оптимизиро-
вать? Очень легко. Здесь у нас внутри цикла выполняется две строки: 3 и 4.
А что, если мы внутри цикла размножим их 2 раза:
1. Б : = 1 |
2. Х:=Х+М[Б];
3. Б:=Б+1;
4. Х:=Х+М[Б];
5. Б:=Б+1;