Пакет программ Microsoft Office — это не только фактический стандарт офисного ПО, но и весьма сложная и многофункциональная среда, позволяющая создавать решения, предназначенные прежде всего для применения возможностей Microsoft Office и автоматизации рутинных действий пользователя при работе с документами. Эта программная платформа, называемая Объектной Моделью Microsoft Office (Microsoft Office Object Model), или же Автоматизацией Microsoft Office (Microsoft Office Automation) основана на Объектной Модели COM и содержит обширный набор классов, предоставляющих доступ практически к любому элементу или действию, доступному пользователю при работе с Microsoft Office через графический интерфейс.

image
Объектная модель Microsoft Word (частично)

Говоря о программировании для Microsoft Office, часто подразумевают «внутренние» программы — макросы, написанные на VBA (Visual Basic for Applications, реализация Visual Basic в Microsoft Office) и встраиваемые непосредственно в документы.

image
Создание макроса для Microsoft Excel

Благодаря широким возможностям языка (за счет доступа к внешним dll и компонентам практически неограниченным) и удобной модели распространения (с файлами документов) макросы Microsoft Office использовались для создания зловредного ПО с момента появления VBA и получили собственное название — макровирусы. Несмотря на некоторое ужесточение настроек, связанных с макросами (на текущий момент актуальные версии Microsoft Office при настройках по умолчанию запрещают автоматическое выполнение макросов, уведомляя об этом пользователя), макровирусы активно применяются злоумышленниками и сейчас. Для эффективного использования этой технологии с двадцатилетней историей оказалось достаточно дополнить ее элементами социальной инженерии.

image
Предложение пользователю разрешить макросы в документе, содержащем зловредный код

Объекты Microsoft Office доступны не только из макросов, но и из «внешних» программ на любых языках, поддерживающих COM. Последние могут быть компилируемыми программами на языках вроде C++ или Delphi, управляемыми приложениями на Java или .Net, или же скриптами на VBScript и PowerShell — COM технология доступна практически для всего, способного выполняться под Windows.

image
Доступ к объектной модели Microsoft Office из PowerShell

Объектная Модель Microsoft Office представляет приложения Microsoft Office в виде COM-объектов. Но существует также возможность добавлять в документы и другие COM-объекты — управляющие элементы ActiveX, не относящиеся к Microsoft Office, но присутствующие в операционной системе. Будучи включенными в документ, эти элементы могут взаимодействовать с кодом макросов, либо выполнять собственный код, основанный на добавляемых в документ «свойствах» — properties объекта. В умелых руках встраивание элементов ActiveX также может приводить к выполнению произвольного кода, поэтому в последних версиях Microsoft Office по умолчанию запрещен запуск встроенных ActiveX за исключением некоторого «белого списка» элементов. Впрочем, пользователь и в этом случае при желании может явно разрешить выполнение.

image
Предупреждение о встроенных ActiveX

Предложение разрешить (или запретить) запуск активного содержимого поступит пользователю при открытии документа нормальным образом в соответствующем приложении. Что же случится, если открыть тот же документ, воспользовавшись Объектной Моделью Microsoft Office?
Примеров таких программ — великое множество на самых разных языках и под самые разные задачи:

Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add("e:\test\fax.dotx")
objDoc.SaveAs("e:\test\temp.docx")
objDoc.Close
objWord.Quit
Пример на VBScript

application = new Word.Application();
Object templatePathObj = "путь к файлу шаблона";;
try
{
    document = application.Documents.Add(ref  templatePathObj, ref missingObj, ref missingObj, ref missingObj);
}
catch (Exception error)
{
    document.Close(ref falseObj, ref  missingObj, ref missingObj);
    application.Quit(ref missingObj, ref  missingObj, ref missingObj);
    document = null;
    application = null;
    throw error;
}
_application.Visible = true;
Пример на C#

try {
        using namespace Word;
        _ApplicationPtr word(L"Word.Application");
        word->Visible = true;
        word->Activate();
        _DocumentPtr wdoc1 = word->Documents->Add();
        RangePtr range = wdoc1->Content;
        range->LanguageID = wdRussian;
        range->Tables->Add(range,5,5);
       wdoc1->SaveAs(&_variant_t("C:\\1test.doc"));
        wdoc1->Close();
 
    } catch (_com_error& er) {}
Пример на C++

$word = New-Object -ComObject Word.Application
$word.Visible = $True
$doc = $word.Documents.Add()
Пример на PowerShell

При изучении подобных примеров лишь один раз нам попалась в коде интересная строчка:

app.AutomationSecurity = 3

Что она означает, расскажет официальная документация:

Application.AutomationSecurity Property (Excel)

Returns or sets an MsoAutomationSecurity constant that represents the security mode Microsoft Excel uses when programmatically opening files.

MsoAutomationSecurity can be one of these MsoAutomationSecurity constants.

msoAutomationSecurityByUI. Uses the security setting specified in the Security dialog box.|
msoAutomationSecurityForceDisable. Disables all macros in all files opened programmatically without showing any security alerts.
msoAutomationSecurityLow. Enables all macros. This is the default value when the application is started.

Оказывается, если приложение Microsoft Office запущено как элемент автоматизации, то код макросов в открываемых документах будет по умолчанию выполнен. Если, конечно, специально не изменить уровень безопасности управляющей программой. Это умолчание не зависит от настроек, выставленных пользователем или администратором. Помимо макросов, будет также загружен и выполнен код любых элементов ActiveX, добавленных в документ.


Выполнение макроса при открытии документа через Автоматизацию

Эта неочевидная особенность, судя по всему, достаточно редко учитывается. К примеру, офисные программы других производителей применяют объектную модель Microsoft Office для импорта и экспорта данных в документы Word и Excel. Достаточно часто встречаются примеры для 1С:

MSWord = Новый COMОбъект("Word.Application"); 
    MSWord.Documents.Add(ИмяФайла);

    ActiveDocument = MSWord.ActiveDocument;
    Content = ActiveDocument.Content;
            
    //Добавляем строки в конец документа
    Content.InsertParagraphAfter();
    Content.InsertAfter("Добавляемая строка 1");
    Content.InsertParagraphAfter();
    Content.InsertAfter("Добавляемая строка 2");
    Content.InsertParagraphAfter();
            
    //Добавляем в конец текущего документа содержимое другого файла без ссылки на исходный
    //Вставим дополнительный абзац
    Content.InsertParagraphAfter();

    //На его место вставляем файл
    ActiveDocument.Range(Content.End - 1, Content.End).InsertFile(ИмяФайлаДляВставки, "", Ложь, Ложь);
    Content.InsertParagraphAfter();
Пример для 1С

Программы 1С, называемые «обработками», также могут использовать COM вообще и объектную модель Microsoft Office в частности. Некоторые полезные обработки предоставляются пользователям производителем, например, обработка «ЗагрузкаДанныхИзТабличногоДокумента.epf» позволяет загружать в базу данные из внешних табличных документов.


Выполнение макроса при открытии документа через обработку 1С

Как можно видеть, свойство AutomationSecurity было забыто и программистами 1С.
С одной стороны, это классический пример того, что необходимо думать о безопасности в процессе программирования, какой бы язык ни использовался. С другой стороны, какая причина заставила Microsoft при ужесточении настроек безопасности Microsoft Office оставить незащищенной объектную модель?


Небольшое видео, демонстрирующее то, как злоумышленник может захватить контроль над компьютером бухгалтерии при помощи Metasploit Framework и прайса на вареники. Макрос, содержащийся в документе Excel, запускает скрипт для PowerShell, открывающий атакующему доступ к командной строке на атакуемой системе.

Комментарии (3)


  1. g0rd1as
    10.08.2017 21:07
    +1

    Я много слышал про макровирусы, но это видео меня просто удивило! Статью сохраню. :)


  1. LbISS
    11.08.2017 09:43
    +1

    Здравствуй, Word.Interop, давно не виделись. Сразу небольшой совет всем к статье — не используйте это в сервером окружении. Это написано на сайте MS, но на stackoverflow все говорят "плюй и используй, будет проще". Не будет.


    • Зависания при работе с несколькими инстансами.
    • Тонна недокументированных ошибок в коде скопипащенном из MSDN вида "Com ошибка, что-то сломалось, насяльника"
    • Работа с dynamic-ами, т.к. возможно несколько версий office на компьютере у пользователя и надо подгружать библиотеку динамически по версии офиса прописанной в реестре.
    • Куча проблем с DCOM config-ом в корпоративных сетях.
    • Доустановка MS Online Services, отсутствие которых тоже приводит к недокументированным ошибкам.
    • Любой алерт вида "документ защищенный", "есть изменения, сохранить?", "файл создан в старой версии, обновить?" приводит к рестарту процесса, т.к. через Com модель к этому алерту у вас нет доступа. И вы должны либо не допустить его появления, либо если появился — то всё, ничего не сделаешь, грохай процесс.
    • Поднятие UI сеанса на сервере, проблемы с правами.
    • и опять же зависаниями "RPC unavailable" Word без причины.
      Основная беда — все ошибки недокументированны, невоспроизводимы и несодержательны. Наиболее частая ситуация, которую вы будете получать — процесс Word-а висит на сервере не закрытым, но уже без UI и не откликается, в логе скупой "RPC server unavailable" — живи с этим.

    Применили решение послушавшись stackoverflow, задача была достаточно сложной — сравнение и объединение нескольких файлов по сложному алгоритму с учетом рецензирования несколькими людьми, примечаний, колонтитулов, таблиц и т.п.
    В итоге оказалось проще просто продублировать все механизмы MS на OpenXML, чем заставить работать Interop. Спустя несколько потерянных месяцев трудозатрат всё было переписано на OpenXML — работает стабильно и значительно быстрее.


    1. ormoulu Автор
      11.08.2017 10:28
      +1

      Да, на Msdn обстоятельная статья на тему «почему вам не следует использовать это в серверном решении».