Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #90, ИЮНЬ 2006 г.

Трюки от Криса

Крис Касперски

Хакер, номер #090, стр. 090-128-3


if (a) x += f(a, ((n < MAX) && n++));

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

Хак №7 – объявление функций вручную

Программирование под windows требует включения огромных include-файлов, заметно снижающих скорость трансляции, что раздражает. Но ведь необходимые функции можно объявить и самостоятельно! Следить за соблюдением прототипов не обязательно, главное — указать компилятору, чтобы он вызывал их по соглашению stdcall:

// #include <windows.h>

int __stdcall MessageBoxA();

main()

{

MessageBoxA(0,"hello,sailor","hello",0);

}

(компиляция: cl.exe file_name.c USER32.lib)

Хак №8: отказ от кучи и динамической памяти

Любовь программистов к динамической памяти с позиции здравой логики ничем, кроме мракобесия, необъяснима. Куча — это тормоза и потенциальные утечки, про борьбу с которыми написано столько, что…

Хакеры активно используют статические массивы, выделяемые операционной системой на еще стадии загрузки файла, а динамическая память выделяется/освобождается каждый раз! Рассмотрим следующий "пионерский" код, который можно встреть даже в профессиональных программах.

f(char *s)

{

p = malloc(sizeof(s) + 1);

…

if (something_goes_wrong) return -1; // ошибка! преждевременный выход

…

free(p);

return val;

}

Кажущаяся потребность в динамической памяти объясняется переменным размером строки s, передаваемой функции f(). И все было бы хорошо, если бы не коварная ошибка, приводящая к преждевременному выходу из функции без освобождения!

А вот "хакерский" вариант, использующий статическую память вместо хипа:

f(char *s)

{

static char p[MAX_POSSIBLE_SIZE];

if ((sizeof(s)+1)> MAX_POSSIBLE_SIZE) return -1;

…

if (something_goes_wrong) return -1;

…

return val;

}

Мы увеличили производительность, избавились от проблем с утечками, но... сделали функцию нерентабельной. В практическом плане это означает невозможность рекурсии (но в данном случае функция заведомо не рекурсивна), и запрет на одновременный вызов функции из двух и более потоков, иначе в статическом массиве образуется "мешанина" данных и наступит крах, предотвратить который можно либо путем принудительной синхронизации (критические секции, мутанты), либо через локальную память потока, известную под аббревиатурой TSL, впрочем, учитывая корявость поддержки этой самой TSL нынешними компиляторами, ни один здравомыслящий хакер ни за что ей не воспользуется.

Хак №9 — программирование без RTL

По умолчанию си-программы собираются вместе с библиотекой времени исполнения (она же RTL), которая занимает много килобайт и обеспечивает работу функций типа spritnf. Но ведь Windows NT уже включает в себя RTL, реализованную в NTDLL.DLL, так зачем же нам еще одна?

Назад на стр. 090-128-2  Содержание  Вперед на стр. 090-128-4