Трудовая дисциплина Крис Касперски 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"! Вот ассемблер и постеснялся разводить самодеятельность! |