Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Программирование

Добавлен: 16.02.2019

Просмотров: 29232

Скачиваний: 1689

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

 

 

Глава 17 

 

Заражение файлов вирусом 

 

17.1. Определение текущего смещения 
выполняемого кода 

Как уже упоминалось в прошлых главах, наш вирус теряется в адресах, если он 

дописывается после кода заражаемого файла. Чтобы избежать этого, мы переноси-
ли код вируса в область 7-й видеостраницы, в которой он и выполнялся. Далее при-
веден  один  из  вариантов  определения  текущего  смещения  выполняемого  кода. 
Причем этот вариант работает в любом случае, независимо от того, переместил ли 
программист  код  собственной  программы  куда-либо  по  другому  смещению  или 
нет. Помните, когда мы пытались записывать вирус в хвост файла, мы акцентиро-
вали ваше внимание на том, что команды вида 

mov  dx,offset  Message

 будут вы-

глядеть в отладчике как 

mov dx,400h

. При перемещении вируса в хвост "програм-

мы-жертвы" мы, тем самым, перемещаем строку 

Message

. В итоге получается, что 

по смещению 

400h

 будет не наша строка, а что-то другое. 

Получить же значение регистра 

ip

 обычной командой 

mov

 не удается. Поэтому 

нам следует прибегнуть к более хитрым способам. Например, к способу из листин-
га 17.1. 

Листинг 17.1. Получение значения регистра ip 

... 

;Якобы переходим на процедуру, при этом в стеке сохраняется адрес следующей 

;за командой call инструкции (т. е. pop ax). 

call Label_1 

Label_1: 

;И сразу же достаем этот адрес из стека. 

pop ax 

;Теперь в ax находится текущий адрес (смещение). 

... 


background image

Глава 17. Заражение файлов вирусом 

175 

Почему команда 

call  Label_1

  всегда  заносит  в  стек  текущее  смещение,  выяс-

нить можно в отладчике (рис. 17.1, 17.2 и 17.3). Тем не менее, мы позже рассмотрим 
различие 

mov  dx,offset  Message

 и 

call  Label_1

. Мы выясним, почему в первом 

случае  в 

dx

  заносится  константа  (постоянное  число),  а  во  втором  случае —  "пла-

вающее". Так или иначе, считайте, что в приведенном выше примере мы получаем 
всегда текущее смещение метки 

Label_1

.  

По этому принципу мы теперь получим текущее смещение в нашем вирусе, тем 

самым,  усложнив  задачу  и — как следствие — усовершенствовав сам код вируса. 
Но об этом в следующем разделе. 

 

Рис. 17.1. Перед вызовом лжеподпрограммы 

 

Рис. 17.2. В стеке — смещение следующей команды 


background image

 

Часть III. Файловая оболочка, вирус, резидент 

176 

17.2. Вирус 

Итак, открываем файл virus17.asm. Сразу же за меткой 

Init

  мы  получаем  сме-

щение,  по  которому  расположена  метка 

Get_ip

  (см. разд. 17.1).  Из  этого  адреса 

нужно вычесть смещение метки 

Get_ip

Допустим, мы запускаем вирус первый раз. То есть все смещения содержат вер-

ные значения. Также допустим, что метка 

Get_ip

 находится по адресу 

0203h

 (лис-

тинг 17.2). 

Листинг 17.2. Получаем текущее смещение в коде 

... 
(1) [1234:0200h]       call Get_ip 
(2) [1234:0203h] Get_ip: 
(3) [1234:0203h]       pop ax 
(4) [1234:0204h]       sub ax,offset Get_ip 
... 

На рис. 17.3 продемонстрировано, как приведенный выше фрагмент кода выгля-

дит в отладчике в случае, если вирус запускается первый раз.  

 

Рис. 17.3. В ax — текущее смещение 

Строка (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 


background image

Глава 17. Заражение файлов вирусом 

177 

Теперь представим, что код вируса был перенесен самой программой в процессе 

заражения в хвост некоторого файла, размером 1000h байт (обратите внимание на 
смещения  в  скобках).  Тот  же  самый  код  будет  располагаться  по  такому  адресу 
(листинг 17.3).  

Листинг 17.3. Код перемещен в хвост "файла-жертвы" 

... 
(1) [1234:1200h]       call Get_ip 
(2) [1234:1203h] Get_ip: 
(3) [1234:1203h]       pop ax 
(4) [1234:1204h]       sub ax,offset Get_ip 
... 

Тогда строка (1) заносит в стек число 

1203h

Pop ax

 достает его из стека. Затем 

выполняется следующее действие: 

sub ax,203h    ;sub ax,offset Get_ip 

 ax=1203h-203h=1000h 

Теперь в 

ax

 находится размер "файла-жертвы", т. е. 

1000h

. Получили то, что нам 

и нужно!  

Вполне возможно, что принцип не до конца понятен. В таком случае особо не 

переживайте,  т. к.  в  главе 20,  когда  вирус  будет  полностью  работоспособным,  вы 
увидите на практике, как именно подставляются необходимые нам значения. Сей-
час просто можете наблюдать за тем, как мы "играем" с адресами. 

Итак, теперь в 

ax

  размер  "файла-жертвы".  Чтобы  получить  реальное  смещение 

того  или  иного  адреса,  нам  достаточно  прибавить  к  уже  имеющемуся  в  регистре 
"ненормальному"  смещению  то,  что  находится  в 

ax

,  т. е.  длину  "файла-жертвы". 

Вот что мы делаем в вирусе (листинг 17.4).  

Листинг 17.4. Вычисление реального смещения 

... 
;Скопируем наш вирус в область 7-й видеостраницы, т. е. сделаем то, 
;что уже делали в предыдущей главе, только "правильней". 
push 0BF00h 
pop es 
;es — сегмент, куда будем перемещать код вируса, 
mov di,offset Open_file 
;di — смещение (адрес самой первой процедуры (см. файл-приложение)) 
 
mov si,di 
;si должен содержать РЕАЛЬНЫЙ адрес (смещение), т. к. мы пока еще 
;в сегменте "файла-жертвы"... 

add si,ax 


background image

 

Часть III. Файловая оболочка, вирус, резидент 

178 

mov cx,offset Finish-100h 
;Т. е. cx = длина нашего вируса в байтах 

 

rep movsb     ;Теперь в памяти две копии нашего вируса 

... 

Обратите внимание, как мы получаем адрес первой процедуры в памяти. Понят-

но, что после директивы 

offset

 не обязательно должен идти адрес метки или стро-

ки, например, для вывода с помощью функции 

09h

. А так как метки и директивы 

(инструкции программы-ассемблера) не занимают памяти, то в 

di

 мы занесем адрес 

(смещение)  первого  байта  процедуры 

Open_file

,  т. е. 

mov  ax,3D02h

  (но  не  саму 

команду 

mov

, а ее смещение).  

Копию  кода  в  7-й  видеостранице  мы  сделали.  Теперь  можно  и  переходить 

("прыгать")  на  нее.  Но  в  данном  случае  мы  не  будем  использовать  оператор 

jmp

Давайте чуть-чуть усложним задачу. Прежде чем разбирать, вспомним об операто-
рах возврата из подпрограмм и прерываний: 

ret

retf

 и 

iret

 (листинг 17.5). 

Листинг 17.5. Переход по другому адресу с помощью retf 

... 

(1)    mov bx,offset Lab_return 

(2)    add bx,ax 

(3)    push cs 

(4)    push bx 

(5)    retf 

 

(6) Lab_jmp: 

... 

На рис. 17.4 и 17.5 показано, что процессор передает управление копии кода ви-

руса совсем в другой сегмент (следите за регистром 

cs

).  

Теперь,  если  вы  разобрались  с 

retf

,  то  понять  принцип  работы  приведенных 

выше  строк  труда  не  составит.  Команда 

retf

  достает  из  стека  2  слова  (4 байта): 

смещение  и  сегмент  для  возврата  в  то  место,  откуда  дальняя  процедура  вызыва-
лась. Мы же имитируем вызов процедуры. Поверьте, процессору все равно, откуда 
вызывалась процедура и куда нужно возвращаться. Более того, он вообще не сле-
дит  за  тем,  вызывалась  ли  процедура.  Однако  при  пользовании  такими  методами 
нужно  быть  предельно  внимательным,  очень  тщательно  все  подготовить  и  обяза-
тельно проверить несколько раз.  

При вызове дальней процедуры в стек заносится сперва смещение, а затем сег-

мент для возврата. Делаем это в строках (1)—(4). Учитывая, что в компьютере дан-
ные хранятся наоборот, но стек растет снизу вверх, то в памяти сегмент и смеще-
ние  будут  располагаться  именно  так,  как  нам  нужно.  В строках  (1),  (2)  мы