Мануальная терапия Крис Касперски ака мыщъх Спецвыпуск: Хакер, номер #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, мы видим, что его контрольная сумма не изменилась, значит, все было сделано правильно! |