Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #57, АВГУСТ 2005 г.

Мануальная терапия

Крис Касперски ака мыщъх

Спецвыпуск: Хакер, номер #057, стр. 057-080-4


Так-так-так, контрольная сумма накапливается в регистре EDX (MOV DL, [EAX]/ADD EDX, EBX), который тут же пересылается в регистр EBX (MOV EBX,EDX), а спустя некоторое время EBX сравнивается с какой-то ячейкой памяти (MOV EAX, [406030]/XOR EAX,EBX). Если они идентичны друг другу, выполняется условный переход по адресу 401088h (JZ 401088). Вот этот переход и портит всю малину, препятствуя нормальной работе хакнутой программы. Если изменить XOR EAX,EBX (33 C3) на XOR EBX,EBX (33 DB или 31 DB), программа будет взломана окончательно.

В редакторе HTE это делается так: загружаем файл, давим <F6> (mode), выбираем pe/image, жмем <F5> (goto) и вводим адрес перехода (401078h), говорим <F4> (edit), а затем <Ctrl-A> (Assemble). Вводим "XOR EBX,EBX", и… HTE запрашивает, каким именно образом мы хотим ассемблировать ее. Этой возможности нет ни у одного другого известного мне hex-редактора! Выбрав любой вариант (оба они двухбайтные), нажимаем <F2> (save) для сохранения изменений и по <F10> выходим из редактора.

Законченная реализация

Попробуем усилить защищенность механизма самоконтроля. Добавим в начале программы следующие строки (полный вариант можно найти в файле demo.protected.c):

Защитный код, обслуживающий нестандартную секцию

// начало нестандартной кодовой секции с именем .tsl

#pragma code_seg(".tsl")

// начало охранной зоны

begin(){ return 0;}

// фиктивная функция, чтобы секция не была пустой

demo(){}

// конец нестандартной секции

#pragma code_seg()

// конец охранной зоны

endA(){ return 0;}

Прагма code_seg(имя_секции) предписывает линкеру размещать весь последующий код в секции с именем ".tsl", что он и делает. На самом деле, как мы уже говорили, это никакой не .tsl, а вполне законная секция кода, только с другим названием. Чтобы линкер не отбраковал секцию как ненужную, мы создает фиктивную функцию demo() и окружаем ее "охранной зоной".

Прагма code_seg() отменяет действие предыдущей прагмы, и весь последующий код ложится линкером в стандартную секцию .text или CODE. Поскольку минимальный размер секции составляет 1000h (вспомним про выравнивание), то, расположив endA() после code_seg(), мы получим в свое распоряжение 1000h байт. Только не перепутай их местами, иначе ничего не получится!

Откомпилировав полученный пример, загрузим его в HTE и перейдем в режим отображения заголовка (<F6>, "PE-header"). Мы видим секцию .tls, содержащую фиктивную функцию demo, и секцию .text с подлинным кодом программы. <ENTER> распахивает содержимое атрибутов секций, а <F4> позволяет редактировать их. Очень хорошо!

Секция .tls отстоит на 1000h байт от начала файла, а .text - на все 2000h. Чтобы отобразить первые 1000h байт секции .text на два региона адресного пространства, необходимо изменить raw offset первой секции, передвинув ее на 1000h байт вглубь файла. Подводим курсор к строке offset (здесь должно быть записано 1000h), нажимаем <F4> (edit) и изменяем ее на 2000h. Сохраняемся по <F2> и выходим. Запустив отредактированный файл с ключом --debug, мы видим, что его контрольная сумма не изменилась, значит, все было сделано правильно!

Назад на стр. 057-080-3  Содержание  Вперед на стр. 057-080-5