На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS

Дорогие друзья! Поздравляем вас с Новым 2018 годом!

Всем удачи, успеха и благополучия!
В новом году ожидаем новых рекордов при подсчёте количества ёлочек на экране ;)


msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Все статьи должны быть оформлены согласно Правил оформления статей.
2. Любые обсуждения должны происходить в специальной теме, обсуждение в любых других темах раздела запрещены.
3. Запрещается писать статьи о создании и распространении вирусов, троянов и других вредоносных программ!
4. За грамотно написанные и правильно оформленные статьи авторы награждаются DigiMoney.

Дополнительные ссылки:
Желаю творческих успехов! ;)
Модераторы: Jin X
  
    > Использование стандартного отладчика debug.exe, Windows, RE/Protection
      Использование стандартного отладчика debug.exe

      Сегодня мы рассмотрим стандартный отладчик debug.exe, входящий в любую версию DOS/Windows. Должен заметить, что этот отладчик не такой мощный, как гиганты SoftICE или Turbo Debugger. Однако, в то же время debug.exe очень прост и доступен, и поэтому идеально подходит для начинающих программистов на языке Ассемблер.
      Итак, запускаем debug.exe (для этого заходим в Пуск->Выполнить и выполняем команду debug) и начинаем изучать этот замечательный отладчик :)

      Команды debug.exe

      Для начала разберемся с правилами набора команд debug.exe:
      • В debug.exe не различается регистр букв.
      • Пробелы в командах используется только для разделения параметров.
      • Вводимые числа должны быть в шестнадцатеричной системе счисления, причем без завершающей буквы h.
      • Сегмент и смещение записываются с использованием двоеточия, в формате сегмент:смещение, например, CS:3C1 (смещение 3C1h в сегменте кода) или 40:17 (смещение 17h в сегменте, адрес начала которого - 40[0]h).

      Разобравшись с правилами, давайте перейдем к изучению команд debug.exe. Замечу, что работа с командами debug.exe в чем-то похожа на работу с командной строкой DOS. Поcле загрузки отладчика на экране появится приглашение, выглядещее в виде дефиса:

      ExpandedWrap disabled
        -_

      Регистры CS, DS, ES, SS в этот момент инициализированы адресом 256-байтного префикса сегмента програмы, а рабочая области в памяти будет начинаться с адреса этого префикса + 100h.
      Команды debug.exe вводятся сразу после приглашения на месте, которое отмечено курсором. Каждая команда состоит из идентификатора и параметров, идентификатор состоит из одной буквы.


      Краткая таблица всех команд debug.exe
      КомандаОписаниеФормат
      A (Assemble)Транслирование команд ассемблера в машинный код;
      адрес по умолчанию - CS:0100h.
      A [<адрес_начала_кода>]
      C (Compare)Сравнение содержимого двух областей памяти; по умолчанию используется DS.
      В команде указывается либо длина участков, либо диапазон адресов.
      C <начальный_адрес_1> L<длина> <начальный_адрес_2>
      C <начальный_адрес_1> <конечный_адрес_1> <начальный_адрес_2>
      D (Display/Dump)Вывод содержимого области памяти в шестнадцатеричном и ASCII-форматах.
      По умолчанию используется DS; можно указывать длину или диапазон.
      D [<начальный_адрес> [L<длина>]]
      D [начальный_адрес конечный_адрес]
      E (Enter)Ввод в память данные или инструкции машинного кода;
      по умолчанию используется DS.
      E [<адрес> [<инструкции/данные>]]
      F (Fill)Заполнение области памяти данными из списка; по умолчанию используется DS.
      Использовать можно как длину, так и диапазон.
      F <начальный_адрес_1> L<длина> '<данные>'
      F <начальный_адрес> <конечный_адрес> '<данные>'
      G (Go)Выполнение отлаженной программы на машинном языке до указанной точки останова;
      по умолчанию используется CS. При этом убедитесь, что IP содержит корректный адрес.
      G [=<начальный_адрес>] <адрес_останова> [<адрес_останова> ...]
      H (Hexadecimal)Вычисление суммы и разности двух шестнадцатеричных величин.H <величина_1> <величина_2>
      I (Input)Считывание и вывод одного байта из порта.I <адрес_порта>
      L (Load)Загрузка файла или данных из секторов диска в память; по умолчанию - CS:100h.
      Файл можно указать с помощью команды N или аргумента при запуске debug.exe.
      L [<адрес_в_памяти_для_загрузки>]
      L [<адрес_в_памяти_для_загрузки> [<номер_диска> <начальный_сектор> <количество_секторов>]]
      M (Move)Копирование содержимого ячеек памяти; по умолчанию используется DS.
      Можно указывать как длину, так и диапазон.
      M <начальный_адрес> L<длина> <адрес_назначения>
      M <начальный_адрес> <конечный_адрес> <адрес_назначения>
      N (Name)Указание имени файла для команд L и W.N <имя_файла>
      O (Output)Отсылка байта в порт.O <адрес_порта> <байт>
      P (Proceed)Выполнение инструкций CALL, LOOP, INT или повторяемой строковой инструкции
      с префиксами REPnn, переходя к следующей инструкции.
      P [=<адрес_начала>] [<количество_инструкций>]
      Q (Quit)Завершение работы debug.exe.Q
      R (Register)Вывод содержимого регистров и следующей инструкции.R <имя_регистра>
      S (Search)Поиск в памяти символов из списка; по умолчанию используется DS.
      Можно указывать как длину, так и диапазон.
      S <начальный_адрес> L<длина> '<данные>'
      S <начальный_адрес> <конечный_адрес> '<данные>'
      T (Trace)Пошаговое выполнение программы. Как и в команде P, по умолчанию используется
      пара CS:IP. Замечу, что для выполнения прерываний лучше пользоваться командой P.
      T [=<адрес_начала>] [<количество_выполняемых_команд>]
      U (Unassemble)Дизассемблирование машинного кода; по умолчанию используется пара CS:IP. К сожалению,
      debug.exe некорректно дизассемблирует специфические команды процессоров 80286+,
      хотя они все равно выполняются корректно.
      U [<начальный_адрес>]
      U [<начальный_адрес конечный_адрес>]
      W (Write)Запись файла из debug.exe; необходимо обязательно задать имя файла командой N, если
      он не был загружен. А программы записываются только в виде файлов .COM!
      W [<адрес> [<номер_диска> <начальный_сектор> <количество_секторов>]]

      Примечание. Символами [] отмечены необязательные параметры.

      Просмотр областей памяти

      В этой части нашей статьи мы рассмотрим подробно работу команды D, позволяющей просматривать содержимое отдельных областей памяти.
      Этот пример использует команду D для просмотра области памяти, начиная с 0159:0240:
      ExpandedWrap disabled
        -d 0159:0240
        0159:0240  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ..........l.....
        0159:0250  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
        0159:0260  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
        0159:0270  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
        0159:0280  00 00 00 00 00 00 00 00-00 FF FF FF FF 00 00 00   ................
        0159:0290  FF 00 00 00 00 00 00 00-00 00 4E 4F 20 4E 41 4D   ..........NO NAM
        0159:02A0  45 20 20 20 20 00 26 81-4F 03 00 01 CB 00 00 00   E    .&.O.......
        0159:02B0  00 00 00 00 00 00 00 00-00 00 00 01 07 04 FF 02   ................
        -_


      Здесь на запрос просмотра участка памяти мы получили восемь строк, в которых указано содержимое выбранной области памяти. Каждая строка состоит из трех частей:
      • Адрес первого слева показанного байта в формате сегмент:смещение.
      • Шестнадцатеричное представление параграфа (16 байт), начинающегося с указанного в начале строки байта.
      • Символы этого же параграфа в ASCII-формате.

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

      Полезные приемы с командой D

      Проверка параллельных и последовательных портов
      Первые 16 байт области данных BIOS содержат адреса параллельных и последовательных портов. Поэтому с помощью следующей команды можно проверить эти порты:

      ExpandedWrap disabled
        -D 40:00_

      Первые выведенные восемь байтов указывают на адреса последовательных портов COM1-COM4. Следующие 8 байтов указывают на адреса параллельных портов LPT1-LPT4.
      Например, если на вашем компьютере есть один параллельный порт, то первые два байта будут, скорее всего, такими: 7803. Адрес порта записывается в обращенной последовательности, т.е. 0378.

      Проверка оборудования
      Первые два байта, располагающиеся в BIOS по адресу 410h, содержат информацию об установленном в системе оборудовании. Находим эти байты командой:

      ExpandedWrap disabled
        -D 40:10_

      Предположим, что первые два байта окажутся 23 44. Расшифруем эти байты для получения информации об установленных устройствах. Для этого обратим эти байты (44 23), затем переведем их в двоичную систему счисления. Получаем:
      Значение бита
      0
      1
      0
      0
      0
      1
      0000100011
      Позиция бита1514131211109876543210


      Что означают эти биты? Продолжаем расшифровывать:
      БитыУстройство
      15, 14Число параллельных портов (01 = 1 порт, ...)
      11, 10, 9Число последовательных портов (..., 010 = 2 порта, ...)
      7, 6Число дисководов (00 = 1 дисковод, 01 = 2, 10 = 3, 11 = 4)
      5, 4Начальный видеорежим (01 = 40х25 цветной, 10 = 80х25 цветной, 11 = 80х25 монохромный)
      1Присутствие математического сопроцессора (0 = нет, 1 = есть)
      0Наличие привода для дискет (0 = нет, 1 = есть)


      Проверка состояния регистра клавиатуры
      В области данных BIOS по адресу 417h находится первый байт, который хранит состояние регистра клавиатуры. Выключаем Num Lock и Caps Lock, затем набираем команду:

      ExpandedWrap disabled
        -d 40:17_

      Первый байт будет равен 00. Включив Num Lock и Caps Lock, снова выполняем команду. Теперь первый байт должен равняться 60. Опытным путем установлено, что при включенном Num Lock первый байт равен 20, а при Caps Lock - 40. :)

      Проверка состояния видеосистемы
      По адресу 449h в BIOS находится первая область видеоданных. Для проверки набираем:

      ExpandedWrap disabled
        -d 40:49_

      Первый байт показывает текущий видеорежим (к примеру, 03 - цветной), а второй - число столбцов (например, 50 - режим с 80 столбцами). Число строк можно найти по адресв 484h (40:84).

      Проверка копирайта BIOS и серийного номера
      Сведения об авторских правах на BIOS встроены в ROM BIOS по адресу FE00:0. Строку с копирайтом можно легко найти в ASCII-последовательности, а серийный номер - в виде шестнадцатеричного числа. Хотя, строка с указанием авторских прав может быть длинной и не умещаться в выведенную область памяти. В таком случае следует просто ввести еще раз D.

      Проверка даты произвоства BIOS
      Эта дата также записана в ROM BIOS начиная с адреса FFFF:5. После выполнения соответствующей команды в ASCII-последовательности будет находиться эта дата, записанная в формате мм/дд/гг.

      Пример:
      ExpandedWrap disabled
        -d FFFF:5
        FFFF:0000                 31 31 2F-32 38 2F 30 35 00 FC 00        11/28/05...
        FFFF:0010  34 12 00 00 00 00 00 00-00 00 00 00 00 00 00 00   4...............
        ...
         
        -_


      Непосредственный ввод программы в память с помощью debug.exe

      debug.exe позволяет вводить программу непосредственно в память машины, а затем следить и управлять ее выполнением. Мы будем вводить программу в машинных кодах, используя команду E. При этом будьте бдительны - ввод ошибочных данных по ошибочному адресу чреват непредсказумыми последствиями! Хотя к серьезным проблемам в системе это вряд ли приведет, но потерять все данные, введенные в debug.exe, можно потерять запросто.
      Программа, которую мы сейчас будем вводить, использует данные, заложенные непосредственно в теле инструкций. Далее показан листинг программы на Ассемблере, в комментариях указаны аналоги команд языка в машинных кодах, а также объяснение каждй команды. Замечу, что в числах нет символа h, поскольку, как было сказано выше, debug.exe понимает только числа в шестнадцатеричной системе.

      ExpandedWrap disabled
        MOV AX, 0123 ; код B82301: заносим значение 0123h в AX
        ADD AX, 0025 ; код 052500: прибавляем 0225h к значению AX
        MOV BX, AX   ; код 8BD8: заносим значение AX в BX
        ADD BX, AX   ; код 03D8: прибавляем значение AX к BX
        MOV CX, BX   ; код 8BCB: заносим значение BX в CX
        SUB CX, AX   ; код 2BC8: отнимаем значение AX из CX
        SUB AX, AX   ; код 2BC0: очищаем AX
        JMP 100      ; код EBEE: переходим к началу программы

      Как можно заметить, каждая машинная инструкция имеет длину от 1 до 3 байтов. Первый байт указывает операцию, последующие - ее операнды. Исполнение программы начинается соответственно с первой инструкции и последовательно проходит через все инструкции одну за другой.
      Теперь можно ввести программу в память. Разделим машинный код на три части по шесть байт и введем каждую, используя команду E и начиная с адреса CS:100.

      ExpandedWrap disabled
        -E CS:100 B8 23 01 05 25 00
        -E CS:106 8B D8 03 D8 8B CB
        -E CS:10C 2B C8 2B C0 EB EE
        -_

      Теперь, когда программа введена в память, попробуем управлять ее выполнением. Для начала проверим текущее состояние регистров и флагов, для этого вводим команду R. Отладчик выведет содержимое регистров в шестнадцатеричной форме; на разных машинах содержимое регистров может различаться.

      ExpandedWrap disabled
        -r
        AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
        DS=15D7  ES=15D7  SS=15D7  CS=15D7  IP=0100   NV UP EI PL NZ NA PO NC
        15D7:0100 B82301        MOV     AX,0123
        -_

      Итак, как можно видеть, debug.exe инициализировал сегменты DS, ES, SS, CS одним и тем же адресом. Регистр IP содержит 0100, указывая на то, что инструкции выполняются со смещения 100h относительно CS (а мы, вводя инструкции в память, как раз указали этот адрес).
      Здесь же указаны и значения флагов переполнения, направления, прерывания, знака, нуля, дополнительного переноса, четности и переноса:
      ЗначениеОписание
      NVОтсутствие переполнения
      UPНаправление вверх или вправо
      EIРазрешение прерываний
      PLПоложительный знак
      NZНенулевое значение
      NAОтсутствие дополнительного переноса
      POНечетное слово
      NCОтсутствие переноса


      После регистров и состояния флагов debug.exe выводит информацию о первой инструкции, которая будет выполняться:
      • Адрес инструкции, в нашем случае это 15D7:0100, где 15D7 - адрес сегмента кода.
      • Машинный код, соответствующей этой инструкции (B82301).
      • Собственно инструкция, записанная на ассемблере (MOV AX,0123).

      Теперь, после анализа содержимого регистров и флагов, давайте перейдем к выполнению программу. Выполнять программу мы будем пошагово, используя команду T. Использовав в первый раз команду T, мы выполняем инструкцию MOV. Здесь машинный код операнда инструкции - 2301. Операция помещает 23 в AL (младшая половина AX), а 01 - в AH (старшая).
      После этого debug.exe снова выводит информацию о регистрах:

      ExpandedWrap disabled
        -t
        AX=0123  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
        DS=15D7  ES=15D7  SS=15D7  CS=15D7  IP=0103   NV UP EI PL NZ NA PO NC
        15D7:0100 B82301        ADD     AX,0025
        -_

      Теперь AX содержит 0123h, IP - 0103h (следовательно, длина выполненной инструкции: 0103h - 0100h = 3 байта), а в качестве следующей инструкции указана операция ADD.
      Так, раз за разом выполняя команду T, мы дойдем до последней инструкции JMP 100. Она установит регистр IP в 100h, и debug.exe вернется к началу программы. Возвращаясь к началу программы, следует заметить, что в DS, ES, SS и CS содержится один и тот же адрес. Дело в том, что debug.exe рассматривает введенные программы исключительно как программы .COM. А в программах .COM, в отличие от .EXE, стек, код и данные хранятся в одном сегменте.

      Ассемблирование и дизассемблирование

      В прошлом примере мы вводили программу в машинных кодах, однако, debug.exe вполне способен понимать инструкции, записанные на ассемблере. Для работы с такими программами в debug.exe используются команды A и U.
      Команда A запрашивает инструкции на ассемблере и преобразовывает их в машинный код. Для начала инициализируем начальный адрес для ввода инструкций (100h):

      ExpandedWrap disabled
        -a 100_

      Отладчик выведет адрес сегмента кода и смещения (например, 13F2:0100). Теперь мы должны ввести следующие инструкции на ассемблере в память, после каждой строки нажимая Enter:

      ExpandedWrap disabled
        MOV CL, 42
        MOV DL, 2A
        ADD CL, DL
        JMP 100

      После ввода последней инструкции нажимаем Enter дважды, чтобы указать отладчику, что мы закончили вводить текст программы. Теперь программу можно запускать, используя команды R для просмотра регистров и T для трассировки. Замечу, что в своих программах при наличии инструкций INT их следует обрабатывать не командой T, а командой P, которая обрабатывает все прерывание сразу.

      Перейдем к процедуре дизассемблирования, а в качестве примера возьмем только что введенную программу. Используем адреса первой и последней инструкций для указания диапазона, который мы собираемся дизассемблировать, т.е. 100h и 107h.

      ExpandedWrap disabled
        -u 100, 107_

      После выполнения этой команды debug.exe выведет инструкции, находящиеся в указанном диапазоне, на ассемблере, в машинных кодах, а также адрес каждой инструкции:

      ExpandedWrap disabled
        13F2:0100 B142          MOV     CL, 42
        13F2:0102 B22A          MOV     DL, 2A
        13F2:0104 00D1          ADD     CL, DL
        13F2:0106 EBF8          JMP     0100


      Итог

      А теперь, после небольшого обзора возможностей стандартного отладчика debug.exe давайте подведем итоги. Итак:
      • debug.exe можно применять для наблюдений и отладки программ на ассемблере и машинных кодах.
      • debug.exe позволяет трассировать программу, устанавливать точки останова, просматривать области памяти, вводить программы непосредственно в память компьютера.
      • debug.exe представляет загружаемые программы как программы .COM.
      • debug.exe воспринимает только числа в шестнадцатеричной системе.
      • debug.exe не различает регистр букв.

      Дополнительные материалы:
      Абель П. АССЕМБЛЕР: Язык и программирование для IBM PC. - К.: Век+, 2003.
      http://www.allasm.ru/low_prog_01.php - низкоуровневое программирование для дZенствующих - DZebug: руководство юZверя
      http://thestarman.pcministry.com/asm/debug/debug.htm - A Guide to DEBUG, by Daniel B. Sedory
      My name is Bond. James Bond.
        Здравствуйте!
        А у меня такой вот вопрос возник. Набираю в debug команду:
        ExpandedWrap disabled
          U 0116:108A
           
          0116:108A 90     NOP
          0116:108B 90     NOP
          0116:108C E8E000 CALL 116F
          0116:108F 2E     CS:
          ............................
          ............................
          .........

        ИНТЕРЕСНО ВАШЕ МНЕНИЕ НА СЧЕТ ПОСЛЕДНЕЙ ИНСТРУКЦИИ:
        ExpandedWrap disabled
          0116:108F 2E     CS:

        НЕ МОГУ НАЙТИ НИ В ОДНОМ СПРАВОЧНИКЕ! :)

        СПАСИБО!
        Сообщение отредактировано: asminog -
          Цитата asminog @
          Здравствуйте!
          А у меня такой вот вопрос возник. Набираю в debug команду:
          ExpandedWrap disabled
            U 0116:108A
             
            0116:108A 90     NOP
            0116:108B 90     NOP
            0116:108C E8E000 CALL 116F
            0116:108F 2E     CS:
            ............................
            ............................
            .........

          ИНТЕРЕСНО ВАШЕ МНЕНИЕ НА СЧЕТ ПОСЛЕДНЕЙ ИНСТРУКЦИИ:
          ExpandedWrap disabled
            0116:108F 2E     CS:

          НЕ МОГУ НАЙТИ НИ В ОДНОМ СПРАВОЧНИКЕ! :)

          СПАСИБО!

          asminog, это обращение к сегменту кода вместо сегмента данных. В следующей строке может быть, скажем, что-то типа
          ExpandedWrap disabled
            MOV DS, [3DE7]

          записывающее в DS значение, находящееся в сегменте кода по смещению 3DE7.
          My name is Bond. James Bond.
          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
          0 пользователей:


          Рейтинг@Mail.ru
          [ Script Execution time: 0,1447 ]   [ 17 queries used ]   [ Generated: 17.01.18, 01:46 GMT ]