Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
assmblr.doc
Скачиваний:
168
Добавлен:
15.03.2015
Размер:
486 Кб
Скачать
☆

4. Выполнение (запуск) программы

Запуск .EXE-программы может быть осуществлён с помощью двойного щелчка мышью.

Если вы создали программу, которая ничего не выводит на экран, то за её работой можно наблюдать при помощи программы-отладчика, например, OllyDbg. Отладчики позволяют наблюдать за изменением содержимого регистров и флагов. Подробнее работа в отладчике OllyDbg будет описана ниже.

2.4. Инструментальный пакет masm32

В п.2.3 отмечено, что для создания программ на ассемблере в Windows, необходим текстовый редактор и компилятор. Реальные программы Win32 используют также внешние функции, стандартные константы и переменные, ресурсы и много другое. Всё это требует дополнительных файлов, которые есть в инструментальном пакете MASM32. Важно понять, что MASM32 не компилятор, а сборник для программирования под Win32, в который входит 32-битный компилятор MASM.

Инструментальный пакет MASM32 предназначен для создания приложений Windows на языке ассемблера и содержит все необходимые инструменты, к тому же он распространяется бесплатно.

Основные сведения и порядок работы в пакете masm32:

1. Для создания исходных текстов программ рекомендуется использовать текстовый процессор пакета MASM32 под названием QEDITOR (от Quick Editor, быстрый редактор):

После набора сохранить текст программы командой File – Save, указать папку BIN и расширение .ASM, например MYPROG.ASM.

2. Командой Project – Build All создать объектный и исполнимый файлы:

Если исходный текст программы набран без ошибок, то в папке, где он хранился, увидим два новых файла: MYPROG.OBJ и MYPROG.EXE.

3. Когда объектный и исполнимый файлы созданы, запустите программу на выполнение. Для этого можно дважды щелкнуть мышью по названию исполнимого файла (в папке BIN) или запустить программу через редактор QEDITOR командой Project – Run Program.

2.5. Примеры

Пример 0. «Скелет» стандартной программы

.386

.model flat, stdcall

option casemap :none

;подключение необходимых библиотек

include \MASM32\INCLUDE\windows.inc

include \MASM32\INCLUDE\masm32.inc

include \MASM32\INCLUDE\gdi32.inc

include \MASM32\INCLUDE\user32.inc

include \MASM32\INCLUDE\kernel32.inc

includelib \MASM32\LIB\masm32.lib

includelib \MASM32\LIB\gdi32.lib

includelib \MASM32\LIB\user32.lib

includelib \MASM32\LIB\kernel32.lib

;раздел, где объявляются все константы

.const

;раздел, где объявляются переменные, уже имеющие какое-то значение

.data

;раздел, где объявляются переменные, еще не имеющие значения

.data?

.code

start: ;с этого слова начинается код программы

invoke ExitProcess,0

end start ;с этого слова заканчивается код программы

Сохраните этот «скелет» в отдельном файле для удобства и используйте как заготовку.

Пример 1. Структура программы и основные директивы

Построчно разберём простейшую программу.

Текст программы на ассемблере содержит кроме инструкций процессору еще и служебную информацию (в виде директив), предназначенную для программы-ассемблера.

Начнем с простого. В первой программе не будет вызовов API-функций, ее цель – понять саму структуру программы на языке ассемблера для Windows. Поэтому программа, прибавляющая к 2 число 3, будет выглядеть следующим образом:

.386

.model flat, stdcall

.code

start:

mov eax, 8

add eax, 8

ret

end start

В ней инструкции процессора mov, add, ret окружены директивами. Первые три директивы начинаются с точки.

Директива .386 показывает, для какого процессора предназначена программа. В нашем случае это процессор Intel 80386 и более поздние модели, ведь семейство процессоров Intel совместимо снизу вверх.

Вторая директива .model flat, stdcall показывает, в какой среде будет работать программа. Все программы работают под управлением операционной системы, которая их запускает и обеспечивает взаимодействие с внешней средой. Директива .model задаёт модель памяти flat (плоская или сплошная) для нашей программы. Эта модель памяти используется для программирования под Windows, т.е. директива говорит о том, что именно для операционных систем семейства Windows 952 предназначена программа.

Stdcall - это "уговор" о том, кто будет чистить параметры (функция, которую вызвали, или сам вызывающий). Мы всегда будем использовать вариант "функция чистит свои параметры". Он и называется stdcall. Однако такое объяснение не полное, и мы вернемся к параметру stdcall при объяснении вызова функций. К этому моменту вы уже будете знать, что такое стек.

Третья директива .code показывает, где начинаются сами команды процессора. Когда операционная система пытается запустить программу, она ищет в ней инструкцию, с которой нужно начать, и отправляет ее процессору. Когда же инструкции кончаются, операционная система «подхватывает» программу и помогает ей правильно завершиться, чтобы освободить место другим, ведь Windows – многозадачная операционная система, способная выполнять одновременно несколько программ. Уйти из-под «опеки» операционной системы помогает инструкция ret.

Инструкция, с которой начинается программа, обычно помечается последовательностью символов с двоеточием на конце (меткой). В нашем случае это start:. Там, где оканчивается последовательность команд процессора, в программе должна стоять директива end <метка первой инструкции программы>, в нашем случае это end start. Эта директива, а также сама метка не переводятся в инструкции ассемблера, а лишь помогают получить программу, которую способен выполнить процессор. Без них программа-ассемблер не поймет, с какой инструкции процессор начнет работу.

Отладка

Программа ничего не выводит на экран, поэтому за для изучения её работы воспользуемся программой-отладчиком OllyDbg. Чтобы открыть программу в отладчике, достаточно загрузить OllyDbg и открыть программу как обычный документ – File-Open.

В верхней левой части отладчика можно увидеть свою программу. Вверху справа – регистры процессора.

Внизу слева - байты памяти (OllyDbg сразу же показывает секцию данных программы). Внизу справа отображается содержимое стека (работа со стеком будет описана ниже).

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

С помощью клавиши F8 можно выполнить программу по шагам и просмотреть, как меняется содержимое регистров. Ответьте на вопрос, почему в результате сложения 8+8 регистр EAX стал равен 10? Состояние флагов также меняется. Мы видим, что после выполнения первой команды флаг Z опустился (обратился в ноль), потому что результат выполнения операции не равен нулю.

Пример 2. Использование функций API

У предыдущей программы не было связи с внешним миром, она ничего не считывала с клавиатуры и не выводила на экран. О том, что она делала, мы могли узнать только с помощью отладчика. Обычно программам помогает общаться с окружающим миром операционная система, которая берет на себя все детали взаимодействия с внешними устройствами. В системе Windows, для этого служат функции API.

API – это стандартные функции, на основе которых и пишут все программы для Windows. Например MessageBox выдаёт сообщение на экран, PostQuitMessage сообщит Windows, что программа хочет закончить работу и т.д. Все они уже готовы – остается только вызывать их. Получается, что используя API-функции, мы применяем элементы программирования высокого уровня.

Находятся API-функции обычно в динамически загружаемых библиотеках – файлах с расширением .DLL.

При вызове каждой API-функции надо передавать параметры, т.е. аргументы, с которыми ей предстоит работать. Раньше это делалось так: параметры заталкивались в стек (команда push) задом наперед – сначала последний, потом предпоследний и т.д., а затем вызывалась сама программа (команда call). Например:

push addr Text2

push addr Text1

push hWnd

call MessageBox

Такая запись допускается и сейчас, но существует и более компактная: invoke MessageBox, hWnd, Text1, Text2

Правда, использование invoke требует прототипов для каждой вызываемой программы, но прототипы API готовы и хранятся в соответствующих файлах включения.

Рассмотрим программу с использованием функций API. Прежде чем приступить к выводу на экран, изучим более простую процедуру ExitProcess. Её вызывает каждая Windows-программа, чтобы завершить свою работу. В ассемблере под DOS мы пользовались инструкцией возврата ret. Но ExitProcess действует правильнее, не только возвращая управление операционной системе, но и освобождая занятые программой ресурсы.

В следующем листинге показана программа для Windows, которая только и делает, что правильно завершается.

.386

.model flat, stdcall

option casemap:none

includelib C:\MASM32\LIB\kernel32.lib

ExitProcess proto :DWORD

.code

start:

push 0

call ExitProcess

end start

Вызываемая в ней процедура ExitProcess требует одного параметра – это код завершения, возвращаемый операционной системе. Он передается процедуре командой push 0. Число 0 считается признаком удачного завершения.

Поскольку ExitProcess – «чужая» процедура, не определенная в нашей программе, ассемблер должен знать, где она находится, а также (для проверки – она ли это) число и размер ее параметров.

Сведения об адресе и параметрах процедуры хранятся в файле библиотеки kernel32.lib, который подключается к ассемблерному тексту директивой includelib C:\MASM32\LIB\kernel32.lib.

Перед тем как создать инструкцию вызова этой процедуры компоновщик сравнивает сведения из библиотеки с прототипом ExitProcess proto :DWORD, и если все совпадает, создает пригодный к исполнению файл с расширением .EXE. Прототип процедуры очень прост и состоит из имени, слова proto и параметров. В нашем случае параметр один – это двойное слово (то есть 4 байта) DWORD. Если параметров несколько, они разделяются запятой.

Пример 3. Вывод строки на экран

Создадим программу, выводящую на экран фразу “Hello, world!”:

.386

.model flat, stdcall

option casemap:none

ExitProcess proto :dword

GetStdHandle proto :dword

WriteConsoleA proto :dword, :dword, :dword, :dword, :dword

includelib C:\MASM32\LIB\kernel32.lib

.data

stdout dd ?

msg db “Hello, world!”, 0dh, 0ah

cWritten dd ?

.code

start:

invoke GetStdHandle, -11

mov stdout, eax

invoke WriteConsoleA, stdout, ADDR msg, sizeof msg, ADDR cWritten, 0

invoke ExitProcess, 0

end start

В программе вызываются три процедуры: GetStdHandle, WriteConsoleA и ExitProcess.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]