Как получить имя файла, зная его Handle
В одной программе у меня появилась необходимость получить имя открытого файла, когда известен его хэндл. Полазив по этим вашим интернетам, я нашел немало решений этой задачи, в основном бездумно скопированных с одного сайта на другой. Пришлось разбираться и систематизировать все самому. Итак, самый простой и приятный способ, чтобы получить имя файла по его хэндлу - использовать функцию GetFinalPathNameByHandle.Code (Assembler) : Убрать нумерацию
- ; Получить имя файла по его хэндлу
- invoke GetFinalPathNameByHandle,[hFile],lpName,MAX_PATH,0
Code (Assembler) : Убрать нумерацию
- ; Создать проекцию файла
- invoke CreateFileMapping,[hFile],NULL,PAGE_READONLY,0,1,NULL
- mov [hFileMap],eax
- invoke MapViewOfFile,[hFileMap],FILE_MAP_READ,0,0,1
- mov [pMem],eax
- ; Получить имя спроецированного файла
- invoke GetCurrentProcess
- invoke GetMappedFileName,eax,[pMem],lpName,MAX_PATH
- ; Прибраться за собой
- invoke UnmapViewOfFile,[pMem]
- invoke CloseHandle,[hFileMap]
Осталось собрать все полученные знания в одну функцию. Вот что у меня получилось:
Code (Assembler) : Убрать нумерацию
- ;-------------------------------------------------------------------
- ; Функция получения полного имени файла по его handle
- ;-------------------------------------------------------------------
- proc get_file_name_from_handle hFile:DWORD, lpName:DWORD
- locals
- szName rb MAX_PATH
- szTmp rb MAX_PATH
- szDisk dd ?
- hFileMap dd ?
- pMem dd ?
- endl
- ; Сохранить все регистры
- pusha
- ; Определить адрес функции GetFinalPathNameByHandle
- invoke LoadLibrary,.szDll
- invoke GetProcAddress,eax,.szFunc
- or eax,eax
- ; Такой функции нет, работаем на старой Windows
- jz .loc_old_windows
- .loc_new_windows:
- ; Vista+
- lea ebx,[szName]
- stdcall eax,[hFile],ebx,MAX_PATH,0
- cmp dword [ebx],'\\?\'
- jne @f
- add ebx,4
- @@:
- invoke lstrcpy,[lpName],ebx
- jmp .loc_ret
- .loc_old_windows:
- ; Old Windows
- invoke GetFileSize,[hFile],NULL
- or eax,eax
- ; Файл с нулевой длиной спроецировать нельзя
- jz .loc_ret
- ; Спроецировать файл в память
- invoke CreateFileMapping,[hFile],NULL,PAGE_READONLY,0,1,NULL
- or eax,eax
- jz .loc_ret
- mov [hFileMap],eax
- invoke MapViewOfFile,[hFileMap],FILE_MAP_READ,0,0,1
- mov [pMem],eax
- ; Получить имя спроецированного файла
- lea ebx,[szName]
- invoke GetCurrentProcess
- invoke GetMappedFileName,eax,[pMem],ebx,MAX_PATH
- ; Прибраться за собой
- invoke UnmapViewOfFile,[pMem]
- invoke CloseHandle,[hFileMap]
- ; Перебрать все диски, начиная с A:
- mov [szDisk],'A:'
- .loc_find_drive:
- ; Преобразовать букву диска в строку типа \Device\HarddiskVolume1
- lea eax,[szDisk]
- lea ebx,[szTmp]
- invoke QueryDosDevice,eax,ebx,MAX_PATH
- or eax,eax
- ; Диска нет, пропускаем
- jz @f
- ; Сравнить начало пути со строкой устройства
- mov ecx,eax
- lea esi,[szName]
- mov edi,ebx
- repe cmpsb
- cmp ecx,1
- jne @f
- ; Дополнительная проверка корректности пути
- dec esi
- cmp byte [esi],'\'
- jne @f
- ; Диск + оставшийся путь к файлу
- lea eax,[szDisk]
- invoke lstrcpy,[lpName],eax
- invoke lstrcat,[lpName],esi
- jmp .loc_ret
- @@:
- ; Все диски проверили?
- lea eax,[szDisk]
- cmp byte [eax],'Z'
- jnz @f
- ; Путь к файлу как есть (сетевой диск и т.п.)
- lea ebx,[szName]
- invoke lstrcpy,[lpName],ebx
- jmp .loc_ret
- @@:
- ; Следующий диск
- inc byte [eax]
- jmp .loc_find_drive
- .loc_ret:
- ; Восстановить все регистры
- popa
- ret
- .szDll db 'kernel32.dll',0
- .szFunc db 'GetFinalPathNameByHandleA',0
- endp
Теперь давайте рассмотрим низкоуровневые способы получения информации об имени файла, если нам известен его хэндл. Первый способ основан на функции NtQueryObject. Раньше она относилась к категории недокументированных, сейчас с документацией все более-менее хорошо. Одна из ее возможностей - получение имени объекта. Хэндл файла является объектом, а имя этого объекта по сути и есть имя файла. Как обычно бывает с нестандартными решениями, придется немного расширить кругозор FASM на предмет нужных структур и констант.
Code (Assembler) : Убрать нумерацию
- ; Тип запрашиваемой информации
- ObjectNameInformation = 1
- ; Структура для получения результата
- struct OBJECT_NAME_INFORMATION
- Length dw ?
- MaximumLength dw ?
- Buffer dd ?
- String rw MAX_PATH-1
- ends
- ; Переменная для приема промежуточных данных
- tmp dd ?
- ; Структура должна быть выровнена на границу DWORD
- align 4
- ObjectNameInfo OBJECT_NAME_INFORMATION
Code (Assembler) : Убрать нумерацию
- ; Получить размер информации
- invoke NtQueryObject,[hFile],ObjectNameInformation,NULL,0,tmp
- ; Получить информацию об объекте
- invoke NtQueryObject,[hFile],ObjectNameInformation,\
- ObjectNameInfo,[tmp],tmp
Следующий способ использует функцию NtQueryInformationFile. С ее помощью можно получить огромное количество информации об открытом файле, в том числе и имя файла. Описываем нужные структуры и константы:
Code (Assembler) : Убрать нумерацию
- ; Тип запрашиваемой информации
- FileNameInformation = 9
- ; Структура для статуса выполнения операции
- struct IO_STATUS_BLOCK
- Status dd ?
- Pointer dd ?
- Information dd ?
- ends
- ; Структура для получения результата
- struct FILE_NAME_INFORMATION
- FileNameLength dd ?
- FileName rw MAX_PATH
- ends
- ; Структура должна быть выровнена на границу DWORD
- align 4
- FileInformation FILE_NAME_INFORMATION
- IoStatusBlock IO_STATUS_BLOCK
Code (Assembler) : Убрать нумерацию
- ; Получить информацию о файле
- invoke NtQueryInformationFile,[hFile],IoStatusBlock,\
- FileInformation,MAX_PATH*2,FileNameInformation
В приложении примеры программ с исходными текстам, которые открывают файл и затем различными способами пытаются получить полный путь по его хэндлу.
Просмотров: 2790 | Комментариев: 3
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
huntingspace
(08.03.2019 в 12:39):
Очень интересные варианты поиска имя файла. Мне тоже как-то, лет пять назад, приходилось писать на ассемблере не только функцию поиска имени файла по хэндлу, но и наоборот - поиска хэндла по имени файла.
ManHunter
(31.01.2019 в 11:06):
Хендл - уникальный идентификатор объекта, через который производятся операции с данным объектом. Например, открыли файл - получили хэндл открытого файла, загрузили DLL - получили хэндл, с помощью которого можно выполнять различные действия с DLL, загрузили иконку - получили хэндл иконки.
u-b0at
(31.01.2019 в 06:02):
Эх, ещё бы знать что такое handle файла?
Добавить комментарий
Заполните форму для добавления комментария