На главную | Содержание | Назад | Вперёд
Наши друзья

 

 

Декомпиляция и дизассемблирование программного обеспечения

Декомпиляция — это процесс преобразования двоичных исполняемых файлов (скомпилированной программы) в символический код на языке более высокого уров­ня, который лучше воспринимается человеком. Как правило, это означает превраще­ние выполняемой программы в исходный код на языке программирования, подобном языку С. Большинство систем для декомпиляции не способны на полное преобразова­ние программ в исходный код. Вместо этого предоставляется нечто среднее. Многие из декомпиляторов одновременно являются и дизассемблерами, которые предоставляют дамп машинного кода, который и заставляет программу работать.
Вероятно, на данный момент лучшим из общедоступных декомпиляторов явля­ется IDA-Pro. Работа этой программы начинается с дизассемблирования программ­ного кода, последующего анализа процесса выполнения программы, переменных и вызовов функций. Пользоваться IDA довольно сложно, а значит, предполагается на­личие серьезных специальных знаний. Программа IDA предоставляет полную биб­лиотеку API для работы с базой данных этой программы, поэтому пользователи мо­гут проводить свои собственные уникальные исследования.
Существуют и другие подобные средства. Например, программа REC с засекре­ченным исходным кодом (но бесплатная) обеспечивает полное восстановление ис­ходного кода на языке для некоторых исполняемых файлов. Еще один коммерче­ский дизассемблер называется WDASM. Существует и несколько декомпиляторов для байт-кода Java, которые позволяют получить исходный код на языке Java (этот процесс намного проще, чем декомпиляция машинного кода для чипов Intel). Эти

системы отличаются довольно высокой точностью, даже когда в программах приме­няются определенные методы маскировки. Также доступны и средства с открытым исходным кодом, которые заинтересованные читатели могут найти самостоятельно. Всегда следует иметь несколько декомпиляторов в своем арсенале, если вы хотите в полной мере понимать, как работает программа.
Декомпиляторы широко используются хакерами для взлома защиты от копирова­ния программ. Интересно отметить, что на заре компьютерной эпохи хакинг и пират­ский взлом программ были абсолютно независимыми направлениями деятельности. Хакинг зародился в среде UNIX, где программное обеспечение было бесплатным, а ис­ходный код был доступным, т.е. декомпиляция была просто не нужна. С другой сторо­ны, пиратские методы взлома были разработаны для взлома компьютерных игр, т.е. в основном предназначались для платформ Apples, DOS и Windows, для которых исход­ный код был обычно недоступен. Вирусы появились именно вследствие пиратского движения. В конце 1990-х годов, когда большинство сетевого программного обеспече­ния стало доступным для систем Windows и хакеры научились взламывать системы Windows, дисциплины хакинга и взлома объединились в одно целое. Основной акцент декомпиляции сместился от взлома защиты от копирования к аудиту программного обеспечения в целях выявления доступных для использования ошибок, т.е. в новой среде стали использоваться некоторые старые хитрости.
Декомпиляция на практике: восстановление исходного кода helpctr. ехе
В этом примере будет проиллюстрирован процесс восстановления исходного ко­да для файла helpctr. ехе — программы от Microsoft, которая поставляется совме­стно с операционной системой Windows XP. С этой программой связана* проблема безопасности, которую называют переполнением буфера. Сведения об этом уязвимом месте общедоступны уже достаточно давно, поэтому наше исследование не может быть использовано для реальной угрозы. Для нас важно лишь описать процесс вы­явления ошибки с помощью средств восстановления исходного кода и структуры программы. Для дизассемблирования проверяемой программы мы воспользовались средством IDA-Pro. При возникновении ошибки атакуемая программа создает спе­циальный отладочный файл Dr.Watson log (журнал ошибок). Мы используем только IDA и информацию в журнале ошибок для точного выявления места в программном коде, которое привело к возникновению ошибки. Обратите внимание, что для про­веряемого программного обеспечения исходный код не доступен. На 4 показа­но окно запущенной программы IDA-Pro.
Мы узнали о существовании этого уязвимого места, как и большинство других людей, прочитав сообщение в списке рассылки bugtraq, в котором как раз и обсуж­даются проблемы безопасности программ. В сообщении было только краткое описа­ние проблемы. Самыми ценными сведениями этого сообщения были имя исполняе­мого файла и входные данные, которые приводили к возникновению ошибки. В со­общении говорилось, что ввод в Internet Explorer URL-адреса hcp://w.w.w. w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w. приводил к запус­ку программы helpctr. ехе . Это достигалось после возникновения в приложении исключения (которое вызывалось удаленно с помощью Web-браузера).
Мы воссоздали ошибку, использовав данный URL-адрес как входные данные в среде Windows XP. Журнал ошибок создается операционной системой, а затем мы копируем этот журнал и двоичный файл на отдельный компьютер для проведения анализа. Обратите внимание, что для проведения анализа мы воспользовались уста­ревшей машиной под управлением Windows NT. Оригинальное окружение Win­dows ХР больше не потребовалось, после того как мы индуцировали ошибку и со­брали все нужные данные.

Журнал ошибок
При сбое в работе программы был создан дамп памяти для проведения отладки. В журнал ошибок добавляется трассировка стека (stack trace), благодаря которой определяется расположение программного кода, содержащего ошибку.
0006f8ac 0100b4ab 0006f8d8 00120000 00000103 msvcrt!wcsncat+0xle 0006fae4 0050004f 00120000 00279b64 00279b44 HelpCtr+0xb4ab 0054004b 00000000 00000000 00000000 00000000 0x50004f
Виновником ошибки является строка функции wcsncat. Дамп стека четко пока­зывает URL-строку. Мы видим, что URL-строка поглощает пространство стека и за­тирает другие значения.
*----> Raw Stack Dump <----*
000000000006f8a8 03 01 00 00 e4 fa 06 00
000000000006f8b8 00 00 12 00 03 01 00 00
000000000006f8c8 f9 00 00 00 b4 20 03 01 ____1 . .>.w
000000000006f8d8 43 00 3a 00 5c 00 57 00 C. : A.W.I.N.D.O.
000000000006f8e8 57 00 53 00 5c 00 50 00 W.S.N.P.C.H.e.a.
000000000006f8f8 6c 00 74 00 68 00 5c 00 l.t.h.\.H.e.l.p.
0000000000061"908 43 00 74 00 72 00 5c 00 C.t.rA.V.e.n.d.
000000000006f918 6f 00 72 00 73 00 5c 00 o.r.s.\.w...w...
000000000006f928 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f938 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f948 77 00 2e 00 77 00 2e 00 w...w...w...w...
000000000006f958 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f968 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f978 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f988 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f998 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f9a8 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f9b8 77 00 2e 00 77 00 2e 00
W...W...W...W...
000000000006f9c8 77 00 2e 00 77 00 2e 00 w...w...w...w.. .
000000000006f9d8 77 00 2e 00 77 00 2e 00
W...W...W...W..
Мы продолжаем наш анализ, учитывая, что ошибка возникла из-за строки функции wcsncat. С помощью IDA мы видим, что wcsncat вызывается из двух мест в коде.
.idata:01001004 extrn wcsncattdword      ;  DATA XREF:  sub_100B425 + 62L]r
.idata:01001004 ;  sub_100B425+77Dr ...
Правила работы с функцией wcsncat очевидны, к тому же получить описание можно из руководства пользователя. Вызову передается три параметра.
- ab Ь4 00 01 d8 f8 06 00
- d8 f8 06 00 a8 22 03 01
- cc 9b 27 00 cl 3e c4 77 .....
- 49 00 4e 00 44 00 4f 00
- 43 00 48 00 65 00 61 00
- 48 00 65 00 6c 00 70 00
- 56 00 65 00 6e 00 64 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00
- 77 00 2e 00 77 00 2e 00

1. Выходной буфер (указатель буфера).
2. Входная строка (предоставляется пользователем).
3. Максимальное количество предоставляемых символов.
Предполагается, что выходной буфер (destination buffer) достаточно большой для сохранения всех предоставляемых символов (обратите внимание, что в этом случае данные предоставляются внешним пользователем, который может оказаться хаке­ром). Именно в связи с данным обстоятельством для программиста предусмотрена возможность задавать максимальную длину предоставляемой строки. Представьте, что буфер — это стакан определенного размера, а вызываемая подпрограмма являет­ся способом для "добавления жидкости в этой стакан". Последний аргумент позво­ляет гарантировать, что "жидкость не перельется за край стакана".
В программе helpctr.exe выполняется несколько вызовов функции wcsncat из уязвимой подпрограммы. На следующем рисунке схематически изображены пра­вила осуществления вызовов функции wcsncat. Предположим, что выходной бу­фер имеет размер 12 символов и мы уже сохранили строку ABCD. Значит, в буфере остается место для 8 символов, включая и завершающий символ NULL. Теперь вызовем функцию wcsncat () и добавим строку EF. Как видно на сле­дующей схеме, эта строка добавляется в выходной буфер, начиная с символа NULL. Для защиты выходного буфера мы должны указать, что максимальное количество добавляемых символов не должно превышать семи. С учетом завершающего симво­ла NULL, это число станет равным восьми. Все остальные данные будут выходить за границы буфера, т.е. произойдет переполнение буфера.
wcsncat(target_buffer,   "EF",  7);
К сожалению, в уязвимой подпрограмме в файле helpctr. exe программист до­пустил небольшую, но фатальную ошибку. Относительно этой функции выполня­ются многочисленные вызовы, но значения максимальной длины никогда не обнов­ляются. Другими словами, постоянные добавления не учитываются для постоянно уменьшающегося пространства в конце выходного буфера. "Стакан" переполняется, но никто не видит, что "жидкость переливается за его края". На нашей следующей иллюстрации это продемонстрировано с помощью добавлению к исходному буферу строки EFGHIJKLMN, т.е. добавляется строка максимальной длины из И символов (или 12, если считать с символом NULL). Корректное значение не должно было пре­вышать семи символов.
wcsncat(target_buffer,   "EFGHIJKLMN",   11) ;

Высококлассный специалист по восстановлению исходного кода способен вы­явить и декодировать программный код, вызьтающий эту ошибку за 10-15 мин. Специалист среднего класса сделает то же самое за один час. Подпрограмма начина­ется с проверки, что она не передает пустой буфер. Это первое ветвление JZ. Если в буфере хранится значение, то мы видим, что в регистр заносится значение 103h. Это двоичное число 259, т.е. максимальный размер буфера равен 259 байт7. Как раз здесь и допущена ошибка. Мы видим, что это значение никогда не обновляется при ус­пешных вызовах wcsncat (). Строки символов неоднократно добавляются в иссле­дуемый буфер, но размер доступного места никогда не уменьшается. Это типичная ошибка в программном коде, допускаемая на стадии анализа (parsing). Анализ, как правило, включает в себя лексический и синтаксический разбор предоставляемых пользователем строк данных, но часто допускаются еще и ошибки при арифметиче­ских операциях с размером буфера.
Какой же будет окончательный вывод? Предоставляемое пользователем значе­ние переменной (задаваемое в URL-адресе, который используется для запуска helpctr. exe) передается этой подпрограмме, которая использует эти данные в се­рии потенциально опасных вызовов.
Увы, это еще одна проблема безопасности, вызванная просчетами при програм­мировании. В качестве домашнего задания мы предлагаем читателям создать про­грамму атаки на это уязвимое место, которая должна привести к компрометации компьютера.

 

На главную | Содержание | Назад | Вперёд
 
Яндекс.Метрика