Немного лирики

Доброго времени суток, уважаемый читатель!
Я — новый автор статей для сайта www.xakep.ru и,
начиная с этой статьи, буду вести здесь цикл
публикаций, посвящённый вопросам сетевой
безопасности и сетевого программирования
платформ Windows и UNIX.

К сожалению (надеюсь, не для многих), я буду
игнорировать всеобщую любовь к Delphi и, нагло
загиная привычную мне линию, буду
вворачивать примеры, написанные на
классическом ANSI C (так называемый gnu style) и на
ассемблере UNIX’ового синтаксиса архитектуры
x86. Однако, я попытаюсь искупить этот грешок,
снабжая исходный текст своих программ
подробными комментариями. Ведь, как говорил
один мой знакомый, не самый последний
человек в хакерском мире, "главное — не
знание языка программирования, а умение им
воспользоваться!". Очень рассчитываю на
то, что этот аргумент сохранит меня от очень
модной на этом сайте деликатности тех самых
немногих читателей 🙂

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

Cygwin: что это такое?

Cygwin — это аббревиатура от ‘Cygnus’, группы
разработчиков свободного ПО в рамках
проекта ‘RedHat’ и ‘Windows’, всеми нами любимой
операционной системы. Спешу развеять очень
популярную точку зрения, будто бы cygwin — это
эмулятор UNIX под Windows: это не так! Cygwin — это
лишь мощный, очень развитый и, самое главное,
бесплатный набор программных средств
переноса (портирования) UNIX’ового ПО под Windows
и кросс-компиляции (создания бинарного кода
на одной платформе под другую) UNIX’овго софта.
Лично для меня, cygwin, прежде всего, это
мощнейший компилятор gcc с отшлифованными
под Windows хидерами и либами.

Cygwin нынче становится весьма популярным:
многие производители свободного ПО под UNIX
поддерживать ‘—target=cygwin’ в конфигах своих
программ, благо, это не столь трудоёмко. А
cygwin, в свою очередь, расширяет
совместимость с UNIX, поддерживая не только
posix, но и другие, более узкоспецифичные
стандарты UNIX-систем.

Cygwin: где смотреть?

http://www.cygwin.com
официальная страница cygwin’а, на которой Вы
сможете найти достаточное количество
информации о текущем состоянии проекта, об
обновлениях cygwin’овских релизов, а также
официальный список ftp-серверов, периодично
зеркалящих cygwin.

Cygwin: что и как устанавливать?

На Хакере уже несколько раз писали про
установку и использование Cygwin, поэтому
рекомендую вам обратится к тем статьям:
CYGWIN
— *nix в ваших Виндах
Особенности
настройки Cygwin

gcc: какой он?

Точно такой же, как и в UNIX. Сочный, мощный,
безглючный. Однако, не такой быстрый. Дело в
том, что запуск препроцессора, компилятора,
ассемблера и линковщика требует
определённого времени на загрузку и
пролинковку в памяти библиотеки cygwin1.dll,
требумую каждым из этих компонентов gcc.
Отмечу, что в Windows 2000 это требует на порядок
меньше времени, чем в Windows 98. Скорость
компиляции в Windows 2000 очень близка к скорости
компиляции в UNIX. Но сок остаётся соком:
генерируемый бинарный код cygwin’ным gcc
остаётся вне конкуренции по компактности и
эффективности!

Если Вы когда-либо писали или компилировали
программы под UNIX, Вы не будете испытывать
никаких трудностей в работе с cygwin. Только
помните, что cygwin’ный gcc может не
поддерживать некоторые опции, которыми Вы
пользуетесь в UNIX’е, хотя количество таких
недоразумений сведено к минимуму. На моём
веку, например, таких проблем не возникало.
В любом случае, если возникают какие-то
проблемы, все мы дружно знаем лучший способ
их решения: ‘man gcc’! :)))

Если же Вам не доводилось прежде заниматься
программированием под UNIX и Вы привыкли жать
<F9> для того, чтобы скомпилировать Вашу
программу, расстраиваться не стоит.
Попробуйте ‘man gcc’ в bash’е cygwin’а: вполне
достойное и увлекательное чтиво.

Таки начнём?

Оригинальничать я не буду, поэтому начнём
мы, как всегда и везде, с вывода ‘hello world!’ на
консоль. Итак, hello.c:

#include <stdio.h>
int main () {
printf("Hello World!\n");
return 0;
}

Компилируем:

gcc -s hello.c -o hello.exe

и смотрим на бинарник. 3072 байта бинарного
кода, формат PE, portable executable, загружаемые dll:

cygwin1.dll, откуда hello.exe берёт нашу printf() и другие
функции, которые накомпилировал нам gcc;
kernel32.dll, откуда hello.exe берёт GetModuleHandleA.

Хидер <stdio.h> gcc берёт из /usr/include, который
является дефолтной инклудной директорией и
в UNIX, и в cygwin’е.

В cygwin’ном gcc есть одна очень приятная опция,
которая, почему-то, не задокументирована в
man-файле, ‘-mno-cygwin’. Скомпилируем нашу
программу с этой опцией:

gcc -mno-cygwin -s hello.c -o hello.exe

и смотрим на бинарник: опять, 3072 байта
бинарного кода, но наша программа больше не
нуждается в cygwin1.dll! вместо этого она
использует msvcrt.dll, где и находит нужную нам
функцию printf.

Если мы юзаем опцию ‘-mno-cygwin’, cygwin кидает gcc’шный
препроцессор в директорию /usr/include/mingw, и,
соответственно, gcc компилирует <stdio.h>
именно из этой директории.

Настоятельно рекомендую совершить
прогулку по содержимому директории /usr/include
для того, чтобы понять, что к чему. Думаю, Вас
особо порадует содержимое директорий /usr/include/sys
и /usr/include/w32api.

Таким образом, cygwin находит компромисс между
двумя противоречащими друг с другом
платформами, UNIX и Windows и даёт нам уникальный
шанс изучать программирование под UNIX, не
покидая Windows. Далее следует пример
простенькой программки, компилирующейся и
под posix’овые BSD Sockets, и под WinSock2. Программка
открывает указанный в командной строчке
порт и ожидает tcp-соединение с любого IP-адреса,
принимает от клиента литеру и возвращает
клиенту эту же литеру, увеличенную на
единицу. Вы можете скомпилировать эту
программку, запустить её (‘easy.exe 500’),
приконнектиться к ней телнетом (‘telnet 127.0.0.1
500’) и ввести любой символ.

—[ Makefile (для неюниксоидов, Makefile с
заглавной буквы ‘M’):

# tiny makefile for a tiny program

all:
@echo Pick ‘make posix’ for UNIX/cygwin or ‘make windows’ for Windows

posix:
@printf "Building easy.c for posix…"
@printf "#define ENV_POSIX" > plateform.h
@gcc -s easy.c -o easy.exe
@echo ok!

windows:
@printf "Building easy.c for windows…"
@printf "#define ENV_WINDOWS" > plateform.h
@gcc -mno-cygwin -s easy.c -lws2_32 -o easy.exe
@echo ok!

—[ easy.c:

#include «plateform.h»
#include <stdio.h>

#ifdef ENV_POSIX
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> // для INADDR_ANY
#include <signal.h> // для signal()
#else
#include <winsock2.h>
#endif

int main (int argc, char **argv) {

struct sockaddr_in dst;
#ifdef ENV_POSIX
int sock, sid;
#else
SOCKET sock, sid;
WSADATA wsaData;
#endif
int len = sizeof(struct sockaddr);
char buf;
unsigned short port;

// entry point

if(argc<2) {
printf(«Usage: easy.exe <tcp-port>\n»);
return 1;
}

port = atoi(argv[1]);

if(!port) {
printf(«Bad <tcp-port> defined!\n»);
return 2;
}

#ifdef ENV_POSIX // в позиксе мы игнорируем сигналы, мало ли 🙂
signal(SIGPIPE, SIG_IGN);
#else ENV_WINDOWS // в Windows мы проверяем версию винсока, мало ли 🙂
printf(«Testing if the WinSock2 version is equal or higher than 2.1…»);
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0) {
printf(«failed!\n»);
return 1;
}
printf(«ok!\n»);
fflush(stdout);
#endif

dst.sin_family = AF_INET;
dst.sin_addr.s_addr = htonl(INADDR_ANY);
dst.sin_port = htons(port);
sock = socket(AF_INET,SOCK_STREAM,0);
printf(«Waiting for an incoming connection…»); fflush(stdout);
bind(sock,(struct sockaddr*)&dst,len);
listen(sock,1);
sid = accept(sock,(struct sockaddr*)&dst,&len);
printf(«done!\nWaiting for incoming data…»); fflush(stdout);
recv(sid,&buf,1,0);
printf(«received: [%2X]…»); fflush(stdout);
buf++;
send(sid,&buf,1,0);
printf(«done!\n»);

#ifdef ENV_POSIX
close(sock);
#else
WSACleanup();
closesocket(sock);
#endif

return 0;
}

Итак, мы набираем ‘make posix’ для того, чтобы
собрать программу под UNIX’ом или под cygwin’ную
среду или ‘make windows’ для того, чтобы не
зависеть от cygwin’а и использовать лишь
kernel32.dll, ws2_32.dll и msvcrt.dll, которые входят в
стандартную поставку каждого дистрибутива
Windows. Обратите внимание на размер бинарника:
4096 байт для cygwin, 4608 байт для windows! 🙂

На этот раз всё! Ждите вскоре следующей
статьи в ближайшее время: "Технология
сканирования сетей: Cокетный движок".

Оставить мнение

Check Also

Безопасность превыше всего. 9 простых трюков, которые сделают жизнь линуксоида секьюрнее

Жизнь обычных людей складывается из мелочей. Жизнь линуксоида складывается из множества ма…