Электронная библиотека
Xakep
Первый вирь - COMом
Xakep, номер #014, стр. 014-058-3
Придумать, конечно, можно еще с десяток методов дойдя до таких извратов, как поиск процедур и свободных участков в файлах-жертвах. А ты пробовал включить комп большим пальцем ноги, удерживая монитор мизинцами? :) Но для первого нерезидентного виря хватит и этого. Я опишу первый метод подробно, но в листинг вируса пойдет второй.
В общем, пора закончить с теорией и приступить к практике. Можно даже считать, что вирус уже написан - осталось его накодить :).
Что, уже пора?
Когда вирус получит управление, его тело - код и данные - будут находиться не в самом начале, а на некотором расстоянии (которое есть ни что иное, как размер жертвы). Это необходимо учитывать, когда вирь обращается к данным и процедурам, вызывая их по JMP/CALL NEAR. Как это сделать? (наложенным платежом перечисляй мне - помогу, расчетный счет в конце телепередачи. :)) Два варианта навскидку - вычислять требуемое смещение к данным еще в процессе заражения и вычислять его на ходу, прямо при запуске виря. Я выбрал второе - оно показалось мне лучше, универсальнее что ли. А что выберешь ты, зависит от твоей фантазии и ловкости рук, конечно:
call $+3 ; команда CALL NEAR занимает три байта,
; поэтому CALL $+3, есть просто вызов следующей
; команды. В стеке появится слово со значением IP
; следующей команды.
pop ax ; осталось только взять его и
sub ax,offset entry virus+3 ; попpавить то, что получилось на IP
; команды CALL, а не POP AX
mov bp,ax ; после этого его можно положить куда-нибудь для
; дальнейшего использования
Обращения к данным и процедурам виря теперь нужно делать только с добавлением BP к их адресам. Тогда все они будут корректно считаны/записаны/вызваны. Т.е. вместо
mov [data],something
пишется
mov [bp+data],something
и все адреса рассчитывать соответственно. Есть один момент, о котором я хотел бы пробулькать пивом, бродящим со вчерашнего дня в моем желудке. Чтобы выяснить адрес, не нужно постоянно добавлять BP к нормальному смещению вот так:
mov dx,offset data
add dx,bp
На это уходит уйма байт, которые пригодятся для другого. Гораздо лучше воспользоваться старым добрым LEA (load effective address), который советовал использовать в своей книжке добрый дядька Питер Нортон:
lea dx,[bp+data]
Раз, два, три, четыре, пять - я иду искать
Вирус должен сохранить состояние среды, в которую его запихали не без помощи INT 21H. Для поиска я воспользуюсь FindFirst и FindNext из INT 21H. Они используют DTA, которая дефолтом располагается с 128 байта в PSP. Там же, кстати, лежат параметры, которые были переданы программе в командной строке. И как только я вызову FindFirst или FindNext c явным намерением похулиганить, все эти параметры просто исчезнут во мраке небытия. Именно поэтому DTA сохраняется. Все-таки не надо лишний раз высовывать голову из окопа, обнаруживая свое (вируса) присутствие в файле. Могут ведь и заметить. Итак, DTA нужно сохранить. Для этого нужно иметь где-то буфер в 128 байт. Но не стоит делать так: