Техника защиты компакт-дисков от копирования

Доктор Ватсон


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

Считается, что "Доктор Ватсон" предпочтительнее использовать на рабочих станциях (точнее –— на автоматизированных рабочих местах), а интерактивные средства отладки –— на серверах. Дескать, во всех премудростях ассемблера пользователи все равно не разбираются, а вот на сервере "продвинутый" отладчик будет как нельзя кстати. Отчасти это действительно так, но не стоит игнорировать то обстоятельство, что далеко не все источники ошибок обнаруживаются статическими средствами анализа, к тому же интерактивные инструменты значительно упрощают процедуру анализа. С другой стороны, "Доктор Ватсон" достается нам даром, а все остальные программные пакеты приходится приобретать за дополнительную плату. Так что предпочтительный обработчик критических ошибок вы должны выбирать сами.

Для установки "Доктора Ватсона" отладчиком по умолчанию добавьте в реестр следующую запись (листинг 3.1) или запустите файл Drwtsn32.exe c ключом "–i" (для выполнения обоих действий вы должны иметь права администратора).:

Листинг 3.1. Установка "Доктора Ватсона" отладчиком по умолчанию

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]


"Auto"="1"

"Debugger"="drwtsn32 -p %ld -e %ld -g"

"UserDebuggerHotKey"=dword:00000000

Листинг 1 установка "Доктора Ватсона" отладчиком по умолчанию

Теперь возникновение критических ошибок программы станет сопровождаться генерацией отчета, составляемого "Доктором Ватсоном" и содержащим более или менее подробные сведения о характере ее происхождения (рис. 3.3).



Рис.унок 3.4 3. drw.gif Реакция "Доктора Ватсона" на критическую ошибку



Образец дампа (dump), созданный "Доктором Ватсоном", приведен в листинге 3.2ниже. Комментарии, добавленные автором, выделены серым цветом.:

Листинг 3.2. Образец отчета "Доктора Ватсона" с комментариями автора

Исключение в приложении:

             Прил.:  (pid=612)

             ; pid процесса, в котором произошло исключение

            

             Время: 14.11.2003 @ 22:51:40.674

             ; время, когда произошло исключение

            

             Номер: c0000005 (нарушение прав доступа)

             ; код категории исключения

             ; расшифровку кодов исключений можно найти в WINNT.H

             ; входящим в состав SDK, прилагаемом к любому Windows-компилятору

             ; подробное описание всех исключений содержится в документации

             ; по процессорам Intel и AMD, бесплатно распространяемой их производителями

             ; (внимание: для перевода кода исключения операционной системы в

             ; вектор прерывания ЦП, вы должны обнулить старшее слово)

             ; в данном случае это 0x5 – попытка доступа к памяти по запрещенному адресу

            

*----> Сведения о системе <----*

             Имя компьютера: KPNC

             Имя пользователя: Kris Kaspersky

             Число процессоров: 1

             Тип процессора: x86 Family 6 Model 8 Stepping 6

             Версия Windows 2000: 5.0



             Текущая сборка: 2195

             Пакет обновления: None

             Текущий тип: Uniprocessor Free

             Зарегистрированная организация:

             Зарегистрированный пользователь: Kris Kaspersky

             ; краткие сведения о системе

*----> Список задач <----*

   0 Idle.exe

   8 System.exe

 232 smss.exe



1244 os2srv.exe

1164 os2ss.exe

1284 windbg.exe

1180 MSDEV.exe

1312 cmd.exe

 612 test.exe

1404 drwtsn32.exe

   0 _Total.exe

(00400000 - 00406000)

(77F80000 - 77FFA000)

(77E80000 - 77F37000)

; перечень загруженных DLL

; согласно документации, справа от адресов должны быть перечислены имена

; соответствующих модулей, однако практически все они так хорошо "замаскировались",

; что стали совершенно не видны. вытащить их имена из файла протокола все-таки можно,

; но придется немного пошаманить (см. ниже "таблицу символов")

Копия памяти для потока 0x188

; ниже идет копия памяти потока, вызывавшего исключение

eax=00000064 ebx=7ffdf000 ecx=00000000 edx=00000064 esi=00000000 edi=00000000

eip=00401014 esp=0012ff70 ebp=0012ffc0 iopl=0         nv up ei pl nz na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000202

; содержимое регистров и флагов

функция: <nosymbols>

; распечатка окрестной точки cбоя

             00400ffc 0000                   add             [eax],al                ds:00000064=??

             ; записываем в ячейку на которую ссылает EAX значение AL

             ; значение адреса ячейки, вычисленной Доктором Ватсоном, равно 64h

             ; что, очевидно, не соответствует действительности;

             ; Доктор Ватсон подставляет в выражение значение регистра EAX

             ; на момент возникновения сбоя, и это совсем не то значение, которое

             ; было в момент исполнения! к сожалению, чему был равен EAX в момент

             ; исполнения ни нам, ни Доктору Ватсону не известен.



            

             00400ffe 0000                  add      [eax],al                     ds:00000064=??

             ; записываем в ячейку, на которую ссылает EAX значение AL

             ; как? опять? что это  за бред?! вообще-то так кодируется

             ; последовательность 00 00 00 00, по всей видимости являющаяся

             ; осколком некоторой машинной команды, неправильно интерпретированной

             ; дизассемблерным движком Доктора Ватсона;

            

             00401000 8b542408       mov             edx,[esp+0x8]                   ss:00f8d547=????????

             ; загружаем в EDX аргумент функции

             ; какой именно аргумент – сказать невозможно, т.к. мы не знаем адрес

             ; стекового фрейма;

            

             00401004 33c9                  xor      ecx,ecx

             ; обнуляем ECX

            

             00401006 85d2                  test            edx,edx

             00401008 7e18                  jle      00409b22

             ; если EDX == 0, прыгаем на адрес 409B22h

            

             0040100a 8b442408       mov             eax,[esp+0x8]                   ss:00f8d547=????????

             ; загружаем уже упомянутый аргумент в регистр EAX

             

             0040100e 56                      push          esi

             ; сохраняем ESI в стеке, перемещая тем самым указатель вершины стека

             ; на 4 байта вверх (в область младших адресов)

            

             0040100f 8b742408       mov             esi, [esp+0x8]                 ss:00f8d547=????????

             ; загружаем в ESI очередной аргумент

             ; поскольку ESP был только что изменен, это совсем не тот аргумент,

             ; с которым мы имели дело ранее

            

             00401013 57                      push          edi

             ; сохраняем регистр EDI в стеке

             

СБОЙ -> 00401014 0fbe3c31         movsx    edi,byte ptr [ecx+esi]         ds:00000000=??



             ; вот мы и добрались до инструкции, возбудившей исключение доступа

             ; она обращается к ячейке памяти, на которую указывает сумма

     ; регистров ECX и ESI

             ; а чему равно их значение? прокручиваем экран немного вверх и находим, что

             ; что ECX и ESI равны 0, о чем Доктор Ватсон нам и сообщает: "ds:000000"

             ; отметим, что этой информации можно верить, поскольку подстановка

             ; эффективного адреса осуществлялась непосредственно в момент исполнения

             ; теперь вспомним, что ESI содержит копию переданного функции аргумента

             ; и что ECX был обнулен явно, следовательно в выражении [ECX+ESI]

             ; регистр ESI – указатель, а ECX – индекс.

             ; раз ESI равен нулю, то нашей функции передали указатель на невыделенную

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

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

             ; к сожалению, Доктор Ватсон не осуществляет дизассемблирование

             ; материнской функции, и какой из двух предполагаемых вариантов правильный

             ; нам остается лишь гадать… правда, можно дизассемблировать дамп памяти

             ; процесса (если, конечно, он был сохранен), но это уже не то…

            

             00401018 03c7                  add      eax, edi

             ; сложить содержимое регистра EAX с регистром EDI и записать результат в EAX

            

             0040101a 41                      inc            ecx

             ; увеличить ECX на единицу

            

             0040101b 3bca                  cmp      ecx,edx

             0040101d 7cf5                  jl        00407014

             ; до тех пор пока ECX < EDX, прыгать на адрес 407014

             ; (очевидно, мы имеем дело с циклом, управляемым счетчиком ECX)

             ; при интерактивной отладке мы могли бы принудительно выйти



             ; из функции, возвратив флаг ошибки, чтобы материнская функция

             ; (а с ней и вся программа целиком) могла продолжить свое выполнение

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

             ; остальные данные окажутся неискаженными;

            

             0040101f 5f                      pop            edi

             00401020 5e                      pop            esi

             00401021 c3                      ret

             ; выходим из функции

*----> Обратная трассировка стека <----*

; содержимое стека на момент возникновения сбоя

; распечатывает адреса и параметры предыдущих выполняемых функций,

; при интерактивной отладке мы могли бы просто передать управление

; на одну из вышележащих функций, что эквивалентно возращению в прошлое

; это только в реальной жизни разбитую чашку восстановить нельзя,

; в компьютерной вселенной возможно все!

FramePtr ReturnAd Param#1  Param#2  Param#3  Param#4  Function Name

; FramePtr:          указывает на значение фрейма стека,

;                    выше (т.е. в более младших адресах) содержатся аргументы функции

;                    ниже – ее локальные переменные

;

; ReturnAd:          бережно хранит адрес возврата в материнскую функцию

;                    если здесь содержится мусор и обратная трассировка стека[Y87] 

;                    начинает характерно шуметь, с высокой степенью вероятности

;                    можно предположить, что мы имеем дело с ошибкой "срыва стека"

;                    а возможно, и с попыткой атаки вашего компьютера

;

; Param#:            четыре первых параметра функции – именно столько параметров

;                    Доктор Ватсон отображает на экране; это достаточно жесткое

;                    ограничение – многие функции имеют десятки параметров и

;                    четыре параметра еще ни о чем не говорят; однако недостающие

;                    параметры легко вытащить из копии необработанного стека вручную



;                     достаточно лишь перейти по указанному в поле FramePtr адресу

;

; Func Name:         имя функции (если только его возможно определить); реально

;                    отображает лишь имена функций, импортируемые из других DLL,

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

;                    вместе с отладочной информацией практически нереально

;

0012FFC0 77E87903 00000000 00000000 7FFDF000 C0000005 !<nosymbols>

0012FFF0 00000000 00401040 00000000 000000C8 00000100 kernel32!SetUnhandledExceptionFilter

; функции перечисляются в порядке их исполнения; самой последней исполнялась

; kernel32!SetUnhandledExceptionFilter функция, обрабатывающая данное исключение

*----> Копия необработанного стека <----*

; копия необработанного стека содержит стек таким, какой он есть

; очень помогает при обнаружении buffer overfull атак – весь shell-код,

; переданный злоумышленником, будет распечатан Доктором Ватсоном, и вам

; останется всего лишь опознать его (подробнее об этом рассказывается

; в моей книге "Техника сетевых атак")

0012ff70  00 00 00 00 00 00 00 00 - 39 10 40 00 00 00 00 00  ........9.@.....

0012ff80  64 00 00 00 f4 10 40 00 - 01 00 00 00 d0 0e 30 00  d.....@.......0.



00130090  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................

001300a0  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................

*----> Таблица символов <----*

; таблица символов содержит имена всех загруженных DLL вместе с именами

; импортируемых функций. используя эти адреса в качестве отправной точки,

; мы без труда сможем восстановить «перечень загруженных DLL»

ntdll.dll

77F81106 00000000   ZwAccessCheckByType



77FCEFB0 00000000   fltused

kernel32.dll

77E81765 0000003d   IsDebuggerPresent



77EDBF7A 00000000   VerSetConditionMask

;

; итак, возвращаемся к таблице загруженных DLL

; (00400000 - 00406000)  - это, очевидно, область памяти, занятая самой программой

; (77F80000 - 77FFA000)  – это KERNEL32.DLL

; (77E80000 - 77F37000)  - это NTDDL.DLL


Содержание раздела