Blog. Just Blog

Как получить путь из символической ссылки

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Начиная с Windows Vista, в системе появились так называемые символические ссылки, специальные файлы, в которых вместо каких-либо данных содержится путь к другому файлу или каталогу, открываемому при обращении к этой ссылке. Это позволяет, например, иметь для одного и того же файла сразу несколько разных имен.

Чтобы получить целевой путь, на который указывает символическая ссылка, есть несколько методов. Обычно в этих ваших интернетах рекомендуют сложный путь через использование функции DeviceIoControl. Штука интересная, с нее и начнем. Но сперва пачка структур и констант, которые нам понадобятся для работы.
  1. struct SymbolicLinkReparseBuffer
  2.     SubstituteNameOffset dw ?
  3.     SubstituteNameLength dw ?
  4.     PrintNameOffset      dw ?
  5.     PrintNameLength      dw ?
  6.     Flags                dd ?
  7.     PathBuffer           rw MAX_PATH*2
  8. ends
  9.  
  10. struct MountPointReparseBuffer
  11.     SubstituteNameOffset dw ?
  12.     SubstituteNameLength dw ?
  13.     PrintNameOffset      dw ?
  14.     PrintNameLength      dw ?
  15.     PathBuffer           rw MAX_PATH*2
  16. ends
  17.  
  18. struct GenericReparseBuffer
  19.     DataBuffer           db ?
  20. ends
  21.  
  22. struct REPARSE_DATA_BUFFER
  23.     ReparseTag dd ?
  24.     ReparseDataLength dw ?
  25.     Reserved dw ?
  26.     union
  27.         SymbolicLink SymbolicLinkReparseBuffer
  28.         MountPoint   MountPointReparseBuffer
  29.         Generic      GenericReparseBuffer
  30.     ends
  31. ends
  32.  
  33. FSCTL_GET_REPARSE_POINT      = 0x000900A8
  34. FILE_FLAG_BACKUP_SEMANTICS   = 0x02000000
  35. FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
  36. IO_REPARSE_TAG_MOUNT_POINT   = 0xA0000003
  37. IO_REPARSE_TAG_SYMLINK       = 0xA000000C
Первым делом для вашего процесса надо активировать привилегию SeBackupPrivilege. Это мы уже делали, тут ничего нового нет. В оригинале эта привилегия нужна для выполнения резервного копирования файлов, а по факту она предоставляет доступ на чтение для любого файла, независимо от списка контроля доступа. Именно это нам требуется для получения информации из символической ссылки.

Получив привилегии, с помощью функции CreateFile открываем символическую ссылку с указанием флагов FILE_FLAG_BACKUP_SEMANTICS и FILE_FLAG_OPEN_REPARSE_POINT.
  1.         ; Открыть файл символической ссылки
  2.         invoke  CreateFile,dir_name,\
  3.                 0,FILE_SHARE_READ,\
  4.                 NULL,OPEN_EXISTING,\
  5.                 FILE_FLAG_BACKUP_SEMANTICS+FILE_FLAG_OPEN_REPARSE_POINT,\
  6.                 NULL
  7.         cmp     eax,INVALID_HANDLE_VALUE
  8.         je      loc_exit
  9.  
  10.         ; Сохранить хэндл
  11.         mov     [hDirectory],eax
  12.  
  13.         ; Зарезервировать память
  14.         invoke  GlobalAlloc,GMEM_MOVEABLE+GMEM_DDESHARE+GMEM_ZEROINIT,\
  15.                 sizeof.REPARSE_DATA_BUFFER
  16.         mov     [mem],eax
  17.         invoke  GlobalLock,[mem]
  18.         mov     [memp],eax
  19.  
  20.         ; Получить данные объекта
  21.         invoke  DeviceIoControl,[hDirectory],\
  22.                 FSCTL_GET_REPARSE_POINT,\
  23.                 0,0,\
  24.                 [memp],sizeof.REPARSE_DATA_BUFFER,\
  25.                 tmp,NULL
  26.         or      eax,eax
  27.         jz      loc_close
  28.  
  29.         ; Проверить тип данных
  30.         mov     eax,[memp]
  31.         mov     ecx,[eax+REPARSE_DATA_BUFFER.ReparseTag]
  32.  
  33.         ; Выбрать источник строки на основании типа
  34.         cmp     ecx,IO_REPARSE_TAG_MOUNT_POINT
  35.         jne     @f
  36.         lea     ebx,[eax+REPARSE_DATA_BUFFER.MountPoint.PathBuffer]
  37.         jmp     loc_message
  38. @@:
  39.         cmp     ecx,IO_REPARSE_TAG_SYMLINK
  40.         jne     loc_close
  41.         lea     ebx,[eax+REPARSE_DATA_BUFFER.SymbolicLink.PathBuffer]
  42.  
  43. loc_message: 
  44.         ...
  45.         ...
  46.         ; EBX -> строка с названием целевого пути
  47.         ...
  48.         ...
  49. loc_close:
  50.         ; Прибраться за собой
  51.         invoke  CloseHandle,[hDirectory]
  52.  
  53.         ; Освободить память
  54.         invoke  GlobalUnlock,[mem]
  55.         invoke  GlobalFree,[mem]
Получив хэндл символической ссылки, с запасом резервируем память под структуру REPARSE_DATA_BUFFER и заполняем ее данными при помощи функции DeviceIoControl с кодом операции FSCTL_GET_REPARSE_POINT. В первом ее поле ReparseTag записан тип полученных данных, это может быть точка монтирования или символическая ссылка. В зависимости от этого получаем строку с целевым путем из соответствующей структуры. Полученный путь имеет вид типа "\??\С:\Users", это надо учитывать при дальнейшей обработке.

Со сложным путем закончили, теперь рассмотрим простой и приятный. Вместе с символическими ссылками в Windows Vista появилась функция GetFinalPathNameByHandle, с помощью которой также можно получить путь символической ссылки. Об обратной совместимости в этом случае можно не заботиться, так как и технология, и инструментарий, все появилось одновременно.
  1. FILE_READ_EA               = 0x0008
  2. FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
Прописав недостающие константы, сразу переходим к коду. Никаких предварительных действий типа повышения привилегий не требуется. Небольшое отличие от предыдущего открытия файла заключается в типе доступа FILE_READ_EA (чтение расширенных атрибутов файла) и единственном флаге FILE_FLAG_BACKUP_SEMANTICS.
  1.         ; Открыть файл символической ссылки
  2.         invoke  CreateFile,dir_name,\
  3.                 FILE_READ_EA,\
  4.                 FILE_SHARE_READ+FILE_SHARE_WRITE,\
  5.                 NULL,OPEN_EXISTING,\
  6.                 FILE_FLAG_BACKUP_SEMANTICS,\
  7.                 NULL
  8.         cmp     eax,INVALID_HANDLE_VALUE
  9.         je      loc_exit
  10.  
  11.         ; Сохранить хэндл
  12.         mov     [hDirectory],eax
  13.  
  14.         ; Зарезервировать память
  15.         invoke  GlobalAlloc,GMEM_MOVEABLE+GMEM_DDESHARE+GMEM_ZEROINIT,\
  16.                 MAX_PATH*2
  17.         mov     [mem],eax
  18.         invoke  GlobalLock,[mem]
  19.         mov     [memp],eax
  20.  
  21.         ; Получить целевой объект символической ссылки
  22.         invoke  GetFinalPathNameByHandle,[hDirectory],[memp],MAX_PATH,0
  23.         ...
  24.         ...
  25.         ; [memp] -> строка с названием целевого пути
  26.         ...
  27.         ...
  28.         ; Прибраться за собой
  29.         invoke  CloseHandle,[hDirectory]
  30.  
  31.         ; Освободить память
  32.         invoke  GlobalUnlock,[mem]
  33.         invoke  GlobalFree,[mem]
Дальше резервируем память нужного объема для получения пути и вызываем функцию GetFinalPathNameByHandle, как показано в коде. Полученный путь, как и в первом примере, также дополняется префиксом типа "\??\С:\Users". Вот и вся магия.

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

Примеры программ с исходными текстами (FASM)Примеры программ с исходными текстами (FASM)

Get.Symlink.Target.zip (4,458 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 580 | Комментариев: 2

Метки: Assembler
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
евгений (23.02.2024 в 18:06):
Да пригодилось, спасибо
Серый (13.11.2022 в 02:09):
Спасибо огромное!

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 4.03 сек. / MySQL: 2 (3.9592 сек.) / Память: 4.5 Mb
Наверх