¦ 7 0001 0E push cs ¦
¦ 8 0002 07 pop es ¦
¦ 9 0003 1F pop ds ¦
¦10 0004 BF 000Cr mov di,offset m ¦
¦11 0007 F9 stc ¦
¦12 0008 FC cld ¦
¦13 0009 B0 88 mov al,88h ¦
¦ ; заменить код операции следующей¦
¦ ; команды на mov byte ptr m, al. ¦
¦14 000B AA stosb ¦
¦15 000C 3A 06 000Cr m: cmp al,byte ptr m ¦
¦16 0010 73 06 jnc norm_ex ¦
¦17 0012 BA 0024r mov dx,offset trace ¦
¦ ; выполнение с трассировкой,¦
¦ ; если бит CF остался ¦
¦18 0015 EB 04 90 jmp exit ; установленным. ¦
¦19 0018 norm_ex: ¦
¦20 0018 BA 002Fr mov dx,offset norm ¦
¦21 001B exit: ¦
¦22 001B B4 09 mov ah,9 ¦
¦23 001D CD 21 int 21h ¦
¦24 001F B8 4C00 mov ax,4C00h ¦
¦25 0022 CD 21 int 21h ¦
¦26 ¦
¦27 0024 trace db 'Tracing!',0Ah,0Dh,'$' ¦
¦28 0024 ¦
¦29 002F norm db 'Normal exit.',0Ah,0Dh,'$' ¦
¦30 ¦
¦31 ¦
¦32 003E sample2 endp ¦
¦33 003E code ends ¦
¦34 end sample2 ¦
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
рис. 4.4
ОПРЕДЕЛЕНИЕ РЕЖИМА ТРАССИРОВКИ
(3 вариант)
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¬
¦ 1 0000 code segment para public ¦
¦ 2 assume cs:code,ds:code ¦
¦ 3 ¦
¦ 4 0000 sample3 proc ¦
¦ 5 ¦
¦ 6 0000 0E push cs ¦
¦ 7 0001 0E push cs ¦
¦ 8 0002 1F pop ds ¦
¦ 9 0003 17 pop ss ¦
¦10 0004 9C pushf ¦
¦11 0005 58 pop ax ¦
¦12 0006 F6 C4 01 test ah,1 ; бит TF установлен ? ¦
¦13 0009 74 06 jz norm_ex ; нет - уйти на norm_ex¦
¦ ; да - вып-ие с трассировкой¦
¦14 000B BA 001Dr mov dx,offset trace ¦
¦15 000E EB 04 90 jmp exit ¦
¦16 001 norm_ex: ¦
¦17 0011 BA 0028r mov dx,offset norm ¦
¦18 0014 exit: ¦
¦19 0014 B4 09 mov ah,9 ¦
¦20 0016 CD 21 int 21h ¦
¦21 0018 B8 4C00 mov ax,4C00h ¦
¦22 001B CD 21 int 21h ¦
¦23 ¦
¦24 001D trace db 'Tracing!',0Ah,0Dh,'$' ¦
¦25 ¦
¦26 0028 norm db 'Normal exit.',0Ah,0Dh,'$' ¦
¦27 ¦
¦28 ¦
¦29 0037 sample3 endp ¦
¦30 0037 code ends ¦
¦31 end sample3 ¦
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
рис. 4.5
DLOCK ver 2.0
DLOCK.EXE - программа встраивания в .EXE файлы модуля защиты от
отладчиков и дизассемблеров, которая сама может использоваться как
часть защиты программного обеспечения. Ее достоинством является то,
что пользователь выбирает место расположения встраиваемых защитных
модулей в своей программе.
Формат запуска программы:
DLOCK <имя файла> <смещение>
где:
<имя файла> - полное имя защищаемого .EXE файла.
<смещение> - смещение от начала файла, заданное в любой системе
счисления до начала буфера , в который будет размещен
модуль защиты (не менее 300h байт).
Для нормальной работы, при программировании необходимо
зарезервировать в своей программе область памяти не менее 300h байт.
Упростить поиск этой области в оттранслированном .EXE файле поможет
какое-нибудь оригинальное ключевое слово. Например:
Ассемблер: DB 'figtebe',300h DUP (?)
C: char buf[0x300] = "figtebe" ;
Средствами поиска любой оболочки DOS (XTREE, Norton Commander,
PCTOOLS и др.) находим ключевое слово и определяем по нему смещение,
требуемое в качестве 2-го аргумента формата запуска программы.
Например, если при просмотре командой View (в режиме Hex) в пакете
XTREE .EXE файл выглядел так:
. . . . . . . . . . . . . . . . . . .
000240 kstackstackstack
000250 .3.P..........!.
000260 ....figtebe.....
000270 ................
. . . . . . . . . . . . . . . . . . .
то смещение равно 264 и формат запуска программы такой:
DLOCK YOURFILE.EXE 0x264
рис. 4.6
5. САМОМОДИФИКАЦИЯ ПРОГРАММ - ЭФФЕКТНО И ПОЛЕЗНО
С самомодифицирующейся программой, т.е. такой программой, которая
постоянно меняет свой исполняемый код, разбираться очень трудно.
Представьте, в распечатке с дизассемблированным текстом хакер не понял
какой-то участок. Естественно, что он загрузит отладчик и попробует
"прогнать" непонятный блок в пошаговом режиме. Каково же будет его
удивление, когда он не сможет найти эту часть - по тем же адресам
записано совсем другое. Он удивится еще больше, после того как сравнит
имеющийся листинг с тем, что выводится на экран компьютера. "Ведь это
посторонняя программа! А где же та, на анализ которой я потратил
столько времени?" - воскликнет он. И при последующих попытках
происходит тоже самое - каждый раз предыдущий текст бесследно
исчезает, а на его месте возникает нечто новое, требующее повторного
анализа.
Впрочем, полностью самомодифицирующиеся модули - большая
редкость. В профессиональных системах защиты чаще применяется
частичная переработка кодов. Легче всего модифицировать EXE и
COM-файлы при загрузке в ОЗУ, выбирая куски для переработки случайным
образом, и при этом можно сразу же вносить изменения в исходный файл
программы на магнитном носителе. Как именно? Познакомьтесь с
несколькими способами.
ЗАМЕНА НА ЭКВИВАЛЕНТЫ
Самый простой - периодически заменять одну последовательнось
команд на другую, внешне не похожую, но, в конечном итоге, выполняющую
то же самое действие. Для этого подбираем эквиваленты. Например,
команда MOV AX,BX и последовательность PUSH BX и POP AX - выполняют
одно действие (пересылка содержимого регистра BX в регистр AX),
команда CALL adr заменяется на последовательность PUSH IP+3 и JMP adr.
Примерные варианты взаимозамены для основных команд ассемблера
приведены в таблице 5.1 (естественно, для конкретных программ ее нужно
дополнить и расширить).
В тексте программы организуется участок, где будут храниться
цепочки команд, с указанием адресов эквивалентных им участков. При
очередной работе программа случайным образом меняет местами отдельные
части из собственного тела и "хранилища". В результате после каждого
прохода исполняемый код будет случайным образом изменен до
неузнаваемости, однако функции программы не нарушаются. Единственный
недостаток этого способа - новый вариант исполняемого кода часто не
может быть адекватен предыдущему по скорости работы.
Разумеется, конкретная таблица может иметь несколько
альтернативных вариантов для каждой последовательности. А для
выравнивания их длин можно использовать команду NOP или ее аналоги
(пара PUSH - POP или MOV AX,AX).
Включение в алгоритм элементов случайности делает "внешность"
задачи непредсказуемой. Пример этого способа приведен на прилагаемой
дискете.
ИЗМЕНЕНИЕ КОДИРОВКИ
Более сложный способ - модификация кодов команд с изменением
характера выполняемых операций (рис. 5.1). Делается это так.
Написанный на ассемблере и уже отлаженный модуль транслируется в
объектный код с получением листинга. На листинге, не обращая внимания
на мнемонику, ищем участки с похожими закономерностями изменения
величин кодов команд (вот где пригодится опыт решения математических
задач, типа "найди закономерность", из популярных журналов). Затем
выделяем найденные участки в отдельную подпрограмму и, используя
подмеченную закономерность, составляем алгоритм ее преобразования в
коды первого участка, второго, третьего... Этот алгоритм встраиваем
вместо участков и по завершению преобразования подпрограммы - передаем
ей управление. Как правило, с первой попытки полной аналогии с изъятым
блоком не получается, поэтому нужно поманипулировать командами,
переставить их местами, может быть - добавить лишние (тем не менее не
нарушающими общего алгоритма), что-то заменить эквивалентной
последовательностью.
ПРОХОД "СВОИМ ХОДОМ" ПО ДАННЫМ
Несмотря на кажущуюся простоту, одновременное использование
некоторых байт как операторов и операндов является "высшим пилотажем"
в программировании. Способ пришел от программистов для 8-разрядных
процессоров типа Z80, К580 и др. Дело в том, что у них основные коды
однобайтовых пересылок и букв совпадают, к тому же у компьютеров с МП
Z80 маловато ОЗУ (приходится его экономить). Вот и используют участки
осмысленного текста - как для появляющихся на экране сообщений, так и
для загрузки нужных регистров. Разумеется, некоторые буквы оказываются
лишними при прогоне участка, как кода программы. Но, с другой стороны,
вслед за "сообщением" можно поставить несколько команд, корректирующих
результаты ненужных операций. Пример приведен в распечатке листинга
игры "Jetpac" фирмы "Ultimate" для компьютера "Spectrum-48" на рис.
5.2 (для МП Z80). По ходу космической игры в верхней части экрана
появляются надписи: "1UP" (результат 1 игрока), "HI" (лучший результат
за всю игру) и "2UP" (2 игрок). При анализе текста программы
выяснилось, что эти надписи образуют отдельную подпрограмму,
осуществляющую пересылки некоторого значения из ячейки ОЗУ (адрес
0D055h) в стек и из аккумулятора в эту же ячейку (то есть сложный
обмен значениями между регистром A, стеком и ОЗУ).
Впрочем, то что легко программируется для 8-разрядных