hex.pp.ua

Создание reparse point собственного типа

Создание точки повторной обработки своего типа




Точки повторной обработки (reparse point) — технология файловой системы NTFS, позволяющая создавать собственные типы объектов в файловой системе. Через механизм reparse в Windows реализована поддержка символьных ссылок и точек монтирования томов и каталогов. Существует возможность создавать и использовать собственные типы точек повторной обработки.

Приведу пример создания собственного типа reparse point, с использованием структуры REPARSE_GUID_DATA_BUFFER и вызова функции DeviceIoControl. В примере кода используются вспомогательные функции OpenLinkHandle и GetPrivilege, исходный код которых можно найти в статье Создание символьной ссылки Windows на C/C++, которая рассказывает о создании стандартных типов точек повторной обработки (симлинк, junction).

Для того, чтобы создать собственный тип точки повторной обработки, следует начать с получения привилегий SE_BACKUP_NAME и и SE_RESTORE_NAME, затем выделить память для структуры REPARSE_GUID_DATA_BUFFER (winnt.h). Из названия структуры видно, что она содержит уникальный идентификатор GUID. Эта структура используется с собственными типами reparse, а при операциях со стандартными типами используется другая структура REPARSE_DATA_BUFFER.

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

Формат тега reparse

Необходимо правильно заполнить поле ReparseTag структуры REPARSE_GUID_DATA_BUFFER. Формат этого поля такой:

 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+-+-+-+-+-----------------------+-------------------------------+
|M|L|N|R|    Резервные биты     |         Значение тега         |
+-+-+-+-+-----------------------+-------------------------------+

Обозначение:

  • M — Бит Майкрософт. Если этот бит установлен, значит тег разработан компанией Майкрософт. Все остальные теги должны иметь значение 0 у этого бита.
  • L — Бит задержки; Если этот бит установлен, это означает, что данные, на которые ссылается точка повторной обработки расположены на носителе с низкой скоростью реакции и большой задержкой выдачи данных.
  • R — Зарезервированный бит; должен быть равен нулю для всех тегов, не принадлежащих компании Майкрософт.
  • N — Бит замены имени. Если этот бит установлен, значит файл или каталог представляет другую именованную сущность в файловой системе.

В поле ReparseTag записано значение 0x0000FF00. Это значение является тегом, указывающим на тип точки повторной обработки. В заданном мной значении резервные биты, а также биты M, R и N обнулены.

Создание reparse point

После помещения в структуру GUID, тега, длины данных и самих данных можно вызывать функцию DeviceIoControl. В предварительно созданный файл будет записан reparse-буфер и превратит этот файл в точку повторной обработки нашего собственного типа. После того, как файл появился, следует проверить, правильно ли создалась reparse point. Для этого следует воспользоваться приложением fsutil в командной строке Windows:

D:\TMP>fsutil reparsepoint query test_link
Значение тега повторной обработки: 0x0000ff00
GUID: {07A869CB-F647-451F-840D-964A3AF8C0B6}

Длина данных повторного анализа: 0x00000044
Данные повторной обработки:
0000:  58 35 4f 21 50 25 40 41  50 5b 34 5c 50 5a 58 35  X5O!P%@AP[4\PZX5
0010:  34 28 50 5e 29 37 43 43  29 37 7d 24 45 49 43 41  4(P^)7CC)7}$EICA
0020:  52 2d 53 54 41 4e 44 41  52 44 2d 41 4e 54 49 56  R-STANDARD-ANTIV
0030:  49 52 55 53 2d 54 45 53  54 2d 46 49 4c 45 21 24  IRUS-TEST-FILE!$
0040:  48 2b 48 2a                                       H+H*

Операции с точкой повторной обработки

Невозможно удалить файл
Невозможно удалить файл

Вывод программы fsutil показывает, что reparse point создался правильно. Для вновь созданной точки повторной обработки отсутствует фильтр файловой системы, способный воспринимать наш тип с тегом 0x0000FF00. Поэтому операционная система не умеет обрабатывать нашу точку повторной обработки. Для файловой системы это теперь совершенно чужеродный объект. Это выражается в том, что с созданным файлом невозможно выполнить никакие операции.

Например, если попытаться удалить из Проводника файл test_link, получим сообщение Ошибка 0x80070780. Доступ к этому файлу из системы отсутствует. Точно такое же сообщение возникает после попыток переместить или переименовать файл. Также невозможно открыть файл в какой-либо программе

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

В reparse буфере файла содержится тестовый безвредный вирус EICAR, созданный специально для проверки антивирусов. Конечно, исполняемый код из reparse-буфера запуститься не способен, его лишь можно оттуда прочесть. Но антивирусные программы обязаны его там найти, если конечно в них есть функция проверки точек повторной обработки.

Avast не может сканировать reparse
Avast не может сканировать reparse

В момент, когда я пишу эту статью в моём распоряжении есть только антивирус Avast. При попытке сканирования файла он выдаёт сообщение "некоторые файлы не удаётся просканировать". При нажатии на кнопку "показать результаты" видно ту же причину ошибки, которую указывает Проводник. Ни слова про reparse.


Результат создания reparse point

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

Удалить точку повторной обработки можно из командной строки, набрав fsutil reparsepoint delete. Программным путём reparse point удаляется через вызов DeviceIoControl с контрольным кодом FSCTL_DELETE_REPARSE_POINT.

Код функции

  GetPrivilege(SE_BACKUP_NAME);
  GetPrivilege(SE_RESTORE_NAME);
  GetPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME);
  
  char reparse_buf[MAX_PATH * 3];
    PREPARSE_GUID_DATA_BUFFER rd
    = (PREPARSE_GUID_DATA_BUFFER) reparse_buf;

  ZeroMemory(reparse_buf, MAX_PATH * 3);

  DWORD dwLen = 0;
  LPCWSTR link_name_full = L"D:\\tmp\\test_link";

  HANDLE hFile = CreateFile(link_name_full, 
    GENERIC_READ | GENERIC_WRITE, 0, NULL, 
    CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE)
  {
    return FALSE;
  }
  CloseHandle(hFile);

  // {07A869CB-F647-451F-840D-964A3AF8C0B6}
  static const GUID my_guid = 
  { 
    0x7a869cb, 0xf647, 0x451f, 
    { 0x84, 0xd, 0x96, 0x4a, 0x3a, 0xf8, 0xc0, 0xb6 } 
  };

  //UINT num = 0xABCD;
  char eicar[] = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$"
                 "EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";

  rd->ReparseTag = 0xFF00; // Собственный тег
  rd->ReparseDataLength = strlen(eicar);
  rd->Reserved = 0;
  rd->ReparseGuid = my_guid;
  memcpy(rd->GenericReparseBuffer.DataBuffer, &eicar;, strlen(eicar));

  wprintf(L"%s", L"Open handle:\n");
  HANDLE hHandle = OpenLinkHandle(link_name_full);

  if (INVALID_HANDLE_VALUE == hHandle)
  {
    return FALSE;    
  }

  // Установить reparse данные открытой папке
  wprintf(L"%s", L"Create link:\n");
    if (!DeviceIoControl( hHandle, FSCTL_SET_REPARSE_POINT,
                rd, rd->ReparseDataLength 
        + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
                NULL, 0, &dwLen;, NULL ))
  {    
    // Если добавить reparse данные
    // не удалось, папку следует удалить
    CloseHandle(hHandle);
    DeleteFile(link_name_full);
    return FALSE;
  }

  CloseHandle(hHandle);

По теме точек повторной обработки также есть следующее:



Автор: амдф
Дата: 07.02.2011


При копировании материалов хорошим тоном будет указание авторства и ссылка на сайт. По поводу рекламы обращайтесь на почту [email protected]