Примеры реальных взломов
Вид материала | Документы |
- Учебник: / Страницы: , 162.62kb.
- В. А. Кулаков московский инженерно-физический институт (государственный университет), 28.6kb.
- И. Закарян И. Филатов, 3215.74kb.
- Задачи : Формирование выборки стран, сбор реальных данных ввп на душу населения 1990-2007, 59.29kb.
- Программа по курсу «Функциональный анализ», 36.73kb.
- 11 готовых сочинений на лингвистическую тему, 59.56kb.
- Экзаменационная программа по стилистике русского языка понятие стиль. Характеристика, 20.43kb.
- Визуализатор алгоритма программа, наглядно демонстрирующая работу алгоритма в пошаговом, 57.48kb.
- Методика по расчету (оценке) общего объема денежных доходов и реальных располагаемых, 252.43kb.
- Планирование аудита и основные его этапы. Тесты средств контроля и примеры их применения, 10.84kb.
UniLink v1.03 от Юрия Харона II
или переходим от штурма к осаде
"Не снабжайте детей готовыми формулами, формулы – пустота. Обогатите их образами и картинами, на которых видны связующие нити. Не отягощайте детей мертвым грузом фактов, обучите их приемам и способам, которые помогут им постигать. Не судите о способностях по легкости усвоения. Успешнее и дальше идет тот, кто мучительно преодолевает себя и препятствия. Любовь к познанию – вот главное мерило. Не учите их, что польза – главное. Главное – возрастание в человеке человеческого. Честный и верный человек гладко выстругает и доску. Научите их почтению, потому что насмехаться любят бездельники, для них не существует целостной картины"
Антуан де Сент-Экзюпери. Цитадель
Обычно хакеры избегают анализа кода, никак не связанного с защитными механизмами ломаемого приложения. Однако на этот раз мы сделаем исключение. Приемы программирования, использованные Юрием Хароном, интересны не только в контексте взлома, но и как занимательная головоломка сама по себе. За примером далеко ходить не надо: программа не импортирует ни одной API – функции, не использует прямых адресов Native API, а каким-то невероятным образом самостоятельно находит их адреса в памяти. Спрашиваете, как? Ответ погребен под многокилобайтным слоем машинного кода в исполняемом файле. Единственный путь во всем разобраться – проанализировать программу и воссоздать оригинальный алгоритм (можно, конечно, спросить и самого Юрия Харона, – надеюсь, он бы не пожадничал с ответом, – но, во-первых, готовые решения хакерам просто не интересны, а, во-вторых, прежде чем задать вопрос надо знать хотя бы половину ответа).
Кроме того, процесс "потрошения" линкера позволяет наглядно продемонстрировать преимущества связки отладчик + дизассемблер над каждым из этих инструментов по отдельности. Такие программы вообще не ломаются в дизассемблере! Даже возможностей IDA Pro окажется более чем недостаточно! Харон активно использует многоуровневые математические преобразования критических к раскрытию текстовых строк и указателей, "благодаря" чему они полностью растворяются в дизассемблерном коде, однако без труда обнаруживаются просмотром дампа памяти под отладчиком. С другой стороны, отладчик в силу другой профессиональной направленности очень плохо приспособлен для изучения взаимосвязи различных частей кода друг с другом и без помощи дизассемблера мы будем видеть не лес, но деверья…
Entry Point и ее окружение
Точка входа в программу начинается с традиционного сохранения регистра EBP (см. листинг $), которое вставлено сюда Хароном исключительно ради этики и приличия, а на самом деле совершенно необязательно, поскольку программа, завершающая свое выполнение по RETN (а UniLink свое выполнение именно так и завершает), передает управление функции ExitProcess, которой как в том анекдоте совершенно по фигу как надета тюбетейка, простите, какое значение содержит регистр EBP.
Следующая за ней команда – PUSH 42CFAEh открывает трилогию "математических манипуляций с указателем" и скрывает адреса передачи управления от дизассемблеров и "детишек". Эвристический анализатор IDA Pro всех версий ошибается, во-первых, принимая 42CFAEh за смещение, и во-вторых, генерируя совершенно "левую" перекрестную ссылку по соответствующему ему адресу. Чтобы махинации с указателем не так бросались в глаза, Харон сдабривает их небольшим количеством мусорного кода, используя для этой цели малораспространенные, а потому и незнакомые начинающим взломщикам, машинные команды XLAT и DAA, однако, результат их выполнения никак не используется в программе, что сразу же демаскирует "мусор" в глазах мало-мальски толковых хакеров.
Метаморфозы указателя очень хорошо наблюдать с помощью отладчика. Отдав команду "DD; D ESP" мы сможем увидеть следующую цепочку превращений: 42CEAEh 44CFAEh 406701h. Последнее значение и будет тем самым адресом на который защитный код спустя несколько машинных команд передаст управление. Чтобы "засечь" тот же самый факт в дизассемблере, все математические вычисления нам придется выполнить вручную. Ну, не то, чтобы совсем вручную (встроенный калькулятор в IDA еще никто не отменял), но такой путь чреват ошибками и вообще трудоемок. Достоинства отладчика в том, что можно вообще не вычислять целевой адрес, а просто сидеть и смотреть куда в следующее мгновение переметнется ветка управления.
001B:00446673 PUSH EBP ; // сохраняем EBP
001B:00446674 PUSH 0042CFAE ; // 1] кусочек указателя
001B:00446679 MOV EBX,ESP ; // EBX := ESP
001B:0044667B AND AL,03 ; м у с о р
001B:0044667D JB 00446682 ; NEVER JUMP
001B:0044667F INC BYTE PTR [EBX+02] ; // 2] 42CEAEh 43CFAEh
001B:00446682 XLAT ; м у с о р
001B:00446683 DAA ; м у с о р
001B:00446684 ADD DWORD PTR [ESP],00009753 ; // 3] 43CFAEh 446701h
001B:0044668B SBB CL,CL ; м у с о р
001B:0044668D LAHF ; м у с о р
001B:0044668E PUSH DWORD PTR [EBX] ; дублируем 406701h на стеке
001B:00446690 CLD ; для подстраховки ;-)
001B:00446691 RET ; JUMP TO 446701h
Листинг 63 код окрестностей точки входа. передает управление на 406701h (значимые команды выделены жирным шрифтом)
Маленькое замечание для начинающих. Вы думаете, что машинная команда RET в строке 446691h представляет собой инструкцию возврата из под программы? Так-то оно так, да не совсем. Если следовать этой логике, то данный RET должен был вышвырнуть программу обратно в Windows (точнее, в породившую ее материнскую функцию CreateProcessA). Но ведь этого не происходит, верно? На самом деле, инструкция RET ничего не знает о породивших ее функциях. Она просто снимает двойное слово с верхушки стека (где при нормальном развитии событий находится адрес возврата) и передает туда управление. Таким образом, конструкция "PUSH p/RETN" полностью эквивалента "JMP p" за тем исключением, что прямой jump слишком нагляден, а вот состояние стека на момент выполнения инструкции RETN в дизассемблере не видать и все, что нам остается: либо наивно надеяться, что данный RET "легален" и действительно возвратит нас туда, откуда мы были вызваны, либо же утомительно анализировать весь код функции в попытке обнаружить "теневые" манипуляции с указателем стека или лежащем на его вершине значением. Если ни то, ни друге вас не прельщает, – запустите свой любимый отладчик и загляните на стек в "живую".
В данном случае он должен выглядеть так:
RETN:...
23:0012FFB8 00446701h – дублированный указатель BOND 007
00446701h – указатель BOND 007, полученный путем хитрых махинаций
0012FFF0h – сохраненное значение EBP (кадр стека CreateProcess)
77E87903h – адрес возврата в CreateProcess
........
Листинг 64 содержимое стека на момент выполнения инструкции RETF
Выделенная жирным цветом строка и есть тот адрес, на который RENT передает управление.