Приближение к даоЛеонид «Cr@wler» Исупов Хакер, номер #104, стр. 068 (crawlerhack@rambler.ru) Шифрование файла формата PE с использованием отладчика Удивительные (но закономерные) события творятся в мире IT-технологий. Средства разработки и защиты программного обеспечения, языки программирования высокого уровня за последнее время настолько абстрагировались от машинного диалекта, что многие уже разучились работать собственной головой. Всем подавай навесные пакеры да протекторы. Между тем иметь навыки «ручной» работы с машинным кодом очень полезно. Бессмертная технология Продолжим шифровать =). В предыдущей статье я на абстрактном примере (программка «Hello, World!», написанная на ассемблере, размером в пару килобайт) показал, как вручную написать маленький жучок - криптор - и запихать его внутрь PE-файла, после чего листинг программы под отладчиком можно было увидеть лишь после трассировки декодера. Напомню основную концепцию создания этого жучка, которая схожа с механизмом внедрения PE-вируса в файл. На место первых байт программы вставлялся прыжок (jmp) на декодер, который располагался в месте, свободном от исполнимых инструкций, а именно в секции нулей, созданной компилятором для выравнивания. Выглядело это примерно так: <jmp адрес_декодировщика> ... <Закодированные инструкции> ... < Тело_декодировщика: 1) процесс декодировки по некоторому алгоритму; 2) переход на точку входа программы; > Теперь я покажу тебе, как применить эту технологию не к обычной программе-«дрозофиле», исполнимого кода в которой всего-то на 26 байт наберется, а к настоящему приложению - к блокноту из стандартной поставки Windows. Мы зашифруем секцию кода простейшим методом, который должен быть тебе хорошо известен, если ты читал предыдущую статью. Метод этот - использование операции XOR 35h. Только теперь мы усложним себе задачу. Мы не будем пользоваться шестнадцатеричным редактором WinHex или каким-либо другим подобным инструментом. Ведь в предыдущей статье я писал, что мы приближаемся к тому, чтобы закодировать PE-файл вообще без каких-либо инструментов, вручную, с помощью того же notepad.exe и развитого мозгового аппарата! Итак, мы выкинули из нашего арсенала шестнадцатеричный редактор. Остался только отладчик OllyDbg. Первое, что мы сделаем, - исследуем программу. Откроем notepad.exe под отладчиком. Мы видим, что точка входа в данном случае равна 01006AE0. Запишем ее на листочек, она нам еще пригодится! Далее обрати внимание на то, какие инструкции расположены прямо на точке входа в программу: 01006AE0 PUSH 70 01006AE2 PUSH NOTE.01001888 Это очень хорошо, так как мы должны вставить на место первых инструкций команду вида «jmp адрес_декодера», а она занимает 5 байт, то есть затирает оба push’а, причем еще 2 байта при этом остаются свободными, их надо будет поменять на инструкции nop. А хороша эта ситуация тем, что данные в стек мы можем положить и после окончания цикла декодирования, то есть разместить эти инструкции прямо в теле декодера, непосредственно перед командой перехода на точку входа в программу. Таким образом, у нас уже есть примерный каркас нашего жучка-декодировщика: <Процедура декодировки> PUSH 70 PUSH 01001888 JMP 01006AE7; переход к точке входа, точнее, на 7 байт ниже нее, ведь первые 7 байт мы затерли jmp’ом! Итак, теперь мы можем заменить первые две инструкции программы следующими: JMP адрес_декодера NOP NOP Довершаем создание жучка Возникает второй вопрос: где поместить наш декодер? Посмотри: начиная с адреса 01007D71h идут сплошные нули, все они в нашем распоряжении! Ты можешь расположить жучок именно здесь, а я его впихну по адресу 01007DA3h (просто понравился адрес =). Теперь надо выяснить, что же мы будем шифровать, и начинать писать наш жучок. Стартовый адрес шифрования - точка входа (01006AE0h). Теперь прокрути дизассемблированный листинг ниже точки входа. Я вижу, что по адресу 01006D12h начинаются структуры, таблички сишных функций и прочая муть. Мы не будем трогать их, чтобы не рисковать работоспособностью программы. Значит, конечным адресом шифрования и будет 01006D12h. Посчитаем, сколько всего циклов должен будет выполнить декодер. Это значение равно разности двух полученных адресов: 01006D12h-01006AE0h=232h. Значит, мы получили следующую инструкцию для нашего жучка - инструкцию установки счетчика циклов (mov ecx, 232). Разумеется, цикл декодировки будем реализовывать с помощью «loop адрес». Теперь у нас есть практически все данные для написания декодировщика. Вот его вид (так он выглядит, если его ввести под отладчиком OllyDbg по смещению 01007DA3h): 01007DA3 MOV ECX,232; установка счетчика 01007DA8 PUSH EDX; сохранение регистра edx 01007DA9 PUSH ECX; сохранение регистра ecx 01007DAA MOV EDX,[ECX+01006AE0]; помещение в edx декодируемого значения из памяти 01007DB0 XOR EDX,35; декодирование 01007DB3 MOV [ECX+01006AE0],EDX; запись декодированного кода на его место 01007DB9 POP ECX; восстановление регистра ecx 01007DBA POP EDX; восстановление регистра edx 01007DBB LOOP 01007DA8; операция цикла 01007DBD PUSH 70; эта и следующая инструкции - такие же, как и первые 01007DBF PUSH 01001888; две инструкции секции кода, которые мы затерли jmp’ом 01007DC4 JMP 01006AE7; переход к декодированному коду Требуется сосредоточение Как видишь, код прост и в комментариях не нуждается. Если ты еще не ввел эти инструкции под отладчиком, то сделай это и приготовься к выходу в астрал. Готов? Теперь следующий шаг: вставляй на точке входа операцию jmp 01007DA3, а 2 байта, которые остаются после этой операции, как я уже говорил выше, заменяй nop’ами (скорее всего, это произойдет автоматически). Следующим логически верным шагом будет кодирование секции кода по алгоритму xor 35 (или по тому, которым ты его заменил, а алгоритм тут может быть любым!). Но как это сделать, если у нас нет шестнадцатеричного редактора? На самом деле он нам и не нужен! Ведь мы уже встроили в файл декодировщик, а при незашифрованной секции кода он работает как кодер, то есть в обратном направлении! Значит, можно просто запустить программу на исполнение, и она сама зашифрует секцию кода. Один тонкий момент: перед тем как нажать <Shift-F9> для запуска программы на исполнение, разреши запись в секцию кода (это делается так: нажимай <Alt-m>, указывай нужную нам секцию (она начинается по адресу 01001000h) правой кнопкой мыши и выбирай «Set access -> Full Access»). После этого запускай процесс (<Shift-F9>). Теперь наша программа закодировала сама себя! Возникает только одна проблема: кодер затер байты перехода, который мы вставили в начало секции. Это легко исправить, нужно снова поменять эти байты на jmp 01007DA3. Итак, все готово! Сохраняй файл под другим именем, это делается следующим образом: в меню правой кнопки мыши выбери «Copy to executable -> All modifications». Olly спросит нас, копировать ли данные в файл, на что надо ответить: Copy all. В открывшемся окне снова жми на правую кнопку мыши, выбирай Save file и сохраняй файл, например, под именем note1.exe. Теперь закрой Olly и попробуй запустить этот файл. Программа не хочет стартовать и выдает ошибку. Это происходит потому, что секция кода защищена от записи! Чтобы убедиться в этом, попробуй загрузить модифицированный файл из-под Olly, предварительно дав атрибуты RWE для секции кода (это мы уже делали выше). Программа тут же заработает! Значит, надо выставить атрибут RWE намертво, зафиксировав его в нашей PE’шке. Это очень легко сделать с помощью, например, LordPE или Hiew, но как быть, когда под рукой их нет? В справочнике находим, что в PE-заголовке 4 байта, которые в нашем файле начинаются с десятичного смещения 516 от самого его начала, отвечают за выставление флагов секции .text. Я нашел эти байты, открыв экзешник прямо в блокноте, и отсчитал 31 байт от заголовка секции (строки «.text», найденной с помощью поиска). Мы должны установить в четвертом, последнем байте этой последовательности (по десятичному смещению 519 от начала файла, в текстовом виде он выглядит как апостроф) старший бит в противоположное значение. Как это сделать? Из таблицы символов (а можно и при помощи debug.com) выясняем, что символу апострофа соответствует код 60h. Теперь вводим это значение в calc.exe и переключаемся в режим bin, чтобы увидеть, чему равно 60h в двоичном виде (01100000). После этого применяем операцию xor с помощью того же калькулятора. Xor по значению 10000000 даст нам установку старшего бита в единичное значение, что и требуется. В результате получаем значение 11100000 в двоичном или E0h в шестнадцатеричном виде. Теперь делаем следующее: выясняем десятичное значение этого числа (224), удаляем из-под блокнота этот символ-апостроф и на его место впечатываем новый символ, набирая «224» на цифровой клавиатуре с зажатой кнопкой <Alt>. Все готово! Теперь сохраняем файл и запускаем! Все работает! Зачем все это? Ты, конечно, спросишь: «Зачем столько мучений и извращений, когда можно воспользоваться удобными хакерскими инструментами и сделать ту же работу вдвое быстрее?» Ответ прост. Это необходимо для совершенствования умственных способностей. Тренируйся, выдумывай себе головоломки и скоро ты постигнешь искусство работы с форматом PE без инструментов. WARNING! Внимание! Перед тем как править любой файл, просто необходимо его зарезервировать. Иначе ты рискуешь потерять важные данные во время эксперимента. WWW www.wasm.ru - там ты узнаешь, как достичь дао в области кодинга. www.cracklab.ru - здесь тусуется лучшая часть крякерского сообщества. www.xakep.ru - тут все понятно ;). Лучший IT-журнал своего времени. |