Вирус на ассемблере Вирус. Итак, открываем файл Virus17.asm. Сразу же за меткой Init мы получаем смещение, по которому расположена метка Get_IP (получить IP - Instruction Pointer - указатель инструкций). Из этого адреса нужно вычесть смещение метки Get_IP. Вот, что получаем: Допустим, мы запускаем вирус первый раз. Т.е. все адреса в порядке. Также допустим, что Get_IP находится по адресу 0203h: (1) [1234:0200h] call Get_IP Строка (1) заносит в стек число 0203h, а (3) - достает со стека 0203h. Т.о. мы оставили стек выровненным и получили текущий адрес (смещение). Сегмент, как вы знаете, можно получить так: mov ax,cs, чего не скажешь о IP. Загрузка и чтение напрямую числа в/из IP не допускается! Поэтому нам нужно действовать хитрее, так, как указано выше в примере. Далее получаем так: в строке (4) вычитаем из 203h смещение метки Get_IP в памяти. В отладчике строка (4) будет всегда выглядеть так: sub ax,0203h ;sub ax,offset Get_IP ---> AX=203h-203h=0 Теперь представим, что мы находимся в хвосте какого-то файла, размером 1000h байт (смотрите на смещения в скобках). Тот же самый код будет располагаться по такому адресу: (1) [1234:1200h] call Get_IP Что мы получаем? Строка (1) заносит в стек число 1203h. Pop ax достает его со стека. Затем выполняется следующее действие: sub ax,203h ;sub ax,offset Get_IP ---> AX=1203h-203h=1000h Теперь в AX размер "файла-жертвы", т.е. 1000h! Получили то, что хотели! Некоторые, возможно, скажут: "Все равно ничего не понял! Зачем мы это делаем?" Ничего страшного. Когда мы в следующем выпуске про вирус запишемся в хвост какого-нибудь файла, вы увидите, что к чему. Сейчас просто смотрите, как мы "играем" с адресами... Итак, теперь в AX размер "файла-жертвы". Чтобы получить реальное смещение того или иного адреса, нам достаточно прибавить к уже имеющемуся в регистре "ненормальному" смещению то, что находится в AX, т.е. длину "файла-жертвы". Вот, что мы делаем в вирусе: ;Скопируем наш вирус в область 7-ой видеостраницы, т.е. сделаем то, что
уже делали в предыдущем выпуске, только правильней. Обратите внимание, как мы получаем адрес первой процедуры в памяти. Понятно, что после offset не обязательно должен идти адрес метки или строки, например, для вывода с помощью функции 09h. А так как метки и директивы (инструкции программы-ассемблера) не занимают памяти, то в DI мы занесем адрес (смещение) первого байта процедуры Open_file, т.е. mov ax,3D02h (не сам mov, а его смещение!). Идем дальше. Копию в 7-ой видеостранице мы сделали. Теперь можно и переходить ("прыгать") на нее. Но теперь мы не будем использовать jmp. Давайте чуть-чуть "извратимся". Зато (как их?) "ламеры" могут "обломаться". Но мы-то уже почти "профи"! Прежде, чем разбирать, вспомним про ret, retf и iret... Вспомнили? Поехали! (1) mov bx,offset Lab_return Теперь, если вы разобрались с retf, то труда понять принцип работы приведенных выше строк труда не составит. RETF достает со стека 2 слова (4 байта): смещение и сегмент для возврата в то место, откуда дальняя процедура вызывалась. Мы же имитируем вызов процедуры. Поверьте, процессору все равно откуда вызывалась процедура и куда возвращаться нужно. Более того, ему все равно, а вызывалась ли процедура вообще или нет. Но нам-то, программистам, не все равно! Процессор, если ему подсунули что-то не то или забыли сделать что-то, просто зависнет и все! А вот нам придется воспользоваться одной самой надежной кнопкой - RESET. Поэтому нужно быть предельно внимательным. При вызове дальней процедуры в стек кладется сперва смещение, а затем - сегмент для возврата. Знаете, почему... Делаем это в строках (1) - (4). Но стоп! Почему мы вначале заносим сегмент (CS), а затем смещение (BX)? Ну что, будем думать или сразу сказать?.. Стек-то как у нас растет? Снизу вверх. Что получится, думаю, вы поняли. Люди вы уже самостоятельные и грамотные... В строках (1) - (2) мы получаем смещение для возврата. К этому смещению и прибавляем размер "файла-жертвы", который находится в AX. Теперь в стеке (а стек - это, как мы помним, специально отведенная память или просто память) у нас смещение и сегмент метки Lab_jmp (точнее первого оператора, который находится под ней). Что делает строка (5)? Ну вот, видите, как стало мне просто объяснять. Достаточно намекнуть - и все! Вопрос: а как нам вернуться назад, в сегмент "файла-жертвы"? Найдете сами это в файле-примере? Конечно! Не сомневаюсь! Все элементарно! Что еще нового мы видим? Байты "файла-жертвы", которые нужно восстанавливать: First_bytes db 90h, 90h, 90h, 90h, 0CDh, 20h Это - знакомые машинные коды: 90h - NOP; 0CDh - INT; 20h - 20h. Получаем программу: nop В эту переменную (в этот массив) будем заносить первые шесть байт "программы-жертвы", вместо которых запишем jmp на начало нашего вируса. Более того, эти байты будут записаны вместе с телом нашего вируса на диск, после "файла-жертвы". Они нужны для того, чтобы в последствии, когда вирус отработает, восстановить их в памяти по адресу 100h и "прыгнуть" на 100h. Программа даже и не заподозрит, что кто-то перед тем, как она получила управление, уже что-то делал! Изначально мы заполняем массив командами nop, а после них - int 20h. Это нужно для того, чтобы при первом запуске вируса корректно завершиться. Первый запуск вируса - это когда мы только-только его сассемблировали (получили com-файл) и запустили полученную программу (в нашем случае - это будет VIRUS17.COM). Она отработает, заразит какой-нибудь файл (если найдет), восстановит первые шесть байт и передаст управление на метку 100h, полагая, что восстановила байты "файла-жертвы" и передала ему управление. Но на деле мы просто выйдем в DOS. А если мы не восстановим эти байты, но перейдем на метку 100h? Тогда вирус будет работать бесконечно. Если же мы заразили какой-то файл и сохранили в переменной First_bytes первые байты зараженного файла, то мы просто передадим ей управление. Вот и все! Если вы заглянули в файл-приложение, то заметили там не строку First_bytes db 90h, 90h, 90h, 90h, 0CDh, 20h а First_bytes db 4 dup (90h), 0CDh, 20h Директива DUP - DUPlicate дублирует число, которое находится в скобка столько раз, сколько указывает стоящая перед ней цифра. Сравните две строки. Все станет понятно. Только имейте в виду, что этот массив занимает память на диске. Проще говоря, он увеличивает нашу программу на 6 байт. Пример: Array db 1500 dup (0) увеличит нашу программу на 1500 байт. Обратите еще внимание, как мы переходим на адрес 100h (передаем управление "файлу-жертве"): mov ax,100h Видите, как можно делать... |
|
Из книги Калашникова. |