Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Низкоуровневое программирование для дZeнствующих


Информационный Канал Subscribe.Ru

Низкоуровневое программирование для дZенствующих, #30 (часть 2)

Низкоуровневое программирование для дZенствующих, #30

(часть 2)

  • Генератор паролей [Serrgio]. Посредством описанной в статье методы можно провести экспериментальную проверку некоторых математических, астрофизических и философских теорий и в конце концов получить ответ на самый глобальный вопрос современности - почему двери в психушку открываются исключительно внутрь.
  • Сам себе компилятор [FatMoon]. В детстве автор пробовал на вкус акварельные "медовые" краски, пытался залить чернила в стержень авторучки, приносил домой гусениц, кормил их листьями и вылуплял бабочек... А разве писать на ассемблере под WINDOWS не извращение?


############################################################

Serrgio [HI-TECH group]

9. Генерация паролей

В тот год, когда Ю'дзын покинул горы,
умел смеяться он и видел свет [он],
хотел больших серьезных перемен [он].
Теперь не хочет, не умеет и не видит...
скажи учитель, жив Ю'дзын ли?
Учитель сказал: "ЧТОБ ЛОТОС ЦВЕЛ,
ЕМУ НУЖНА ВОДААААА!!"
И ударил его палкой. По голове.
(C) НОМ, portion by Конфуций

#1.В этой главе мы с вами напишем продвинутую программу для генерации паролей. В отличие от тех программ, что мы писали ранее, эта длиннее и более наворочена (а вы чего хотели?), так что будьте бдительны ;)

Не могу не отметить, что DOS'овский прототип программы был взят из книги "Техника и философия хакерских атак" Криса Касперски, а процесс медитирования над win32-версией сопровождался постоянным постукиванием бамбуковой палкой в железных руках Аркадия Белоусова, за что ему большой дзенский сенькс.

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

Например, для алфавита, состоящего из трех символов "abc", программа сгенерирует и напечатает следующие пароли: a, b, c, aa, ba, ca, ab, bb, cb, ac, bc, cc, aaa, baa, caa ... cccbcbbaba, aaaccbbaba, baaccbbaba, caaccbbaba...И будет печатать их, пока не наступит одно из нижеследующих событий:

- вам надоедает это безобразие, и вы жмете на "крестик" закрытия окна;

Тут, однако, встает первый, философский вопрос - не является ли закрытие окна консольной программы столь варварским способом нарушением священных принципов Правильного Программирования? Со всей ответственностью за возможные последствия отвечаю: нет, не является! И тут же, на всякий случай, даю себе пути к отступлению: если ВСЕ-ТАКИ является, то хорошо известная каждому сетевику программаping-очередное доказательство того, что программисты Microsoft этим правилам не следуют, в чем легко убедиться (как, впрочем, и опровергнуть), выполнив команду ping 127.0.0.1 -t.

- число символов пароля превосходит размер буфера;

А вот это уже вопрос математический. Зная число символов в "алфавите" и скорость генерации их сочетаний (достав с полки толстый талмуд по комбинаторике), нетрудно подсчитать длину пароля, при превышении которой дальнейшую работу программы стоит признать нецелесообразной ;). Без доказательства приведём такую формулу: при длине буфера N и количестве знаков алфавита B количество разных паролей будет B*(B^N-1)/(B-1). Так, при двух знаках (B=2) и длине буфера под 8 знаков (N=8) можно получить 510 паролей. Если же знаков будет 64, то при длине буфера под 4 знака можно получить более 17 миллионов паролей".

- тепловая смерть Вселенной.

Абстрагируясь от многих вещей, астрофизическую часть этого вопроса можно сформулировать следующим образом - какой размер буфера для двухсимвольного алфавита "01" будет достаточным для того, чтобы программа прекратила работу лишь в момент наступления данного события? Часть квантово-физическая - не приближаем ли мы данное событие, проводя дефрагментацию жесткого диска и тем самым уменьшая коэффициент энтропийности нашей Вселенной? И, наконец, часть экологическая - где взять источник энергии для экспериментальной проверки части астрофизической?

Этот алгоритм можно запросто использовать, например, для реверсирования односторонних функций (что, кстати говоря - альфа и омега криптографии) методом брутфорса (сиречь методом грубой силы). Впоследствии мы ещё вернёмся к этому вопросу.

#2.Секция данных нашей программы выглядит следующим образом:

S_consoleTitle db 'DicMaker+',0
   S_alphabet db 'abcde'
   szAlphabet = $-S_alphabet
   szBuffer = 20
   S_password db szBuffer dup(?)
   S_key db szBuffer dup(?)
   SzKey = $-S_key

S_alphabet - "алфавит", то есть набор символов, которые будут "участвовать" в генерации пароля. SzAlphabet - его размер (говоря другими словами, число символов). Далее у нас следуют два буфера - S_password для хранения пароля и S_key для хранения "ключа". Учитывая, что ключ и пароль - близнецы-братья, размер буфера под них должен быть одинаковым.

"Что такое пассворд, мы знаем, но что подразумевается под термином ключ?" - спросит читатель. И совершенно правильно сделает, что спросит.

Объясняю. Например, для шестисимвольного алфавита "abcdef" мы можем нарисовать следующую табличку:

Начертание символа a b c d e f
Индекс символа 0 1 2 3 4 5

При генерации паролей в буферы S_passwordи S_keyбудут попадать соответственно:

Ключ(байты) Пароль
00 'a'
01 'b'
02 'c'
03 'd'
04 'e'
05 'f'
00 'aa'
01 00 'ba'
02 00 'ca'
03 00 'da'
04 00 'ea'
05 00 'fa'
.......  
00 00 00 'aaa'
01 00 00 'baa'
02 00 00 'caa'
03 00 00 'daa'
04 00 00 'eaa'
....... ......

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

Однако, даже среди грубиянов (к контексте brute force) обязательно найдется особо грубый ;). Специально для таких мужественных, бескомпромиссных, и, что самое главное, собирающихся экспериментально проверить некоторые теории, изложенные параграфом выше, привожу классический алгоритм генерации паролей:

lea esi,S_password
   @@nextpassword:
   xor ebx,ebx
   @@checkover:
   inc byte ptr [esi+ebx]
   cmp byte ptr [esi+ebx],'z'
   jb @@writepassword
   mov byte ptr [esi+ebx],' '
   inc bx
   jmp @@checkover
   @@writepassword:
   ;очередной пароль готов к употреблению
   jmp @@nextpassword


Медитируем!

#3.А теперь полюбуемся на код программы, и попробуем разобраться, как он работает.

Сначала, как и всегда - локальные переменные под хэндл и под "напечатано символов":

local houtput :dword
   local nwritten :dword

Хорошо знакомые по предыдущим программам "подготовительные операции":

invoke SetConsoleTitle,addr S_consoleTitle
   invoke GetStdHandle,STD_OUTPUT_HANDLE
   mov [houtput],eax 

Теперь, собственно, рабочая часть программы (замрите в ужасе!):

mov esi,offset S_key ;(1)
   mov edi,offset S_password
   mov ecx,esi
@@keylenloop: ;(2)
   cmp ecx,offset S_key+szKey
   jae @@break
   mov byte ptr [esi],0
@@passwordloop: ;(3)
   movzx ebx,byte ptr [esi]
   mov al,S_alphabet[ebx]
   mov [edi],al
;-|A|--------------------- ;(4)
push ecx
   mov edi,offset S_password
   sub ecx,offset S_key-3
   mov word ptr [edi+ecx-2],0A0Dh
   invoke WriteConsole,houtput,edi,ecx,
   addr nwritten,NULL
   pop ecx
;-|Б|---------------------
mov esi,offset S_key ;(5)
   ;mov edi,offset S_password 
@@carryloop: ;(6)
   inc byte ptr [esi]
   cmp byte ptr [esi],szAlphabet
   jb @@passwordloop 
mov byte ptr [esi],0
   mov al,S_alphabet[0]
   mov [edi],al
   inc esi
   inc edi
   cmp esi,ecx
   jbe @@carryloop 
inc ecx
   jmp @@keylenloop
   @@break:
invoke ExitProcess,0 ; ВЫХОД ;)

Уф... Что ж, давайте анализировать, и да пребудет с вами долготерпение.

Бряк 1- загружаем в регистры esiи ediуказатели на буферы ключейи паролейсоответственно. Регистр ecxиспользуется для подсчета числа разрядов в ключе (оно же - число символов в пароле), с той лишь разницей, что для удобства там лежит смещение от начала буфера ключа. Изначально он инициализируется указателем на первый разряд ключа, что вполне естественно, так как еще не произошло ни одной итерации цикла и первый разряд является одновременно и старшим, и младшим (на выбор), т. е. единственным ;).

Бряк 2- сюда переходит управление в том случае если предполагаетсяувеличение разрядности ключа (она же - длина пароля). Здесь сравнивается указатель на старший разряд ключас адресом, следующим за буфером под ключ. И если "потребности" программы больше, чем "возможности" буфера, перепрыгиваем на invoke ExitProcessи благополучно завершаем её выполнение. А если же подобное безобразие ещё не случилось, то инициализируем старший разряд ключа нулем. Собственно, алгоритм начинается отсюда, с "увеличения" ключа до единичной длины.

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

Бряк 4- между A и Б можно вставить любое действо, которое должно произойти со сгенерированным паролем. В данном примере пароль печатается, но ничто не мешает вставить сюда, например, код вычисления хэш-функции пароля и сравнения его с реверсируемым ;). Также обратите внимание, каким "хитрым" способом проводится добавление CRLF в буфер пароля для вывода на печать (с вычислением длины пароля вместе с CRLF). ;)

Бряк 5- снова берутся указатели. Вследствие особенностей кода между A и Б нам нет необходимости повторно брать указатель на буфер пароля, поэтому эта строчка закомментирована. Но, заметьте, не убрана - на тот случай если мы захотим написать между A и Б нечто иное. ;) Это разумный компромисс между оптимальностью (когда нет лишних инструкций) и читабельностью/модифицируемостью.

Бряк 6- увеличивается разряд (разряд, не разрядность!) ключа на единицу. Если не превышено максимальное значение разряда (соответствующее последнему символу "алфавита"), то ключ считается готовым и значение его разряда конвертируется в символ пароля, то есть идёт прыжок на бряк 3. Если же максимальное значение разряда превышено, то разряд обнуляется, также "обнуляется" соответствующий разряд пароля и, если не было выхода за пределы позиции старшего разряда (указатель в ecx), увеличивается следующий разряд (вам это ещё не напомнило длинную многоразрядную арифметику? :). А если выход был - добавляется очередной разряд к ключу (увеличивается его разрядность), то есть идёт прыжок на бряк 1.

Вот, в общем-то, и вся программа ;).


########################################################################

FatMoon [HI-TECH group]

Сам себе компилятор

(или руководство по мазохизму для дзенствующих)

Предисловие

FatMoon, ты извращенец! Знаешь об этом?
Serrgio

 

Да, об этом я знаю. Подозревать начал еще в раннем детстве, когда

  • пробовал на вкус акварельные "медовые" краски;
  • пытался залить чернила в стержень авторучки;
  • приносил домой гусениц, кормил их листьями и вылуплял бабочек.

    Когда я сел за компьютер, подозрения перешли в твердую уверенность. Да, похоже, что я извращенец. Хотя все относительно - видал я таких извращенцев, по сравнению с которыми я просто … пуританин! А писать на ассемблере под WINDOWS не извращение? Молчите? И в этом молчании я слышу глас рассудка. © А. Сапковский.
    О чем эта статья? О программировании на ассемблере без компилятора, об отладчике DEBUG из стандартного пакета DOS/WINDOWS, о машинном коде и прочим смежным темам.
    Alex FatMoon

Как обычно пишутся программы на ассемблере? В редакторе - не суть важно, каком - набирается исходный текст, содержащий директивы ассемблера, мнемокоды инструкций, определения данных и метки. Затем вызывается компилятор - не суть важно, какой - который транслирует исходный файл в объектный. Затем линкер собирает исполняемый файл из одного или нескольких объектных модулей. Знакомая картина, не правда ли? Однако необходимо ли все это для создания работоспособной программы? Нет, конечно же. Для создания .com - файлов вполне достаточно отладчика DEBUG. Вот об этом и будет речь.

Почти любой отладчик имеет функцию транслирования мнемокодов в машинный код с возможностью записи на диск набранного блока. Поэтому в принципе эти же приемы могут быть использованы и с другими утилитами. Почему все-таки я описываю DEBUG? Он есть практически на любой машине, где установлена любая из версий MS-DOS или WINDOWS. Он прост в использовании, не требователен к ресурсам, знает почти все машинные коды и даже поддерживает инструкции сопроцессора. Он - первый друг взломщика сейвов к играм и просто хакера. И вообще - одно из лучших творений МикроСофт. Лежит он, родимый, в директории C:\DOS или C:\WINDOWS\COMMAND - даже если ваши папки называются по-другому и расположены на других дисках, найти его нетрудно. Переходим к непосредственному использованию.

Программирование без компилятора

Русские сначала придумывают себе препятствия, а потом их преодолевают.
(известный факт)
Входите узкими вратами, ибо широки врата и просторен путь, ведущий в геену огненную.
(Евангелие от Матфея)

Да, если у вас есть компилятор, использовать что-то еще нет нужды. Но представим себе, что компилятора нет. Или мы только начали изучать ассемблер и в принципе знаем мнемокоды по богатому опыту программирования на БК, Спектруме или Микроше, но о директивах имеем только общее представление. И напряженно думаем, с какими ключами запускать этот tasm? И почему tasm выдает ошибки при компиляции, хотя все написано правильно (кто бы мог подумать, что ss: mov ax, [si] на самом деле должно быть записано как mov ax, ss:[si]?). Тогда это для вас. А также если есть желание понять, как же работает компилятор и зачем он все-таки нужен. Подумав (от "DOOM") и перекрестясь (наведя перекрестье на последнего из монстров, нажав "fire primary" и выйдя из игры), приступим!

Пример программы.
Главная команда отладчика, которую будем использовать, "А"ssembly. Итак, входим в отладчик, набираем

a 100

и видим адрес ххх:0100. От нас ждут ввода инструкций. Собственно, можно набирать программу. Пример:

a 100
   mov ah,09
   mov dx,0100
   int 21
   ret
   db "Hello, world!$"

и готово. Однако это еще не конец. Надо скорректировать dx - 0100 туда засылается просто для того, чтобы обозначить команду. Ведь когда мы пишем:

mov dx,xxx

мы еще не знаем адреса, с которого начнется строка "Hello, world!$", не так ли? Этот адрес мы узнаем только после того, как введем "ret". Итак, запоминаем в cx длину нашей программы - она равна адресу инструкции после строки, где мы нажали "Enter", чтобы выйти из режима компиляции, за вычетом 0100 - адрес, с которого начинается программа типа "COM". У меня для вышеприведенной программы получилось 016h. Значит, набираем:

rcx
   16
 

А теперь корректируем адрес - строка начинается с 0108. Набираем:

a 102
   mov dx,108

Осталось сохранить программу на диске:

n hello.com
   w

Вуаля! Теперь в директории, где мы находились перед вызовом отладчика, есть файл hello.com длиной в 22 байта, исправно печатающий при запуске строку "Hello, world!" и возвращающий управление ОС. Просто, не так ли? И никаких компиляторов. На самом деле в роли такового выступили мы сами - назначили строке фиктивный адрес (0100), затем заменили его на точный (0108). Вся помощь отладчика заключалась в переводе мнемокодов в машинные. Не можем же мы помнить все машинные коды!

Это кажется элементарным, не спорю. Попробуем сделать что-нибудь более сложное, и затем попытаемся оптимизировать это. То есть, обычная процедура для любой программы - сначала "рыхлый" код, от которого добиваются работоспособности, затем оптимизация. Лично я придерживаюсь именно такой тактики, и нахожу ее достаточно удобной. Для примера выведем бегущую строку на обычный текстовый экран 80*25 - разрешение, к которому все привыкли (надеюсь) в Norton Commander. Не претендуя на оригинальность, скажу, что нам потребуется две строки в качестве данных/переменных. Одна из строк будет оригиналом, а вторая - служить для хранения подстроки. Алгоритм весьма прост:

  • Цикл: вырезать подстроку выбранной длины;
  • переместить курсор на выбранное место на экране;
  • вывести подстроку;
  • сделать задержку;
  • сдвинуться в строке на символ;
  • если не конец строки, то продолжать цикл.

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

Перенаправление ввода-вывода в ДОС.

Каждый раз набивать программу в отладчике было бы очень долго и может навсегда отвратить от программирования. К счастью, в ДОС (и, в частности,("в частности" убрать) в коммандной строке Windows (согласен, переставить слово надо)) можно использовать перенаправление стандартного ввода-вывода. Как это делается? Пишем текстовый файл, например, содержащий предыдущую программу "Hello, world!", в виде:

----8<---
   a 100
   mov ah,09
   mov dx,108
   int 21
   ret
   db "Hello, world!$"
rcx
   16
   n hello.com
   w
   q
--->8---

Не забудьте пустую строку после DB (она выводит отладчик из режима ассемблирования), и не забываем поставить в конце команду выхода! Сохраняем его под именем, например, hello.dbg и пишем в командной строке:

debug < hello.dbg

В результате отладчик берет команды не с клавиатуры, а из файла. Вводит программу на языке ассемблера начиная с адреса 0100, и сохраняет на диск под именем hello.com. И выходит в ДОС. А что, почти обычная программа - только вместо

ORG 0100h

имеем

a 100

и еще команды в конце.

Точно также, чтобы получить красивый листинг при дизассемблировании, не обязательно делать PrintScreen после команды "u". Поскольку это наша программа и мы знаем, где находится код, а где данные, создаем файл d_hello.dbg, содержащий следующие строки:

u 100,107
   d 108,115
   q

И набираем в командной строке

debug hello.com < d_hello.dbg > hello.diz

Здесь мы перенаправляем как ввод (из файла d_hello.dbg), так и вывод (в файл hello.diz).

В результате получаем еще и файл hello.diz, содержащий дизассемблированную программу.

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

[прим.: Но это ещё не всё! В отличие от "простого" компилятора DEBUG может также сразу и выполнять (почти "интерпретировать") нашу "программу" (по аналогии с бейсиком), поэтому сохранять результат трансляции в отдельный файл нет необходимости - достаточно вместо команд RCX и N поставить G=100, не забыв завершить нашу программу инструкцией INT 3, если мы желаем увидеть содержимое регистров, с которым наша программа завершается. Итак, делаем следующий файл:

a
     xor ax,ax
     mov es,ax ; сегмент 0
     es:
     mov ax,[46c] ; адрес таймера в области данных BIOS
     es:
     mov dx,[46e]
     int 3 ; DX:AX содержат значение системного таймера
g=100
     q

сохраняем это под именем ticks, даём команду DEBUG<TICKS>RESULT, и наблюдаем в файле RESULT в регистрах DX и AX значение системного таймера. Впрочем, конкретно для данного случая наша программа может быть "короче":

d 0:46c l 4
     q

Использование внешнего файла и комментариев в нём также облегчает "настройку" адресов. Например, в исходном файле на месте меток можно вставить соответствующий комментарий, а в инструкциях перехода вместо имён меток будет фиктивное значение. Разумеется, в исходном файле не должно быть команды G, ведь программа ещё не завершена. Например:

a
     mov ax,100
     mov cx,100
     ;top:
     dec ax
     loop 100 ; top
     int 3
;g=100
     q

После первого "прохода" (выполнения DEBUG с перенаправлением ввода-вывода) следует проанализировать вывод на наличие сообщений об ошибках. Потом следует проверить значения закомментированных меток и скопировать эти значения в соответствующие места (в данном случае значение метки top нужно вставить после инструкции loop). Теперь можно расскоментарить команду G и программа готова. :)]

Вывод "бегущей строки" - создание программы с помощью отладчика.

Итак, набираем сразу в виде файла, чтобы потом "скомпилировать" его отладчиком.

---------Start of file------------
   a 100
   mov cx,555
   push cx
   mov si,200
   sub cx,555
   sub si,cx
   mov di,400
   mov cx,14
   rep movsb
   mov byte ptr [di],24
   mov bh,0
   mov dx,0c1f
   mov ah,02
   int 10
   mov dx,400
   mov ah,09
   int 21
   mov ah, 86
   inc cx
   inc cx
   xor dx,dx
   int 15
   mov ah,01
   int 16
   pop cx
   jnz 0140
   loop 0103
   jmp 0100
   ret
   db " ******** This is a long long string."
   db " It can be up to 64K long! You never see such long string"
   db " before! Enjoy it. Here may be some of your text and "
   db "advertizing. Just type what you want together"
   db " with WISPA chocolate! This program is debug handwork."
   db " All rights reserved. Decompilation and dizassembly "
   db " prohibited! The length of this string now 477 bytes"
   db " but length of code that print them is only 59 bytes."
   db " Sorry for my english, I write as I can. Alex FatMoon. $"
rcx
   400
   n r_string.com
   w
   q
   ------------End of file----------

Не забудьте поставить пробел перед долларом - он нужен, что бы конец строки затирал символы, остающиеся от предыдущего вывода. Сделаю некоторые пояснения:

  • 555 - обозначил длину строки. На самом деле тут должно быть число, равное "адрес конца строки" - "адрес начала строки".
  • 0200 - обозначим адрес начала строки. Мы его пока не знаем, но потом в листинге легко найдем.
  • 0400 - адрес начала подстроки. Подстрока начнется сразу после конца строки. Этот адрес мы тоже пока не знаем.
  • 0140 - адрес инструкции "ret". Он идет непосредственно перед строкой. И его тоже пока не знаем.

Сохраняем на диске 1К, поскольку точной длины программы опять же не знаем. Для тех, кто ввел очень длинную строку - можете сохранять не 0400h, а ff00h. Наверняка где-то в начале этого блока все-таки уместилась наша "гигантская" программа.

Теперь загружаем в отладчик почти готовый r_string.com, и дизассемблируем, отмечая исправления, которые надо внести: строка начинается с 013ch, длина всей программы 0219h, длина строки = 0319h-013ch=01ddh, адрес "ret" - 013bh. Вносим изменения - можно прямо в отладчике, можно в текстовом файле. Все должно работать. Оптимизация, очистка экрана в начале и прочее - на ваше усмотрение.

[прим.: как упоминалось выше, для этого ничего дизассемблировать не нужно, достаточно выполнить один проход "компиляции" с перенаправлением вывода, после чего значения всех меток станут известны]

Послесловие

Блаженны больные, ибо исцелятся.
(почти из Библии)
И тебя вылечат… И меня вылечат!
("Иван Васильевич меняет профессию")

Вот собственно для этого и нужен компилятор - назначить адреса меткам и переменным и правильно вставить их в машинный код. Чем больше переменных и переходов, тем сложнее написать программу в отладчике. И слава богу, что это делать не обязательно, поскольку есть компиляторы. Если же читатель достаточно безумен, чтобы попробовать самостоятельно написать довольно объемистый проект, флаг в руки. Моего терпения хватило однажды на двух-килобайтную видеодемку, и я думаю, что писать программы под ДОС, используя только debug, вполне реально. Хотя и неудобно. А вот для написания небольших скриптов и тестовых фрагментов использование DEBUG в качестве компилятора - самое оно. И, кстати, при этом автоматом решается проблема лицензионности компилятора. J
При этом надо помнить несколько вещей:

  • смена сегментного регистра делается в две команды, поскольку это префикс, как и REP, LOCK и другие. То есть
    mov si, es:[di]
    записывается в виде
    es:
    mov si, [di]
  • переходы типа short возможны лишь в пределах 128 байт выше или ниже. Из-за этого могут быть проблемы при вводе программ вышеописанным способом.
  • отладчик не выдаст ошибки, если какая-то инструкция неправильна. То есть, выдаст, но мы ее можем не увидеть, если используем перенаправленный ввод.
  • некоторые машинные коды 186-го, 286-го, 386-го и выше процов к сожалению остаются для debug'а неизвестными, а именно:
    pusha
    popa
    push <immediate>
    bound
    arpl
    • все команды, появившиеся в 486 и позднее
    • все команды, использующие 32-битную адресацию и операнды
    • insb / insw
    • и некоторые другие.

Проблему можно решить, занося непосредственно код через

db <opcode>

Да, если вы хотите писать в отладчике, все эти машинные коды придется запомнить. После этого в голове возникает каша из цифр и букв, и человек неадекватно реагирует на окружающих. Вот и я… пойду-ка лечиться! Поскольку подобные упражнения легко могут подорвать психическое здоровье, всем рекомендую лекарство - бутылочки 3 пива минимум.

© Alex Antipoff aka FatMoon, 2002.


###########################################################################
Номер подготовлен к выпуску 19.11.2002
HI-TECH
Все замечания и опечатки, обнаруженные Вами, могут быть направленны:
EdmondX@narod.ru
###########################################################################


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное