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

Трудовая дисциплина

Крис Касперски aka мыщъх

Хакер, номер #088, стр. 088-114-6


[MASM, TASM и FASM]

Будем считать, что мы достаточно созрели для ассемблирования всей программы целиком. Казалось бы, чего же тут сложного? Бери и транслируй. Ан-нет! Вот еще один классический пример, выловленный на просторах Сети и по замыслу своего создателя выводящий "hello,world":

.386

.model flat

extern ExitProcess:PROC

extern MessageBoxA:PROC

.data

s0 db 'hello, world',0

.code

start:

push 0

push 0

push offset s0

push 0

call MessageBoxA

push 0

call ExitProcess

end start

Транслируем программу MASM'ом, последнюю версию которого можно позаимствовать из NTDDK:

ml /c /coff hello.asm,

где /c - ключ, означающий «только ассемблировать, не линковать» (линкованием мы займемся самостоятельно, только позже), /coff – транслировать в coff-файл (по умолчанию создается omf, с которым мало кто из линкеров умеет работать). Ну а hello.asm – имя нашего файла. MASM ругается: «warning A4022: with /coff switch, leading underscore required for start address: start», но вроде бы ассемблирует. Постой, но ведь у нас уже есть метка start, заданная в качестве стартового адреса! Что же транслятору еще надо?! Уродский Microsoft! MASM хочет иметь «_start» (с подчеркиваем), а у нас подчеркивания и нет! Выход: заменить start на _start или в модели памяти указать тип вызовов «stdcall».

Теперь программа ассемблируется без проблем, и наступает черед ее линковать. Это делается так:

link /SUBSYSTEM:WINDOWS hello.obj KERNEL32.LIB USER32.lib,

где SUBSYSTEM - ключ, отвечающий за выбор подсистемы (в данном случае WINDOWS, еще есть CONSOLE для консольных программ и NATIVE для драйверов), hello.obj - имя линкуемого файла, KERNEL32.LIB и USER32.LIB - имена необходимых библиотек, поставляемых вместе с Platform SDK. Если же SDK нет, то линкер ms link может сгенерировать их самостоятельно, стоит только указать ему ключ /IMPLIB:KERNEL32.DLL. Откуда мы знаем, какие библиотеки нужно подключать? Ответ дают вызываемые API-функции: ExitProcrss, экспортируемая KERNEL32.DLL и MessageBoxA, экспортируемая USER32.DLL, о чем написано в SDK. Если же SDK нет - смотри экспорты всех системных библиотек любой подходящей утилитой типа dumpbin.

Только все равно ни хрена у нас не линкуется!

hello2.obj : error LNK2001: unresolved external symbol _ExitProcess

hello2.obj : error LNK2001: unresolved external symbol _MessageBoxA

hello2.exe : fatal error LNK1120: 2 unresolved externals

Вот так номер! Линкер не может найти функции! Почему? Заглянув в USER32.lib hex-редактором, мы увидим, что MessageBoxA там объявлена как _MessageBoxA@16, где _ - признак stdcall-вызова, а @16 - размер всех аргументов функции в байтах. Соответственно, ExitProress зовется как _ExitProcess@4, поскольку принимает всего один аргумент, а в 32-разрядном режиме все они двухсловные.

Все равно ни хрена не понятно! Мы же уже сказали, что модели памяти – stdcall, и транслятор послушно добавил ко всем функциям знак подчеркивания. Но оказывается, что он забыл дописать аргументы. А как бы он их дописал? Ведь прототип функции объявлен как "PROC"! Вот ассемблер и постеснялся разводить самодеятельность!

Назад на стр. 088-114-5  Содержание  Вперед на стр. 088-114-7