ZF

              КАК НАПИСАТЬ АНТИВИРУС ДЛЯ WM.CAP
                           by DrMAD

    Введение
    1. Немного о WordBasic-е
    2. Основные принципы устройства и работы макровирусов
    2.1. Как макровирусы распространяются
    2.2. Как макровирусы получают управление
    2.3. Как макровирусы заражают MS Word
    2.4. Как макровирусы заражают другие документы
    2.5. Типовая структура макровируса
    2.6. Некоторые малораспространенные алгоритмы заражения
    2.7. О проявлениях макровирусов
    3. Написание антивируса
    3.1. Еще раз о стуктуре DOC-файла
    3.2. Принципы лечения
    3.3. Рекомендации по выбору сигнатур
    3.4. Тексты процедур infected() и cure()
    Заключение

                           Введение

    Милостивые государи!  В прошлом  выпуске  "Земского  Фершала"  была
опубликована  статья,  посвященная  изучению структуры WinWord-файлов и
ручному удалению макровирусов ("Немного криптологии" (с) DrMAD). Теперь
перед  Вами  ее  продолжение,  посвященное  написанию  антивирусов  для
макрозаразы. Вообще, рекомендую сначала прочитать 1-ю часть.

    Следует отметить,  что  и прошлая статья,  и нынешняя - всего -лишь
сокращенные варианты одной из глав фундаментального труда  "Как  Пымать
Выря  За  Хвост".  В  частности,  тот  текст  содержит комментированные
листинги некоторых вирусов,  краткое введение в язык WordBasic, примеры
дампов   зараженных  документов,  более  подробное  описание  структуры
DOC-файлов,  сервисные утилиты и пр.  Полностью с данной работой  можно
познакомиться на антивирусном сайте А.Гостева:

                     http://virus.komi.ru

    Кроме того,  в ближайшее  время  будет  опубликована  online-версия
труда. Следите за рекламой! J

                   1. Немного о WordBasic-е

    Для понимания  принципов  организации  макровирусов и борьбы с ними
совершенно необходимо  иметь  хотя  бы  поверхностное  представление  о
языках WordBasic и VBA.  Вернее,  в первую очередь о первом из них, ибо
MS WinWord 6.0/7.0 все еще очень широко распространены.

    Язык WordBasic позволяет  создавать  так  называемые  макрокоманды,
которые  должны  (по идее) избавить пользователя от повторения рутинных
операций при многократной нетривиальной обработке текста.

    Программы на  WordBasic-е  хранятся  в  так   называемых   шаблонах
(template)  -  документах  особого  вида.  Главным для MS Word является
шаблон NORMAL.DOТ.  Все макрокоманды по умолчанию загружаются из него и
сохраняются в нем.  Если файл с этим шаблоном удалить,  он будет создан
автоматически при запуске MS Word.

    Новую макрокоманду можно создать так:  после запуска MS Word в меню
Сервис выбрвть альтернативу Макрокоманда.  Появится форма ввода. В поле
Имя надо набрать имя макрокоманды,  в  поле  Описание  можно  поместить
справочный  комментарий.  Затем  следует  нажать  на кнопку Создать,  и
появится окно ввода/редактирования макросов.  Готовый  макрос  надо  не
забыть Записать.

    Старую макрокоманду   посмотреть/отредактировать   можно,   если  в
альтернативе Макрокоманда выбрать имя желаемого  макроса  из  списка  и
нажать кнопку Правка.

    В этом  месте  может  прилететь  розовая птица Обломинго J,  если
макрос,  который  вы  желаете   посмотреть/отредактировать   зашифрован
(ExecuteOnly).  В  этом  случае  кнопка Правка будет просто недоступна.
Например,   изначально   зашифрована   библиотека   полезных   макросов
MSWORD.DOT.   Если   Вы   хотите   изучить   возможности   WordBasic  в
совершенстве,  я  рекомендую  Вам  заняться  изучением   текстов   этих
макросов.  Зашифрованы также некоторые макровирусы (например, Cap). Как
увидеть эти макросы?  Ну-у,  это вы должны знать, если прочитали статью
"Немного криптологии". Если нет, немедленно читайте! J

    Особенно важна для нас команда MacroCopy. Опишем ее подробно:

    MacroCopy [Шаблон1:]Макро1$,
              [Шаблон2:]Макро2$
              [,ПризнакШифрации]

    Выполняет копирование  макроса  Макро1$ из одного шаблона в другой,
присваивая ему имя Макро2$.  Если  ПризнакШифрации  присутствует  и  он
ненулевой,    то   скопированный   макрос   не   будет   доступен   для
редактирования.  Именно  на  работе  этой  команды  основано   свойство
саморазмножения макровирусов.

    2. Основные принципы устройства и работы макровирусов

            2.1. Как макровирусы распространяются

    Макровирусы распространяются  вместе  с  переносимыми  с  машины на
машину документами MS Word.  Внутри  зараженного  документа  содержатся
вирусные  макросы.  При  этом документ имеет формат шаблона (template),
что не исключает нахождение внутри него также  содержательного  текста,
изображений,  формул  и  т.п.  Такой  документ с точки зрения обработки
текста ничем не отличается от "нормального".  По умолчанию принято, что
файлы  "обычных"  документов MS Word имеют расширения DOC,  а шаблоны -
DOT.  На практике же  MS  Word  различает  их  по  внутреннему  формату
автоматически, не извещая об этом пользователя.

    "Нормальный" документ  превращается в шаблон в момент копирования в
него вирусных макросов,  т.е.  в момент исполнения  команды  MacroCopy,
если  установлен  в  определенное  значение  флажок  способа сохранения
FileSaveAs.Format.

    Важным отличием  шаблонов  от  "нормальных"   документов   является
невозможность сохранения их при помощи SaveFileAs.

          2.2. Как макровирусы получают управление

    В MS  Word существуют так называемые "автоматические" макросы.  Это
макросы,  автоматически  выполняющиеся  при  определенных  условиях   и
предназначенные для переопределения их пользователем.

    К таким   макросам   относятся,   например,   AutoOpen  (получающий
управление при стандартном открытии документа) и  AutoClose (получающий
управление при закрытии документа). По умолчанию эти макросы "пустые" и
не выполняют никаких действий.

    Если открываемый  документ  (вернее,  шаблон)  содержит   один   из
автоматических  макросов,  то  они запустятся,  а вместе с ними получит
управление и макровирус.

    Запретить запуск  автоматических  макросов  можно,  установив  в  1
системную переменную DisableAutoMacros.

            2.3. Как макровирусы заражают MS Word

    Получив управление  (при  помощи одного из автоматических макросов)
из зараженного документа,  макровирус обычно предпринимает действия  по
"фиксированию"  себя  в системе.  Для этого он переносит свои макросы в
"главный" шаблон NORMAL.DOT.  Макросы из  этого  шаблона  автоматически
загружаются  и  активируются при запуске MS Word.  Таким образом,  если
вирус переносит  свои  макросы  в  "главный"  шаблон,  то  он  получает
возможность постоянного находиться в системе.

    "Вылечить" NORMAL.DOT  можно  просто  -  удалив его с диска.  После
этого автоматически создастся новый NORMAL.DOT - читсый и  без вирусных
макросов.   Единственный   недостаток   -  при  этом  пропадают  и  все
"полезные" макросы,  которые в нем  могли  содержаться.  Но,  например,
широко  известный  макровирус  Cap  перед  помещением  своих макросов в
NORMAL.DOT удаляет все его "полезные" макросы самостоятельно.

    Естественно, удалять  NORMAL.DOT  можно  и   имеет   смысл   только
"выключив" MS Word.

       2.4. Как макровирусы заражают другие документы

    Часть действий   выполняется   в  MS  Word  посредством  выполнения
стандартных макросов. Так, например, если для открытия нового документа
пользователь   выбирает  пункт  меню  Открыть/Open,  то  активизируется
стандартный макрос FileOpen.

    Если макровирус переопределяет один или несколько таких стандартных
макросов,   то  он  иммет  возмлжность  получить  управление  в  момент
выполнения соотвествующих операций.  Естественно,  обычно макровирусами
переопределяются  макросы,  соответствующие файловым операциям MS Word:
FileOpen, FileClose, FilePrint и т.п.

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

             2.5. Типовая структура макровируса

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

    - получающие управление в  результате  исполнения  "автоматических"
макросов и копирующие вирусные макросы из шаблона в NORMAL.DOT;
    - получающие  управление  в  результате  исполнения   "стандартных"
макросов  и  копирующие  вирусные  макросы  из  NORMAL.DOT  в  документ
(конвертируя его в формат шаблона).
    В некотрых  вирусах  эти  макросы  совмещены  в  один.  В некоторых
вирусах присутствуют другие  макросы,  предназначенные  для  выполнения
действий, отличающихся от операций размножения.

   2.6. Некоторые малораспространенные алгоритмы заражения

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

    ToolsCustomizeKeyboard .KeyCode=32, .Category=2,
                           .Name="Gangsterz", .Add, .Context=0

    приведет к  тому,  что  при нажатии клавиши "пробел" будет выполнен
макрос с именем Gangsterz.

               2.7. О проявлениях макровирусов

    Возможности языка  WordBasic  весьма  велики,  соотвественно  этому
проявления   макровирусов   разнообразны  -  это  и  файловые  операции
(открытие/закрытие/чтение/запись/переименование/удаление),    различные
"шутки"   с   редактируемым  текстом,  выдача  на  экран  разнообразных
сообщений и пр.
    Одним из   примечательных  проявлений  макровирусов  можно  считать
изменение стандартной структуры меню MS Word.  Например,  вирус Cap при
получении  управления  удаляет  из  структуры  меню альтернативу Макро,
обеспечивая  этим   самым   невозможность   (относительную)   визуально
обнаружить свое наличие в файле NORMAL. DOT.

                   3. Написание антивируса

    Как макровирус  вылечить  вручную  -  про  это Вы уже знаете,  если
прочитали статью  "Немного  криптологии".  Теперь  займемся  написанием
своего антивируса.

              3.1. Еще раз о стуктуре DOC-файла

    DOC-файл имеет весьма сложную структуру. Он представляет собой OLE2
-  объект,  организованный  по  принципу  отдельной  файловой  системы:
содержит  каталог  своих  подобъектов,  таблицы размещения подобъектов,
пустые  участки  и  пр.  Документ  MS  Word  является  одним  из  таких
подобъектов. Максимально корректное извлечение документа MS Word из DOC
-файла реализуется при помощи специализированных библиотек  MS  Windows
API. Но есть способ лучше (т.е. проще).
    Известно, что:
    - DOC-файл   имеет   в  начале  сигнатуру  (признак  OLE2-объекта),
выполняющую  примерно  такую  же  роль,  что  и  байты  'MZ'  в  начале
EXE-программ;
    - документ  MS  Word  представляет   собой   непрерывный   фрагмент
DOC-файла, размещающийся в файле по смещению, кратному 0х10;
    - документ MS Word  содержит  заголовок,  содержащий  описание  его
компонентов:

    Смещение  Длина Содержимое

    00h         4   Признак Word-документа
    04h         4   Номер версии MS Word
    ...
    0Ah         4   Статус Word-документа
    ...
    118h        4   Позиция макрозаголовка
    11Ah        4   Длина макрозаголовка

    - если документ MS Word содержит макросы,  то по адресу 0х118 в его
заголовке содержится адрес макрозаголовка,  т.е.  структуры, содержащей
описания макросов:

    Смещение  Длина Содержимое

    00h       2     Признак макрозаголовка
    02h       2     Количество макросов

    - если количество макросов ненулевое,  то сразу за  макрозаголовком
последовательно размещаются описатели макросов:

    Смещение Длина Содержимое

    00h       1    Версия макроязыка
    01h       1    Ключ шифрации макроса
    ...
    0Сh       4    Длина макроса
    ...
    14h       4    Позиция макроса

    Приведем также необходимую справочную информацию:

    Признак OLE2-объекта (длиной 8 байт):  0D0h 0CFh  011h 0Eh
0A1h 0B1h 01Ah 0E1h.

    Возможные значения признака документа MS Word: 65A5DCh, 68
A5DCh, 68A697h, 68A699h, 0C1A5ECh...

    Возможные значения  номера  версии  MS  Word:   0407С02Dh,
0407C035h, 0407C03Dh,    0409C033h,    0409C03Dh,   0409C03Fh,
0409C041h, 0409C047h, 0409E057h, 0409E063h, 04070049h....

    Значения младшего бита поля статуса: 0 - обычный документ,
1 - шаблон.

    Признак макрозаголовка: 10FFh.

    Типовая версия макроязыка для WORD 6.0: 055h.

    Шифрация тела   макроса   производится   по  алгоритму  побайтового
"исключающего ИЛИ" (XOR).

                    3.2. Принципы лечения

    Для лечения  зараженного  DOC-файла  обычно   достаточно   сбросить
признак   "шаблона".   Удалять  собственно  код  макроса  при  этом  не
обязательно,  но  желательно,  ибо  (согласно  замечанию  Д.  Грязнова)
WinWord  97  не  обращает  внимания на этот битик и все равно загружает
макросы.
    Для лечения зараженного шаблона, например, NORMAL.DOT, необходимо в
макрозаголовке скорректировать поле "Количество макросов"  и  исправить
число   и   содержимое  описателей  макросов,  что  не  должно  вызвать
затруднений при условии знания структур данных.

            3.3. Рекомендации по выбору сигнатур.

    Термин "сигнатура макровируса" имеет в точности такое  же значение,
что  и в случае с COM- и EXE-вирусами.  Более того,  пока не существует
полностью полиморфных макровирусов ( "полиморфность"  часто заключается
в   вариации  порядком  размещения  и  числом  макросов),  а  значит  -
макровирус всегда может быть определен и  однозначно  детектирован  при
помощи аппарата сигнатур.
    Единственное отличие обусловлено  тем,  что  поскольку  макровирусы
пишутся   на   языке   высокого   уровня,  то  одному  оператору  может
соответствовать довольно длинная байтовая  последовательность. Учитывая
тот факт, что некоторые операторы и группы операторов являются типовыми
как для вирусов,  так и для "нормальных" макросов,  приходим к  выводу,
что  для  надежного  детектирования  длина  сигнатуры должна составлять
минимум несколько десятков байт.
    Кроме того,  принцип  сигнатур  можно использовать для предсказания
наличия в  DOC-файле  неизвестного  (нового)  вируса.  Автору  пока  не
известен полный набор компилированных кодов и алгоритм декомпиляции, но
с большой долей уверенности можно утверждать,  что  следующие  байты  в
теле макроса:

                       64h 67h С2h 80h

    являются 16-ричным кодом для команды MacroCopy.

            3.4. Тексты процедур infected() и cure()

    Надеюсь, обход  дерева  каталогов  и сканирование DOC/DOT-файлов Вы
можете организовать и сами.  J Вашему вниманию предлагаются  исходные
тексты двух Си-шных функций:

    int infected( char *filename) - анализирует документ на
                                    зараженность и возвращает
                                    соответствующий признак;
    int cure( char *filename)     - лечит документ.


Естественно, использовать  их в Вашей программе нужно примерно
так:

       if (infected( "NORMAL.DOT")) cure("NORMAL.DOT");

    Ну а в качестве мишени избран горячо "любимый" массами ви-
рус WM.Cap. Итак:

/***************************************************/
/* Процедуры обнаружения и лечения вируса CAP      */
/* (c) Климентьев К. Самара, 1998                  */
/***************************************************/

/* Длина сигнатуры */
#define SIGLEN 10

/* Преобразование 4-х последовательных байт
в длинное целое */
unsigned long mk_long(unsigned char *c)
 {
  return *(unsigned long *)c;
}

/* Преобразование 2-х последовательных байт в целое */
unsigned int mk_int(unsigned char *c)
 {
  return *(unsigned int *)c;
}

/******************************************************************/
/*       Процедура поиска в DOC-файле вируса MW.Cap               */
/******************************************************************/
int infected( char *fn )
 {
  int f;
  unsigned q;
  size_t fl;                 /* Длина файла */
  unsigned char *fbuf, *fb;  /* Буфер под проверяемый файл и его копия */
  long SHIFT;                /* Смещение Word-документа в файле */
  long MHPOS;                /* Позиция макрозаголовка */
  unsigned NMACR;            /* Количество макросов */
  unsigned char XORMASK;     /* Ключ шифрации макроса */
  unsigned long MACRLEN;     /* Длина макроса */
  unsigned long MACRPOS;     /* Позиция макроса */
  unsigned long MHBASE;      /* Абсолютная позиция макрозаголовка */
  long i,j,k,jj;

  /* Открываем файл */
  f = _open( fn, O_RDONLY );

  /* Определяем его длину */
  fl = (size_t) lseek( f, 0, SEEK_END );

  /* Пытаемся распределить память */
  fb = fbuf = (unsigned char *) malloc( (size_t)  fl );
  if (fbuf == NULL) { printf(" - файл слишком велик!\n"); return GOOD; }

  /* Возвращаемся на начало файла */
  lseek( f, 0, SEEK_SET );

  /* Считываем файл в буфер */
  q = _read( f, fbuf, 0xffff );
  while (q==0xffff)
   {
    fbuf+=0xffff;
    q = _read( f, fbuf, 0xffff);
   }

  /* Закрываем файл */
  _close(f);

  i=0;
  /* Проверяем на OLE2 объект */
  if ((fb[ i ]!=0xD0) ||
      (fb[i+1]!=0xCF) ||
      (fb[i+2]!=0x11) ||
      (fb[i+3]!=0xE0) ||
      (fb[i+4]!=0xA1) ||
      (fb[i+5]!=0xB1) ||
      (fb[i+6]!=0x1A) ||
      (fb[i+7]!=0xE1))
        {printf(" - это не OLE2-объект!\n");free(fb); return GOOD; }

  /* Ищем всевозможные заголовки Word-документа */
  for (i=0; i<(fl-16); i+=16)

    if (((fb[i]==0xDC)&&(fb[i+1]==0xA5)) ||
        ((fb[i]==0x97)&&(fb[i+1]==0xA6)) ||
        ((fb[i]==0x99)&&(fb[i+1]==0xA6)) ||
        ((fb[i]==0xEC)&&(fb[i+1]==0xA5)))

         {

          SHIFT = i; /* Устанавливаем базовое смещение */
                     /*   потенциального начала        */
                     /*   Word-документа               */

          printf("\nБаза: 0x%lx", SHIFT );

          if (!(fb[SHIFT+0xA]&0x1)) /* Проверяем младший бит */
              continue;             /* поля типа документа.  */
                                    /* Если он 0, то это не  */
                                    /* template и можно      */
                                    /* отваливать            */

          MHPOS = mk_long(&fb[SHIFT+0x118]);    /* Интерпретируем
                                                   первые 4 байта по
                                                   адресу 118h как
                                                   смещение макро-
                                                   заголовка */

          MHBASE = SHIFT+MHPOS; /* Абсолютная позиция макрозаголовка */

          printf("\nПозиция макрозаголовка: 0x%lx", MHBASE);

          if ((fb[MHBASE  ]!=0xFF) || /* Присутствует ли */
              (fb[MHBASE+1]!=0x01))   /* корректный макрозаголовок? */
              continue;

          NMACR =  mk_int(&fb[MHBASE+2]); /* Количество
                                             макросов */

          printf("\nВ документе %u макросов", NMACR);

          /* Цикл по макросам */
          for (j=0;j<NMACR;j++)
           {

	    jj = j*24; /* Смещение описателя j-го макроса */

            XORMASK =      /* Ключ шифрации */
		     fb[MHBASE+jj+5 ];

	    MACRLEN =      /* Длина макроса */
		     mk_long(&(fb[MHBASE+(j*24)+16]));

	    MACRPOS =      /* Позиция макроса */
		     mk_long(&(fb[MHBASE+(j*24)+24]));

	    if (MACRLEN<SIGLEN) /* А не коротковат ли макрос? */
                             continue;

            if (XORMASK)  /* Если макрос зашифрован - расксорим */
              for (k=0;k<MACRLEN;k++)
               fb[SHIFT+MACRPOS+k] ^= XORMASK;

              for (k=0;k<(MACRLEN-SIGLEN);k++)  /* Ищем сигнатуру */
               if((fb[SHIFT+MACRPOS+k]   == 'C') &&
                  (fb[SHIFT+MACRPOS+k+1] == '.') &&
                  (fb[SHIFT+MACRPOS+k+2] == 'A') &&
                  (fb[SHIFT+MACRPOS+k+3] == '.') &&
                  (fb[SHIFT+MACRPOS+k+4] == 'P') &&
                  (fb[SHIFT+MACRPOS+k+5] == ':') &&
                  (fb[SHIFT+MACRPOS+k+6] == ' ') &&
                  (fb[SHIFT+MACRPOS+k+7] == 'U') &&
                  (fb[SHIFT+MACRPOS+k+8] == 'n') &&
                  (fb[SHIFT+MACRPOS+k+9] == ' '))
                     { puts("- болен и...");
                       free(fb);
                       return (BAD); } /* Засыпался, сукин сын! */
            }
  }

  /* Освобождаем память */
  free(fb);

  puts(" - OK!");
  return GOOD;  /* Годен к в/службе */

}

/****************************************************************/
/*  Процедура лечения в DOC-файле вируса WM.Cap                 */
/****************************************************************/
cure( char *fn )
 {
  int f;
  unsigned q;
  size_t fl;                 /* Длина файла */
  unsigned char *fbuf, *fb;  /* Буфер под проверяемый файл и его копия */
  long SHIFT;                /* Смещение Word-документа в файле */
  long MHPOS;                /* Позиция макрозаголовка */
  unsigned NMACR;            /* Количество макросов */
  unsigned long MACRLEN;     /* Длина макроса */
  unsigned long MACRPOS;     /* Позиция макроса */
  unsigned long MHBASE;      /* Абсолютная позиция макрозаголовка */
  long i,j,k;

  /* Открываем файл */
  f = _open( fn, O_RDWR );

  /* Определяем его длину */
  fl = (size_t) lseek( f, 0, SEEK_END );

  /* Пытаемся распределить память */
  fb = fbuf = (unsigned char *) malloc( (size_t)  fl );
  if (fbuf == NULL) { printf(" - файл слишком велик!\n"); return; }

  /* Возвращаемся на начало файла */
  lseek( f, 0, SEEK_SET );

  /* Считываем файл в буфер */
  q = _read( f, fbuf, 0xffff );
  while (q==0xffff)
   {
    fbuf+=0xffff;
    q = _read( f, fbuf, 0xffff);
   }

  /* Ищем всевозможные заголовки Word-документа */
  for (i=0; i<(fl-16); i+=16)

    if (((fb[i]==0xDC)&&(fb[i+1]==0xA5)) ||
        ((fb[i]==0x97)&&(fb[i+1]==0xA6)) ||
        ((fb[i]==0x99)&&(fb[i+1]==0xA6)) ||
        ((fb[i]==0xEC)&&(fb[i+1]==0xA5)))

         {

          SHIFT = i; /* Устанавливаем базовое смещение */
                     /*   потенциального начала        */
                     /*   Word-документа               */

          fb[SHIFT+0xA] &= 0xFE; /* Сбрасываем признак шаблона */

          MHPOS = mk_long(&fb[SHIFT+0x118]);    /* Интерпретируем
                                                   первые 4 байта по
                                                   адресу 118h как
                                                   смещение макро-
                                                   заголовка */

          MHBASE = SHIFT+MHPOS; /* Абсолютная позиция макрозаголовка */

          if ((fb[MHBASE  ]!=0xFF) || /* Присутствует ли */
              (fb[MHBASE+1]!=0x01))   /* корректный макрозаголовок? */
              continue;

          NMACR =  mk_int(&fb[MHBASE+2]); /* Количество
                                             макросов */

          /* Цикл по макросам */
          for (j=0;j<NMACR;j++)
           {

            MACRLEN =      /* Длина макроса */
		     mk_long(&(fb[MHBASE+4+(j*24)+12]));
	    MACRPOS =      /* Позиция макроса */
		     mk_long(&(fb[MHBASE+4+(j*24)+20]));

            for (k=0;k<MACRLEN;k++)     /* Вытираем макрос */
              fb[SHIFT+MACRPOS+k] = '*';

            }
  }

  /* Возвращаемся на начало файла */
  lseek( f, 0, SEEK_SET );

  /* Записываем файло на диск */
  do
   {
    q = _write( f, fb, (int) min(fl, 0xffff ));
    fl-=min(fl,0xffff);
    fb+=min(fl, 0xffff);
  } while (fl>0);

  /* Освобождаем память */
  free(fb);

  /* Закрываем файл */
  _close(f);
  printf("теперь исцелен!\n");

  return;
}

                          Заключение

    Хотелось бы  еще разобраться с Excel-вирусами и VBA-вирусами. Кроме
того,  есть заинтересованность в информации по декодированию  двоичного
кода WordBasic- и VBA-программ.  Если кто в курсе, welcome to you, мы с
радостью опубликуем Ваши разработки в "Земском Фершале".


(C) NF, 1998-2004