Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11650
Последний выпуск: 19.06.2015

Техника и философия хакерских атак

Крис Касперски

Продолжение...

HIEW, к сожалению, не поддерживает полностью автономных скриптов, поэтому необходимо вручную "провести" его от 0x0 до 1x1E. Посмотрим теперь, какое значение имеет регистр BL. Если все сделано правильно, то там находится число 0xB8. Попробуем расшифровать им остальной код:

XOR AL,0xB8 

В результате получится следующее:

0000001F: B409                         mov       ah,009 
00000021: BA2701                       mov       dx,00127 
00000024: CD21                         int       021 
00000026: C3                           retn 
00000020: 09 BA 27 01-CD 21 C3 43-52 41 43 4B-20 30 78 31  ¦'  =!+CRACK 0x1 
00000030: 31 2E 20 8F-E0 AE A3 E0-A0 AC AC A0-20 A2 EB AF  1. Программа вып 
00000040: AE AB AD A5-AD A0 20 E3-E1 AF A5 E8-AD AE 0D 0A  олнена успешно 
00000050: 24         -           -           -             $ 

Таким образом, приемы против отладчиков "прозрачны" для дизассемблеров. Конечно, дизассемблеры не эквивалентны отладчикам и даже частично не покрывают возможности последних. Поэтому желательно все же найти способ заставить отладчик работать.

Напоминаю, что мы пока говорим о 8086 микропроцессоре и никаких аппаратных точек останова еще нет. Эмуляция может быть теоретически осуществима, но практически для нее не хватит ресурсов процессора. Можно, однако, поступить проще: перед каждой командой обращения к памяти контролировать достоверность результата и при необходимости исправлять его. Это очень ресурсоемкая операция, к тому же возможная только в режиме пошаговой трассировки (что само по себе сильно замедляло выполнение программы на первых процессорах): поэтому большинство отладчиков полагало, что среднему пользователю эти возможности не понадобятся, и не реализовывало их.

Казалось бы, сегодня, в век быстрых процессоров, мы должны были бы давно забыть об этом и устанавливать контрольные точки, где нам вздумается, не беспокоясь, что это может нарушить правильное выполнение программы. Однако ничего не изменилось за прошедший десяток лет. Вот грустный пример программы под Win32. Почему грустный? Да потому, что штатным отладчиком с ним ничего нельзя будет сделать. Рассмотрим его подробнее:

int main(int argc, char* argv[]) 
{ 
  char c[]="Hello World! \n"; 
  __asm { 
         LEA ESI,From 
         LEA EDI,To 
         xor eax,eax 
 From: 
         MOV al,CS:[ESI] 
         INC ESI 
         ADD ah,al 
         CMP  esi,edi 
         jb From 
         LEA ESI,c 
         MOV EDI,ESI 
 Repeat: 
         LODSB 
         OR AL,AL 
         JZ To 
         XOR AL,AH 
         STOSB 
         JMP Repeat 
 To: 
 } 
 printf(c); 
 return 0; 
} 

Не правда ли, этот пример почти полностью повторяет пример под MS-DOS десятилетней давности? Изменилась только одна команда - в Windows не так-то просто модифицировать исполняемый код, вместо этого программа расшифровывает данные.

Попробуйте установить контрольную точку в границах ассемблерского фрагмента. Используется, к примеру, отладчик для MS VC 6.0 или даже Soft-Ice! И в том, и в другом случае строка 'Hello Word!' будет расшифрована некорректно и вместо ожидаемого приветствия на экране появится бессмысленный мусор. Любопытный факт! На протяжении всей истории существования платформы Intel отладчики повторяют одну и ту же ошибку, которую с успехом используют разработчики защит.

А теперь подумаем, что будет, если мы подсчитаем контрольную сумму всей программы, а не только одного расшифровщика. Правильно! Ни одной точки останова нельзя будет установить! Отладка обычными средствами станет невозможной! Впрочем, Soft-Ice позволяет установить аппаратные точки останова командой bpm (в отличие от bpx), и легко выйти из положения.

А вот отладчики от Borland и MicroSoft будут наталкиваться на непреодолимую преграду лени своих разработчиков. Впрочем, не будем строги к последним. Они рассчитывали все же не на хакеров, а на прикладных разработчиков, в жизни которых подобной ситуации, может быть, никогда и не встретится.

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

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

Защита может прочитать этот адрес и записать в обработчик немного (или много - кому как понравится) "мусора", убивая при этом отладчик. Разумеется, для этого необходимо выяснить, что это именно отладчик, а не что-то другое. По умолчанию Int 0x3 обрабатывается MS-DOS и обработчик состоит из одной команды IRET (0xCF). Если обнаруживается нечто иное, то с некоторой степенью вероятности это и будет отладчиком. Чтобы нейтрализовать последний, достаточно переустановить int 0x3 (и int 0x1 - но об этом ниже) на свой обработчик, в котором нужно вывести сообщение с просьбой не отлаживать эту программу.

Впрочем, это может и не сработать. "Умные" отладчики могут отслеживать чтение программой таблицы векторов прерываний и "подсовывать" предыдущие значения обработчиков. Сегодня это умеет делать большинство из них, в том числе и Soft-Ice. Отметим также, что в Windows прикладной программе никто попросту не даст манипулировать векторами и это становится уже неактуально.

Отлаживаемая программа может также содержать опкод 0xCC, беспорядочно и в изобилии разбросанный по всему ее телу и при этом делающий что-то полезное. Например, обработчик int 0x3 может расшифровывать код или вызывать int 0x21. В результате произойдет конфликт ресурсов: отладчику и защите понадобится прерывание int 0x3 - каждому для своих нужд. Обычный отладчик при этом будет постоянно "всплывать" на каждом 0xСC, и если последнее установить в глубоко вложенном цикле, то отладка превратится в пытку. Однако у некоторых отладчиков можно отключить всплытие по точке останова. К таким отладчикам относится, например, trsutil Евгения Касперского.

Заметим, что это не в меньшей степени актуально и для платформы Windows. Наглядным примером может служить CRACK13, который при попытке запуска под отладчиком (скажем, интегрированным с MS VC) вызывает останов последнего, командой int 0x3. Забавно, но его разработчики не предусмотрели возможности отключения этого действия.

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

Рассмотрим еще раз поведение процессора при встрече инструкции 0xCC - контрольной точки останова: он заносит в стек флаги и значение указателя команд и вызывает обработчик. Давайте представим, что при исполнении некоторого критического фрагмента кода защита присвоила указателю стека нулевое значение. А стек, как известно, растет вверх, т.е. от старших адресов к младшим. Когда процессор, встретив int 0x3, попытается сохранить (занести) в стек регистр флагов, он не сможет этого сделать, т.к. стек уже исчерпан. Операционной системе ничего не останется сделать, как завершить некорректно работающее приложение, потому что восстановить его работоспособность уже будет невозможно.

Этот прием продемонстрирован в программе CRACK13. Однако в приведенном примере можно просто удалить команды xchg esp,eax, чтобы приложение успешно работало под отладчиком. Хорошая защита должна этому препятствовать. Здесь возможны множество путей. Например, можно подсчитывать контрольную сумму своего кода, а потом полученным значением расшифровывать некоторый фрагмент. Впрочем, хакеру будет нетрудно расшифровать код вручную, и удалить защищенный расшифровшик. Поэтому рекомендуется прибегать к динамической шифровке или читать данные командой pop. Действительно, рассмотрим следующую ситуацию:

 ----T---T---T---T---T---T---T---T---T---T---T--------
 ¦ H ¦ E ¦ L ¦ L ¦ O ¦   ¦ W ¦ O ¦ R ¦ L ¦ D ¦ . . .
 L---+---+---+---+---+---+---+---+---+---+---+---------
 ^
 ¦
 ¦
 ¦
 

esp

-- pop -->

Если установить esp на начало строки, а потом последовательно извлекать из стека байт за байтом, то получим некий аналог LODSB, только более мощный, т.к.он может читать в любой регистр и оставляет esi нетронутым под нужды программы. При этом любое вмешательство отладчика в процесс приведет к затиранию читаемых данных и краху программы. Неплохо, очень неплохо, - в этом можно убедиться на примере CRACK13. Попробуйте запустить его под отладчиком! Но лучше не пробуйте, ибо ничего хорошего все равно не получится.

Немного поразмыслив, мы придем к выводу, что в данном случае POP AX можно безболезненно заменить на LODSW. Но нетрудно так спроектировать код, чтобы подобная замена была невозможна. Например, достаточно задействовать все свободные регистры, а также команду PUSH, ближайшим аналогом которой будет DEC EDI\STOSW, несколько большая по длине и к тому же тесно связанная с флагом направления (который защита может умышленно изменить на противоположный) и с регистром AX.

Что предпринять хакеру в такой ситуации? Пожалуй, воспользоваться дизассемблером или эмулирующим отладчиком. Однако последних под Windows, похоже, еще не существует, поэтому остается только первое.

****************** Рисунок 13 *************

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

Но какое отношение имеет профилировщик ко взлому? И может ли он быть хоть чем-то полезен хакеру? Может, еще как! Особенно если это хороший профилировщик. Заметим, что защитный механизм написан целиком на ассемблере. С виду написан довольно аккуратно, но на деле коряво и неоптимально. Это позволяет с легкостью находить в исполняемом файле ассемблерные фрагменты. Возможно, что один из них - искомый защитный механизм.

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

Практически все антиотладочные механизмы основаны на оригинальных приемах программирования и не поддерживаются языками высокого уровня. Это вынуждает разработчика прибегнуть к ассемблеру. При этом многие (в том числе и старые) программисты забывают, что архитектура процессоров не стояла на месте и за последние несколько лет представления об оптимизации кардинально изменились. Код, оптимальный для 80486, не будет автоматически оптимальным для Pentium'а. Необходимо позаботиться хотя бы о спаривании команд, без чего ассемблерская "заплатка" будет сильно выделяться на фоне оптимизированного компилятором кода.

Вторым отладочным механизмом 8086 процессора является поддержка трассировки исполнения программы. Трассировка - это пошаговое выполнение инструкций. Во времена 8086 она была единственным средством отладки программ на процессорах того поколения. Организовывалась она с помощью "ловушки". Под ее нужды выделялся один из флагов (TF - trace flag). Если он был установлен, то после выполнения каждой инструкции процессор генерировал исключение 1 (т.е. вызывал int 0x1). При этом он сохранял в стеке регистры флагов и указателя команд и при входе в обработчик автоматически очищал флаг трассировки, чтобы не привести систему к краху.

При этом отладчик никак не был защищен от агрессивных действий отлаживаемой программы. Описанные выше приемы применимы и к этому случаю. Так, чтобы войти в обработчик, int 0x1 требуется по крайней мере шесть байт стекового пространства. При этом стековыми регистрами свободно владеет отлаживаемая программа и нет никакой возможности зарезервировать эти шесть байт для отладчика. Как это может использовать защита, было показано выше.

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

       PUSHF 
       MOV      AX,2577h 
       MOV      BP,SP 
       LEA      DX,NewInt0x77 
       INC      Byte ptr [BP+1] 
       INT      21h 
       POPF 
       INT      77h 

NewInt0x77: 
       NOP 
       MOV AL,[BP+1] 
       SHL AL,7 
       ADD SP,6 
       LEA SI,Crypted 
       MOV CX, offset _end - offset Crypted 
Repeat: 
       XOR  Byte ptr [SI],AL 
       INC  SI 
       LOOP Repeat 

Crypted: 
       MOV AH,9 
       LEA DX,About 
       INT 21h 
       RET 
About   DB 'Hello,Sailor!',0Dh,0Ah,'$' 

Если этот фрагмент запустить под отладчиком, то расшифрованный код будет выглядеть следующим образом:

2298:0126¦ 34 89                XOR     AL,89 
2298:0128¦ 3A AE 81 4D          CMP     CH,Byte ptr [BP]+4D81 
2298:012C¦ A1 43 C8             MOV     AX,Word ptr [C843] 
2298:012F¦ E5 EC                IN      AX,[EC] 
2298:0131¦ EC                   IN      AL,DX 
2298:0132¦ EF                   OUT     DX,AX 
2298:0133¦ AC                   LODSB 
2298:0134¦ D3 E1                SHL     CX,CL 
2298:0136¦ E9 EC EF             JMP     F125 
2298:0139¦ F2                   REPNE 

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

Вся загвоздка именно в "рассеянии" инструкций защиты среди не относящихся к ней команд. Рассмотрим подробнее следующий фрагмент:

PUSHF 
MOV      AX,2577h 
MOV      BP,SP 
LEA      DX,NewInt0x77 
INC      Byte ptr [BP+1] 
INT      21h 
POPF 

Выделим следующую последовательность инструкций:

PUSHF 
MOV BP,SP 
INC Byte ptr [BP+1] 
POPF 

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

Кроме того, ни в коем случае не надо делать тривиальную проверку типа

TEST [BP+1],1 
JNZ under_debuger 

Это слишком заметно и к тому же элементарно нейтрализуется удалением условного перехода. Используйте значение флага трассировки, например, для расшифровки или в арифметических выражениях. Последнее особо трудно обнаружить и исправить. Для этого как минимум потребуется полностью проанализировать алгоритм работы приложения.

Как с этим жить хакеру? Ответ все тот же: используйте дизассемблеры и эмулирующие отладчики. И все усилия разработчиков защиты пойдут прахом. Сегодня можно с уверенностью сказать, что все антиотладочные приемы стали неактуальны. И просто непостижимо то упорство, с которыми некоторые разработчики тратят свое время и силы на борьбу с отладчиками реального режима, которые уже давно никто не использует.

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

Repeat: 
  LODSW 
  MOV [SI-2],BX 
  LOOP Repeat 

Не правда ли, малопонятный цикл? На самом деле это часть расшифровщика. А другая его часть хитро спрятана в обработчике Int 0x1:

NewInt01h: 
 XOR AX,9FADh 
 MOV BX,AX 
 IRET 

Т.е. на самом деле расшифровщик полностью выглядит так:

Repeat: 
   XOR AX,9FADh 
   MOV BX,AX 

   LODSW 
   XOR AX,9FADh 
   MOV BX,AX 

   MOV [SI-2],BX 
   XOR AX,9FADh 
   MOV BX,AX 

   LOOP Repeat 

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

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

Рассмотрим некоторые из них. Неочевидно с первого взгляда, но практически все отладчики перехватывают часть исключений с целью предотвращения некорректной работы программ. Это в первую очередь int 0x6 (неверный опкод) и int 0x0 (деление на нуль или переполнение). Ничего не стоит построить защиту, активно использующую эти ресурсы. Например, для расширения существующих команд микропроцессора. При этом не будет существовать никакого способа заставить эту защиту работать под отладчиком, который самостоятельно перехватывает эту исключительную ситуацию и блокирует работу.

Однако не стоит принимать вышеизложенное как руководство к написанию защит подобного типа. Напротив, я всячески призываю этого не делать. Ведь не только отладчик перехватывает исключение "неверный опкод", но и менеджеры расширенной памяти (emm386, qemm), операционная система Windows, да мало ли еще кто. В любом случае вашему клиенту не понравится, если программу придется запускать в "голой" MS-DOS или отказыватся от использования Windows и драйверов расширенной памяти.

Гораздо больше подходит на эту роль переполнение при делении. Эта исключительная ситуация признана довольно рядовой, и любая операционная система позволяет приложениям обрабатывать ее самостоятельно. В самом деле, иначе было бы невозможно существование математических программ. Как бы вам понравилось, если бы при попытке деления на ноль в электронной таблице Windows, сообщив о некорректном поведении приложения, закрывала бы его? Вообще непонятно, почему отладчики "взъелись" на это исключение и принялись обрабатывать его независимо от приложений. Самое интересное, что этим грешат даже некоторые эмулирующие отладчики!

Самое сложное в использовании этого приема - найти такой алгоритм, который не позволял бы обойти его непосредственным вызовом int 0. Т.е. если в теле защиты есть некая инструкция DIV, которая вызывает обработчик исключения, то ничего не стоит заменить ее на непосредственный вызов прерывания int xx, предварительно переустановив обработчик на любое свободное значение.

Рассмотрим следующий пример, где подобная замена просто невозможна (взят из реальной защиты):

NewInt00h: 
   ADD SI,AX 
   CBW 
   ADD SP,6 
Repeat: 
   LODSW 
   DIV AH 
   STOSB 
   LOOP Repeat 

Зашифрованный фрагмент содержал помимо всего прочего инструкции декодирования. Изучите защиту внимательно еще раз, и вы поймете, что это так. Внешне расшифровщик очень прост. Пара чисел a и b расшифровывается как целая часть от a/b. Но если b равно нулю, тогда a интерпретируется как указатель на следующую расшифровываемую инструкцию. Т.е. декодер может "прыгать блохой" и одновременно разжимать текст, фактически реализуя LZ-распаковку. Дешифровщик и распаковщик в одном флаконе и в семи ассемблерских командах - не правда ли, результат, которым можно гордиться? (Теперь можно уточнить, что это фрагмент из моей защиты).

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

Замечу, что приведенный фрагмент защиты был разработан специально для Win32 и успешно работал в Windows NT. Под NT существует немного отладчиков и все известные мне (по крайней мере на момент разработки защиты) перехватывали исключение деления на нуль и блокировали работу программы.

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

Приемы против отладчиков защищенного режима

Позже появился 80286 (с точки зрения хакера мало чем отличавшийся от своего предшественника), а вслед за ним и 80386, принесший принципиально новые возможности отладки. Точнее, "принципиально новые" только для платформы Intel, а еще точнее - для этой линейки микропроцессоров, ибо большая часть из того, что появилось только в 80386, уже было реализовано давным-давно на других платформах, например на PDP. Однако это были большие, серьезные, дорогостоящие машины, которые в восьмидесятые годы никак нельзя было сравнивать с персоналками, коим и применения достойного еще не могли найти. Компания Intel первой решилась усилить возможности отладки на "домашнем компьютере", догадываясь, что пройдет совсем немного времени, прежде чем программное обеспечение усложнится настолько, чтобы реально потребовать той мощи, которая была заложена в 80386 чип.

Новый процессор полностью унаследовал все "прелести" реального режима, включая и автоматическую трассировку. Т.е. сохраняя полную совместимость "сверху-вниз". Полную, да не совсем. Изменилась реакция процессора на модификацию сегментных регистров. 8086 ввел такое интересное понятие, как "потеря трассировочного прерывания", которое возникало всякий раз, как предыдущая команда изменяла любой сегментный регистр. При этом трассировочное прерывание действительно терялось на одну команду. 80386 несколько изменил свое поведение. Теперь потеря происходила только при изменении сегмента стека SS. Впрочем, взгляните сами:

PUSH DS 
POP  DS 
PUSH SS 
POP  SS 
RET 

Хотя я сильно сомневаюсь, что читателю будет легко найти XT в рабочем состоянии, но... Как говорится, охота пуще неволи. Побродите по радиорынкам, поищите старые материнские платы - быть может, вам и повезет. Иначе придется верить только на слово.

Как можно использовать потерю трассировочного прерывания? Например, можно помешать войти в ключевую процедуру:

  PUSH SS 
  POP  SS 
> CALL MyGodProc 

Конечно, это очень наивно. Достаточно установить в этой строке точку останова (неважно, аппаратную или программную), чтобы независимо от флага трассировки войти в нее. Между тем такой код не редкость даже в современных защитах. Совершенно непонятно: на что же рассчитывают разработчики? Неужели все еще на пользователей Debug.com?

Разумеется, современные отладчики все реже и реже используют автоматическую трассировку: они пользуются аппаратными точками останова. Что это такое? Вообще-то эта книга не "Intel Architecture Software Developer's Manual", и подробного объяснения тут не будет. Любой уважающий себя разработчик должен подробно ознакомиться с документацией Intel в первоисточнике. В частности, процесс отладки описан в главе 14 технического руководства N 24319201, доступного на сайте Intel.ru

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

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

Но в 80386 все кардинально изменилось. Теперь процессор предоставлял отладчику исчерпывающую информацию об отлаживаемом приложении и мог позволить контролировать каждый его шаг.

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

Иначе говоря, невозможно обнаружить правильно спроектированный отладчик или выйти из-под его контроля. К сожалению, таковых на сегодняшний день выпущено немного; мне достоверно известен только один: cup386, которому не научилась противостоять еще ни одна защита. Soft-Ice, к сожалению, оставляет часть своего кода в общем адресном пространстве с отлаживаемой программой и, что самое неприятное, позволяет ей свободно манипулировать отладочными регистрами, а значит снимать установленные отладчиком контрольные точки.

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

Для написания такой утилиты не потребуется особых знаний и навыков. Обо всем позаботились инженеры Intel, вам остается только воспользоваться предлагаемыми возможностями. Аппаратная отладка базируется на восьми специально выделенных для этой цели регистрах DR0-DR7. Чтение и запись их осуществляется командой MOV. Никаких других команд для манипуляций с этими регистрами не предусмотрено. Доступ к этим регистрам возможен только в следующих случаях:

  • реальный режим процессора (Real-Mode);

  • режим SMM (System Management Mode);

  • защищенный режим, CPL0.

В противном случае будет сгенерировано исключение GPF (General Protection Fault). Отсюда видно, что управлять отладочными регистрами из прикладной программы Windows (исполняющейся в CPL3) никак не получится.

Поэтому для упрощения изложения материала все нижесказанное будет относиться только к реальному режиму и MS-DOS. Написание приложений, работающих в нулевом кольце операционной системы Windows, выходит за рамки данной книги и поэтому рассматриваться не будет. Интересующихся я отсылаю к MSDN. MicroSoft предоставила достаточно примеров программ, позволяющих если не освоить системное программирование, то по крайней мере использовать эти заготовки для своего кода.

Наиболее важным из всех отладочных регистров является DR7. который задает режимы работы всех четырех контрольных точек (а их может быть, к сожалению, только четыре).

****************** Рисунок p15 *************

Биты Gx и Lx указывают на глобальность (локальность) контрольной точки. Бит Lx очищается при каждом переключении контекста задачи, а Gx - нет. Если тот или иной бит взведен, то это означает, что контрольная точка n установлена и остальные биты этого регистра уточняют условие ее срабатывания. (В реальном режиме оба флага равноценны и можно выбирать любой по вашему вкусу).

Назначение флагов LE и GE здесь рассматривать не будем, отметим только, что Intel рекомендует устанавливать оба в единицу, чтобы ваши действия возымели должный эффект.

Пара бит R/W задает следующие условия срабатывания контрольной точки:

a) Если бит DE регистра CR4 установлен:

COLUMNS(2), DIMENSION(IN), COLWIDTHS(1.2042,4.0883), WIDTH(8.1767), ABOVE(.0984), BELOW(.0984), HGUTTER(.0555), VGUTTER(.0433), BOX(Z_DOUBLE), HGRID(Z_SINGLE), VGRID(Z_SINGLE), KEEP(OFF), ALIGN(CT)

ZGT, ZGT

R/W

TTL9, TTL9

00, Прерывание по исполнению

01, Прерывание по записи данных

10, Прерывание по записи\чтению в порт ввода\вывода

11, Прерывание по записи и чтению данных,, но не исполнению

б) Если бит DE регистра CR4 сброшен:

COLUMNS(2), DIMENSION(IN), COLWIDTHS(1.2042,4.0883), WIDTH(8.1767), ABOVE(.0984), BELOW(.0984), HGUTTER(.0555), VGUTTER(.0433), BOX(Z_DOUBLE), HGRID(Z_SINGLE), VGRID(Z_SINGLE), KEEP(OFF), ALIGN(CT)

ZGT, ZGT

R/W

TTL9, TTL9

00, Прерывание по исполнению

01, Прерывание по записи данных

10, Неопределено

11, Прерывание по записи и чтению данных,, но не исполнению

Заметим, что перехват обращения к портам ввода-вывода появился несколько позднее на процессорах Pentium. Ни 80386, ни 80486 еще не имели такой возможности.

Два бита LENn задают длину контрольной точки:

COLUMNS(2), DIMENSION(IN), COLWIDTHS(1.2042,4.0883), WIDTH(8.1767), ABOVE(.0984), BELOW(.0984), HGUTTER(.0555), VGUTTER(.0433), BOX(Z_DOUBLE), HGRID(Z_SINGLE), VGRID(Z_SINGLE), KEEP(OFF), ALIGN(CT)

ZGT, ZGT

LEN

TTL9, TTL9

00, 1 байт

01, 2 байта

10, Неопределено

11, 4 байта

Флаг DG (general detect enable) очень любопытен и заслуживает пристального рассмотрения. Он позволяет полностью защитить отладчик от агрессивных программ. Как уже было сказано выше, манипуляции с отладочными регистрами в защищенном режиме возможны только в нулевом кольце защиты. На первый взгляд, это надежно защищает отладчик от попыток защиты модифицировать отладочные регистры или прочитать их и на этой основе сделать вывод о присутствии отладчика.

Но что если защита сама работает в нулевом кольце? Или в "голой" MS-DOS в реальном режиме? Неужели, как говорят, "сушите весла - приехали"? На самом деле инженеры Intel предусмотрели такой поворот событий и ввели новую возможность - перехват обращений к отладочным регистрам. Если флаг DG установлен, то любое обращение к DR0-DR7 вызовет отладочное исключение, т.е. передаст управление отладчику. Теперь последний может для сокрытия своего присутствия проэмулировать эту инструкцию или просто остановить работу (последнее, впрочем, не очень разумно).

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

Это тот самый случай, когда необходимо садиться за написание собственного трассировщика. Однако последнее возможно далеко не всегда. Защите ничего не стоит занять все четыре контрольные точки под свои нужды. При этом грамотно спроектированная защита будет использовать их так, чтобы их невозможно было проэмулировать средствами самого процессора. Например, защита использует четыре потока, каждый из которых расшифровывает себя аппаратной трассировкой. Процессор позволит перехватить обращение программы к отладочным регистрам, перекладывая эмуляцию на плечи разработчика отладчика. Но для эмуляции необходимы свободные отладочные регистры, а их нет.

Отметим этот очень важный момент. Вопреки распространенному заблуждению, что проэмулировать отладочный регистр нельзя. Все эмуляция сводится лишь к переадресации регистров. Так, например, если отладчик использует DR0 для своих нужд и к нему же обращается защита, то он может заменить DR0 на DR1 (к примеру) и при этом защите никак не удастся обнаружить такую подмену. Однако, когда защита потребует все четыре контрольные точки, отладчику придется отдать все свои ресурсы и самому остаться ни с чем. К счастью, подобных защит немного. Большинство из них просто используют отладочные регистры как регистры общего назначения или периодически заполняют их мусором. Разаработки, наверное, думают, что этим они страшно осложняют отладчику жизнь. На самом деле ничуть! Действительно, проэмулировать запись\чтение в отладочный регистр очень просто. Достаточно отслеживать обращения к нему и перенаправлять все вызовы в отдельную переменную. Защита может записывать, читать, сравнивать - и все это будет работать.

Вообще же существует не так много защит, манипулирующих отладочными регистрами. И это понятно. В Windows, например, чтобы "дотянуться" до них, необходимо спуститься на уровень нулевого кольца, что само по себе является нетривиальной задачей. Разработчики редко решаются на такой шаг. К тому же из нулевого кольца можно сделать нечто более оригинальное, чем попытаться отнять ресурсы у отладчика. Положим, мы их отнимем. Но какими усилиями! А что выиграем? Хакер возьмет в руки дизассемблер и, не испытывая больших затруднений, пройдет все уровни защиты.

Однако мы забегаем вперед. Вернемся к описанию архитектуры отладки. Четыре регистра DR0-DR3 задают линейный физический адрес контрольной точки или порта ввода\вывода. На выбор адреса наложены некоторые ограничения. Так, если размер контрольной точки составляет слово, она должна располагаться по четному адресу. При двойном слове - по адресу, кратному четырем. Смысл этого станет ясен, если учесть, что поле LEN маскирует младшие биты регистра адреса. Это связано с микроархитектурой процессоров Intel и иногда может служить источником неудобств. Так, например, установить контрольную точку останова на слово, расположенное по адресу 0x13, просто невозможно. Адрес будет округлен до 0x10, и мы рискуем как натолкнуться на ложные обращения, так и пропустить искомые.

                 -----T----T----T----¬
                 ¦    ¦    ¦    ¦    ¦  Попытка установить сюда
                 L----+----+----+-----
                 ¦                   ¦
--T----T----T----T----T----T----T----T----T-----------------------
  ¦ 10 ¦ 11 ¦ 12 ¦ 13 ¦ 14 ¦ 15 ¦ 16 ¦ 17 ¦
--+----+----+----+----+----+----+----+----+------------
  ¦                   ¦
  -----T----T----T----¬
  ¦    ¦    ¦    ¦    ¦  А получилось сюда!
  L----+----+----+-----

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

Если же контрольная точка срабатывает, то она генерирует отладочное исключение 0x1. В реальном режиме обработчик все еще оказывается уязвимым и может быть модифицирован отлаживаемой программой. При этом нельзя установить точку останова на адрес 0x4, т.к. тогда процессор просто не сможет вызвать обработчик отладочного исключения. Существуют приемы позволяющие в той или иной степени этому противодействовать, но все они не универсальны и рассчитаны на то, что разработчик защиты не будет настолько дотошным, чтобы предусмотреть в защите все варианты.

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

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

Однако для отладчика необходима дополнительная информация об источнике вызвавшего его исключения. Частично эта проблемма решена инженерами Intel, частично же придется поработать вам самим.

Регистр DR6 - это регистр статуса. Четыре младших бита ассоциированы с четырьмя контрольными точками. Как только контольная точка срабатывает, соответствующий бит регистра DR6 устнавливается в единицу. Любопытно, что даже если не установлен бит Gn (Ln) и точка останова не вызвала отладочного исключения, соответствующий бит регистра статуса все же будет установлен в единицу. Подумайте на досуге, как можно использовать эту тонкость архитекуры.

Флаг BD установлен, если следующая инструкция обращается к любому из отладочных регистров. При этом необходимо, чтобы бит GD регистра DR7 был равен единице, иначе ничего не произойдет. Заметим, что эмулятор должен правильно выставлять значение этого бита в соответствии с флагом GD. Обычно отлаживаемая программа сбрасывает последний. При этом BD, равный единице, красноречиво свидетельствует об активном отладчике, на что защита может соответствующе прореагировать. К сожалению, многие распространенные отладчики никак не учитывают этот факт. Но, с другой стороны, не так много разработчиков осведомлены об этой тонкости, и несовершенство отладчиков проблем обычно не вызывает.

Бит BS устанавливается во время пошаговой трассировки программы. Заметим, что если отлаживаемое приложение имеет доступ к DR6, то это еще один способ обнаружить трассировку. Иногда это встречается в различных вирусах и антивирусных мониторах с целью обнаружить и блокировать трассировку. Причем это относится не только к DOS программам, но к Windows-приложениям. Уже существуют вирусы, работающие в нулевом кольце, они могут как угодно манипулировать с отладочными регистрами.

Ненулевое значение Флага BT говорит о том, что последнее исключение вызвано переключением задач. К отладочным регистрам это непосредственно не относится, поэтому и не рассматривается здесь подробно.

<B>Важное замечание:<D> содержимое регистра DR6 никогда не очищается процессором. Поэтому он должен обнуляться отладчиком после считывания результата.

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

Но хакер должен всегда мыслить на самом "низком" уровне - уровне микропроцессора и железа. Точнее, даже на уровне микроархитектуры процессора, а не готовых к применению команд и регистров. В самом деле: почему контрольных точек только четыре? Почему поля LENn маскируют младшие биты адреса контрольной точки? С чем все это связано? К сожалению, на этот вопрос невозможно ответить в рамках данной книги. Для этого нужно подробно изучить архитектуру микропроцессора и взаимодействие отдельных его компонентов. При этом многие вопросы отпадут сами собой и мотивы разработчиков станут понятными.

Для закрепления изложенного материала предлагается рассмотреть пример crack18, который устанавливает точку останова на чтение\запись по адресу 0x9000:0 (точнее, физическому адресу 0x90000). При этом раздастся предупредительный сигнал. Программа не работает в DOS окне в операционной системе Windows. Необходим режим эмуляции MS-DOS без установленных драйверов типа emm386.

Рассмотрим здесь ключевой ее фрагмент:

      MOV eax,00000000110000001100000010b
      ;       ¦¦      ¦¦      ¦¦      ¦¦
      ;       ¦¦      ¦¦      ¦¦      ¦L---> Бит Lx Может  быть  установлен
      ;       ¦¦      ¦¦      ¦¦      L----> Бит Gx любой из них.
      ;       ¦¦      ¦¦      ¦¦
      ;       ¦¦      ¦¦      L+-----------> Биты LE & GE. P6 их игнорирует   ~~10
      ;       ¦¦      ¦¦                     Поэтому их значение некритично
      ;       ¦¦      ¦¦
      ;       ¦¦      L+-------------------> R\W На чтение и  запись памяти
      ;       ¦¦
      ;       L+---------------------------> LEN Длина конт. точки. 1 байт
      

      MOV ebx,090000h
      ;       ^^^^^^^- линейный физический адрес точки останова.
      ;                вычисляется как segment*0x10+offset
      

      MOV dr7,eax
      mov dr0,ebx
      ; ^ Заносим значения в отладочные регистры. С этого момента любое
      ; обращение к контольной точки будет приводить к генерации отладо-
      ; чного исключения Int 0x1.

Микропроцессоры Intel, начиная с Pentium предоставляют возможность установления контрольной точки на порты ввода\вывода. Ранее их можно было перехватывать только в защищенном режиме, опираясь на привилегированность инструкций чтения\записи в порт. Разумеется, это было неудобно и недостаточно: поэтому в Pentium реализован механизм перехвата портов через контрольные точки. При этом сам порт необязательно должен физически существовать. Последнее позволяет не только эмулировать неподключенные устройства, но и писать драйверы под полностью виртуальное аппаратное обеспечение, что иногда реализуется некоторыми системами.

Следующий пример издает короткий звук при обращении к порту 1. Можно считать, что этим мы эмулируем некоторое несуществующее устройство. Или, что ближе к проблеме защиты информации, перехватываем обращение к порту, после чего последний переходит в наше распоряжение. (Например, так можно написать 100% эмулятор FDD и ключевой дискеты к нему, при этом ни одна защита не сможет отличить его от настоящего).

       MOV  eax,cr4
       ; ^ Считываем начальное значение управляющего регистра Cr4
       

       OR eax,01000b
       ;       ^
       ;       L-------> Флаг DE
       ;
       ; Устанавливаем флаг DE (смысл этого был изложен выше).
       

       MOV cr4,eax
       ; ^ Записываем новое значение
       

       MOV eax,0100000001100000010b
       ;        ^^      ^^      ^^
       ;        ¦¦      ¦¦      L+--> Флаги Ln,Gn. Любой должен быть взведен
       ;        ¦¦      ¦¦
       ;        ¦¦      L+----------> Флаги LE,GE.Значение некритично для P6
       ;        ¦¦
       ;        L+------------------> Точка останова на I\O
       

       MOV ebx,00001h
       ;       ^^^^^^
       ;       ¦¦¦¦¦¦
       ;       L+++++---------------> Адрес порта I\0
       

       MOV dr7,eax
       mov dr0,ebx

Рекомендую поэкспериментировать с контрольными точками. Нетрудно убедиться, какое это мощное средство и какие перспективы оно открывает. Как уже упоминалось выше, можно перехватывать обращения к портам и замещать существующее оборудование или эмулировать неподключенное. Так, например, можно проэмулировать электронный ключ "ХАСП" или любой другой. Ключевую дискету (вместе с дисководом). Если защита привязывается к серийному номеру IDE винчестера, то нетрудно перехватить его порты и выдавать ложную информацию, вводя защиту в заблуждение. Аналогично решается и привязка к дате создания BIOS (для этого достаточно установить контрольную точку в необходимом месте). При этом нет никаких противоречий с законодательством. Действительно, клиент вправе эмулировать любое оборудование, которое пожелает. Впрочем, тут есть маленькое исключение. Возможен конфликт с патентным правом. Запрещается без соответствующего разрешения каким бы то ни было образом воспроизводить запатентованное аппаратное обеспечение. Однако тут обе стороны наталкиваются на расплывчатость формулировок и законодательных статей. Является ли программная эмуляция воспроизведением аппаратного устройства? С одной стороны да, т.к. прикладная программа его не может отличить. С другой стороны - нет, поскольку эмулятор может быть построен по совершенно другой архитектуре.

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

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

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

Однако оставим патентное право в стороне и перейдем непосредственно к вопросу, как защиты могут противостоять отладке. Первое и самое простое решение (как уже отмечалось выше) - это периодически забивать мусором отладочные регистры. Несмотря на комичность ситуации, Софт-Айс этого не переживет. Впрочем, не переживет этого и разработчик. Программа не будет работать в среде WINDOWS (разве что в нулевом кольце), что не понравится клиенту и он уйдет к другому разработчику. При этом надежность такого подхода сомнительна - ведь можно просто найти все команды обращения в регистрам DR0-DR7 и удалить их. Чтобы этого избежать, разработчик будет вынужден хранить в них полезные данные и при этом задействовать все остальные регистры так, чтобы у хакера не было возможности заменить отладочный регистр на какой-нибудь другой или использовать команды PUSH\POP. Скажу сразу, что построить защиту таким образом не просто трудно, но практически невозможно. Поэтому сегодня крайне редко можно встретить прикладную программу, манипулирующую отладочными регистрами. За исключением, быть может, чтения DR6 и попытки обнаружить активную отладку (или DR0-DR3 с проверкой, не стоит ли контрольная точка в определенном месте). Разумеется, все это наивно: хороший отладчик не должен позволять приложению читать отладочные регистры, это просто смешно. Если защита остерегается контрольной точки в некотором месте, то ее без колебаний можно установить именно туда и тем самым сократить время анализа. Любопытно, но последнее все же встречается. На моей жизни я видел две таких защиты, и обе были созданы одним автором!

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

Необходимо воспользоваться либо эмулирующим отладчиком (но под Windows и с полной эмуляцией 386+ таких вроде бы нет), либо дизассемблером. Последнее, впрочем, не решает проблему полностью, поскольку дизассемблер все же не эквивалентен отладчику.

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

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

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

История "запирания" клавиатуры восходит к глубокой древности. Во времена PC\XT достаточно было лишь запретить прерывания, чтобы "убить" консольные отладчики наподобие Debug.com . Сейчас, конечно, это выглядит несколько наивным. Действительно, отладчику, запустившему приложение, скажем, на отдельном V86, совершенно безразлично, как оно манипулирует прерываниями. Однако тут разработчик упустил из виду, несмотря на полную изоляцию отладчика и приложения клавиатура у них осталась общей. Заглянем в руководство по контроллеру клавиатуры - что же может сделать защита с последней? Например, существует любопытная команда 0xAD, блокирующая клавиатуру. При этом нажатие клавиш не будет обрабатываться вплоть до момента разблокировки последней командой 0xAE. Этот пример реализован в crack1A. Попробуйте его пошагово трассировать. Очень много отладчиков, начиная с TurboDebuger, убьются этим приемом. Поэтому рекомендую запускать их из DOS окна в операционной системе Windows, чтобы можно было безболезненно "прибить" зависшее окно мышью. Однако Soft-Ice на это не купится и клавиатуру не заблокирует - это еще раз подтверждает, что ребята из NuMega неплохо соображают.

Но и они кое-что упустили из виду. Действительно, у контроллера клавиатуры используется один и тот же порт как для задания адреса, так и для чтения\записи данных. Это уже любопытно. Получается, что после передачи кода команды контроллер клавиатуры не будет отрабатывать нажатие клавиш, пока не будет передан байт данных. Самое интересное, что отладчик не сможет определить причину "зависания" клавиатуры и не сможет корректно ее разморозить. Попробуйте потрассировать пример crack1B, используя Soft-Ice 2.8 (заметим, что это последняя версия отладчика под MS-DOS). При этом после первой же команды записи в порт клавиатура зависнет! Так приложение может защищать критические куски кода от отладчиков.

Однако версия 3.2, например, превосходно справляется с этой проблемой, поскольку виртуализирует порты. Т.е. защита обращается не к физическому контроллеру клавиатуры, а к мнимому, точнее - к эмулируемому отладчиком. И при этом никак испортить настоящий не может.

Аналогичным разделенным ресурсом является монитор, а точнее видеоконтроллер. Далеко не все отладчики способны корректно восстанавливать нестандартные видеорежимы. Это может быть использовано защитами, хотя, не столь часто. Видеокарточки во многом несовместимы, и в современных операционных системах низкоуровневый доступ к ним очень ограничен. К тому же в Windows, например, монитор разделен между всеми приложениями, а не только между защитой и отладчиком, как это было когда-то в MS-DOS. Поэтому крайне маловероятно, что читатель столкнется с такой защитой на практике. Если же такое вдруг случится, то можно попробовать подключить второй монитор (Soft-Ice это поддерживает) или воспользоваться удаленной отладкой по сети или нуль-модемному кабелю, что поддерживает большинство отладчиков.

Технологии эмуляции процессора

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

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

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


Части: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог