- •Аппаратно-ориентированное программирование
- •Ббк 32.973.73
- •Удк 681.3 ббк 32.973.73ф 73
- •1. Основы программирования на ассемблере
- •1.1. Принципы построения ассемблерных программ
- •1.2. Понятие архитектуры компьютера
- •1.3. Регистры программиста в ia32
- •1.4. Описание сегментной структуры программы
- •2. Простейшие средства ассемблера
- •2.1. Средства описания данных
- •2.2. Обращения к функциям ос посредством прерываний
- •2.3. Средства преобразования в исполняемый файл
- •2.4. Управление строками при выводе и ввод данных
- •2.5. Простейшие способы адресации
- •3. Архитектурные элементы для построения программ
- •3.1. Организация условных переходов
- •3.2. Средства организации циклов
- •3.3. Особенности команд умножения и деления
- •3.4. Организация процедур
- •3.5. Неарифметические операции над кодами
- •4. Использование неэлементарных способов адресации
- •4.1. Косвенно-регистровая адресация
- •4.2. Использование индексной адресации данных
- •4.3. Базовая и индексно базовая адресации
- •4.4. Адресация с масштабированием
- •5. Взаимосвязи программных единиц
- •5.1. Многомодульная разработка программ
- •5.2. Использование библиотек объектных модулей
- •5.3. Организация стекового кадра подпрограммы
- •5.4. Программный доступ к системным функциям Win32
- •5.5. Особенности использования объектных файлов формата coff
- •5.6. Стандартный доступ к системным функциям Unix
- •6. Вспомогательные средства базовой архитектуры
- •6.1. Использование строковых команд пересылки
- •6.2. Применение строковых команд сравнения
- •7. Использование ассемблерных отладчиков
- •7.1. Особенности отладчика gdb для программ в Linux
- •7.2. Отладчики текстового режима для Windows
- •Библиографический список
- •Оглавление
7.2. Отладчики текстового режима для Windows
В связи со сложившейся спецификой операционных систем типа Windows, ориентированных в первую очередь на неквалифицированных пользователей и поэтому использующих преимущественно графический интерфейс, преобладающая часть отладчиков для этих ОС обеспечивают отладку только графических приложений. В частности только этими возможностями обладают отладчики известной фирмы Borland/Inprise.
К настоящему времени отдельные самостоятельные разработчики предлагают неплохие программные продукты - не очень известные среди корпоративных пользователей, но эффективные, надежные и, главное для высшей школы, - не требующие материальных затрат на их приобретение. В качестве такого программного инструмента рассмотрим отладчик OllyDbg, разработанный Oleh Yuschuk и доступный по электронному адресу на Internet сайте http://home.t-online.de/home/Ollydbg.
Отладчик OllyDbg, версию 1.09 которого мы рассматриваем, есть 32-битный отладчик ассемблерного уровня с внутренними средствами анализа кода для Microsoft Windows(R). Он не требует инсталляции, и для использования его программные компоненты нужно просто поместить в отдельное оглавление. Данный отладчик представляет собой свободно распространяемое программное обеспечение (shareware) с авторскими правами - Copyright (C) 2000-2003 Oleh Yuschuk.
Имя исполняемого файла отладчика - OLLYDBG.EXE, по которому его и следует запускать. Имя исполняемого файла отлаживаемой программы может задаваться как аргумент строки вызова отладчика. Отладчик имеет очень широкие возможности, в том числе отладку графических приложений и библиотек динамической компоновки. Поэтому его пользовательский интерфейс основан на графическом окне приложения (а не текстовом окне, как ранее рассмотренный отладчик gdb для Linux).
Практически более удобно запускать отладчик из его собственного оглавления, как текущего при таком запуске (или с помощью ярлыка). Причем, запускать без аргумента - имени исполняемого файла, а исполняемый файл задавать с помощью меню отладчика. После начального запуска программы OLLYDBG.EXE следует использовать раздел File в главном меню отладчика и пункт Open этого раздела для задания через диалоговую панель имени исполняемого файла - в любом желаемом оглавлении.
Основная информация, предоставляемая разработчику отладчиком, размещается в нескольких панелях основного окна отладчика. Основной панелью является панель, называемая окном CPU, которая предоставляет дизассемблированный текст исполняемого файла.
Работа отладчика OllyDbg управляется с помощью мыши или с помощью клавиатуры, в частности с помощью управляющих комбинаций «горячих клавиш».
Точки приостановки (контрольные точки) устанавливаются выбором требуемой строки дизассемблированного текста в окне CPU и нажатием клавиши F2, причем эта клавиша действует как переключатель установки контрольной точки - повторное нажатие этой клавиши на строке с уже установленной контрольной точкой выключает ее (контрольная точка на данной строке изчезает).
Для удобства демонстрации конкретных средств отладки в качестве опорного примера возьмем программу, приведенную в листинге 7.2.1.
; Вывод десятичного значения содержимого EAX в MS Windows
EXTERN GetStdHandle, WriteFile, ExitProcess
SEGMENT CODE USE32 CLASS=CODE
..start:
push dword STD_OUTPUT_HANDLE
call GetStdHandle
mov [hstdout],eax
mov eax, 1000h
mov esi,10 ; base of position digit system
mov ecx, 0 ; reset digit counter
pov: mov edx, 0 ; null into left part of devident
div esi ; divide for next digit = rest
add dl, '0'
push edx
inc ecx ; step into counter
cmp eax, 0
jne pov
mov [cnt], ecx
mov ebx, numtxt
izv: pop edx
mov byte [ebx],dl ; digit into array for text value
inc ebx
loop izv ; izv,ecx
;--- WriteFile(hstdout, txt, 7, &actlen, NULL)
push dword 0
push dword actlen
push dword [cnt] ; number of bytes
push dword numtxt ; address of txt
push dword [hstdout] ; N handle=hstdout
call WriteFile
; ExitProcess(0)
push dword 0
call ExitProcess
SEGMENT DATA USE32 CLASS=DATA
numtxt times 10 db 0 ; may be <resb 10> but then - warning!
cnt dd 0
hstdout dd 0
actlen dd 0
STD_OUTPUT_HANDLE equ -11
Листинг 7.2.1. Пример программы PRIM4.asm для отладкиРис
После запуска под отладчиком исполняемого файла, полученного ассемблированием и компоновкой (с помощью компоновщика TLINK32) программы в листинге 7.2.1, в панели CPU отладчика можно наблюдать следующий текст, приведенный в листинге 7.2.2.
00401000 68 F5FFFFFF PUSH -0B ; DevType = STD_OUTPUT_HANDLE
00401005 E8 62000000 CALL <JMP.&Kernel32.GetStdHandle> ; GetStdHandle
0040100A A3 0E204000 MOV DWORD PTR DS:[40200E],EAX
0040100F B8 00100000 MOV EAX,1000
00401014 BE 0A000000 MOV ESI,0A
00401019 B9 00000000 MOV ECX,0
0040101E BA 00000000 MOV EDX,0
00401023 F7F6 DIV ESI
00401025 80C2 30 ADD DL,30
00401028 52 PUSH EDX
00401029 41 INC ECX
0040102A 3D 00000000 CMP EAX,0
0040102F 75 ED JNZ SHORT PRW.0040101E
00401031 890D 0A204000 MOV DWORD PTR DS:[40200A],ECX
00401037 BB 00204000 MOV EBX,PRW.00402000
0040103C 5A POP EDX
0040103D 8813 MOV BYTE PTR DS:[EBX],DL
0040103F 43 INC EBX
00401040 E2 FA LOOPD SHORT PRW.0040103C
00401042 68 00000000 PUSH 0 ; pOverlapped = NULL
00401047 68 12204000 PUSH PRW.00402012 ; pBytesWritten = PRW.00402012
0040104C FF35 0A204000 PUSH DWORD PTR DS:[40200A] ; nBytesToWrite = 0
00401052 68 00204000 PUSH PRW.00402000 ; Buffer = PRW.00402000
00401057 FF35 0E204000 PUSH DWORD PTR DS:[40200E] ; File = NULL
0040105D E8 10000000 CALL <JMP.&Kernel32.WriteFile> ; WriteFile
00401062 68 00000000 PUSH 0 ; ExitCode = 0
00401067 E8 0C000000 CALL <JMP.&Kernel32.ExitProcess> ; ExitProcess
0040106C $-FF25 38304000 JMP DWORD PTR DS:[<&Kernel32.GetStdHandl>
00401072 $-FF25 3C304000 JMP DWORD PTR DS:[<&Kernel32.WriteFile>]
00401078 .-FF25 40304000 JMP DWORD PTR DS:[<&Kernel32.ExitProcess>
Листинг 7.2.2. Содержимое окна CPU отладчика для примера,
полученного компоновщиком TLINK32
При использовании компоновщика ALINK получается несколько иной исполняемый код, представленный в листинге 7.2.3.
00401000 68 F5FFFFFF PUSH -0B
00401005 E8 F61F0000 CALL <JMP.&kernel32.GetStdHandle>
0040100A A3 0E204000 MOV DWORD PTR DS:[40200E],EAX
0040100F B8 00100000 MOV EAX,1000
00401014 BE 0A000000 MOV ESI,0A
00401019 B9 00000000 MOV ECX,0
0040101E BA 00000000 MOV EDX,0
00401023 F7F6 DIV ESI
00401025 80C2 30 ADD DL,30
00401028 52 PUSH EDX
00401029 41 INC ECX
0040102A 3D 00000000 CMP EAX,0
0040102F 75 ED JNZ SHORT PR.0040101E
00401031 890D 0A204000 MOV DWORD PTR DS:[40200A],ECX
00401037 BB 00204000 MOV EBX,PR.00402000
0040103C 5A POP EDX
0040103D 8813 MOV BYTE PTR DS:[EBX],DL
0040103F 43 INC EBX
00401040 E2 FA LOOPD SHORT PR.0040103C
00401042 68 00000000 PUSH 0
00401047 68 12204000 PUSH PR.00402012
0040104C FF35 0A204000 PUSH DWORD PTR DS:[40200A]
00401052 68 00204000 PUSH PR.00402000
00401057 FF35 0E204000 PUSH DWORD PTR DS:[40200E]
0040105D E8 A41F0000 CALL <JMP.&kernel32.WriteFile>
00401062 68 00000000 PUSH 0
00401067 E8 A01F0000 CALL <JMP.&kernel32.ExitProcess>
0040106C 0000
Листинг 7.2.3. Содержимое окна CPU отладчика для примера,
полученного компоновщиком ALINK
Различия наблюдаемых исполняемых кодов связаны с теми частями наблюдаемых в отладчике кодов, которые не были явно заданы исходной программой, а обусловлены дополнительными построениями исполняемого файла по объектному. Эти построения - по месту размещения в памяти - отличаются для различных компоновщиков.
Заметим, что окно дизассемблирования CPU состоит из четырех столбцов. В первом из них для каждой строки приводится (виртуальный) адрес, с которого размещается содержимое этой строки при выполнении программы. Во втором столбце приводится шестнадцатеричный код содержимого этой строки, в третьем - дизассемблированное содержимое, записанное с помощью мнемокодов команд, обозначений регистров и вспомогательных операндов ассемблера. Кроме того, в этой же строке для операндов, задающих места переходов или вызываемых подпрограмм, в угловых скобках приведены обозначения соответствующих исполняемых файлов и имена доступных извне меток или подпрограмм в этих исполняемых файлах. В частности, в рассматриваемом примере для обращения к функциям API, находящимся в DLL библиотеки KERNEL32, используются программные переходники, которые представляют собой обращения по командам CALL к командам-переходникам в конце исполняемого кода. Эти команды-переходники являются косвенными безусловными переходами, которые осуществляют переходы по адресам, записанным в специальные поля и обеспечивают переходы на требуемые системные функции. (Тем самым, в реализацию пожеланий исходной программы система разработки вносит свои изменения - вместо прямых обращений к системным функциям используются упомянутые переходники.)
Для варианта, который использует компоновщик TLINK32, эти программные переходники размещаются сразу за основным исходным кодом - по адресам памяти с 0040106C по 0040107B. Для варианта, который использует компоновщик ALINK, такие программные переходники размещаются в другом месте, а именно (для данного примера) по адресами памяти с 00403000 по 0040300F и могут быть наблюдаемы в окне отладчика, когда при выполнении программы к ним осуществляется переход с помощью соответствующей директивы этого отладчика. Такой директивой может быть как директива покомандного выполнения (Step into в меню Debug отладчика или клавищей F7), либо же через контекстное меню при выделенной строке окна COU отладчика, которая обеспечивает переход на такой переходник (в нашем примере это вторая строка рассмотреннго исходного содержимого программы в указанном окне).
Для варианта компоновки ALINK коды указанных переходников отображаются в виде следующих строк
00403000 -FF25 48404000 JMP DWORD PTR DS:[<&kernel32.GetStdHandl>]
00403006 -FF25 4C404000 JMP DWORD PTR DS:[<&kernel32.WriteFile>]
0040300C -FF25 50404000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]
Для выполнения программы в пошаговом режиме служат клавиши F7 и F8. Первая из них задает пошаговое исполнение с пошаговым вхождением и выполнением вызываемых подпрограмм. Клавиша F8 задает пошаговый режим только для текущей программы (подпрограммы), при этом выполнение всех вызываемых подпрограмм осуществляется автоматически до момента выхода из них, так что отлаживаемые действия приостанавливаются на следующей за вызовом команде. Автоматическое выполнение программы задается клавишей F9, при этом выполнение происходит до первой встретившейся контрольной точки, до системного вызова, следствием которого является ожидание события (например, ввод данных) или завершение программы. Повторный запуск программы осуществляется «горячей клавишей» Ctrl-F2.
Текущее значение данных в рассматриваемый момент отладки программы можно получить из двух панелей отладчика: окна Register и окна Dump. Первое из них отображает текущие значения всех регистров, а окно предназначено для отображения участка памяти. Кроме того, при отладке в последнем столбце панели CPU в ряде случаев появляется поясняющая информация о данных, полученных в результате выполнения очередной команды. Отладчик OllyDbg имеет множество возможностей, познакомиться с которыми можно через его справочную систему.