Просмотр списка всех файлов открытых любым процессом и удаление залоченых файлов

Вчера для тестирования приложения понадобилась утилита, которая могла бы показать список всех открытых в процессе файлов и выполнить с ними некоторые операции (правку, удаление).
Сложность в том, что как только приложение открывает файл, оно его лочит и его нельзя ни удалить ни редактировать. А для теста нужно было удалить такой файл на этапе, когда он уже залочен. Для этого понадобилось обратиться к недокументированным API виндовса.

Задача решается следующим образом. Вызывается функция NtQuerySystemInformation из библиотеки NTDLL. Она возвращает информацию по всем хендлам (HANDLE) в ОСи в виде структур:

typedef struct _SYSTEM_HANDLE_ENTRY {
ULONG  OwnerPid; // PID процесса
BYTE   ObjectType; // Тип информации, на который ссылается HANDLE
BYTE   HandleFlags; // Флаги, по ним я ничего не знаю
USHORT HandleValue; // Дескриптор хендла
PVOID  ObjectPointer; // указатель на прочитаный обьект в памяти
ACCESS_MASK  AccessMask; // маска доступа
}

Дальше мы перебираем каждый открытый HANDLE_ENTRY и смотрим его тип. До виндовс 8.1 ObjectType == 28 указывал на файлы. В виндовс 8.1 видно чего-то добавили (API не документировано, так что хрен его знает чего добавлено), так что теперь тип для файлов равняется 30. И это тот момент, который долго выносил мне мозг и я не мог понять почему код не работает.
Дальше когда мы находим ENTRY у которого OwnerPid равняется PID тестируемого процесса и ObjectType == 30, мы дублируем этот хендлер с полными правами доступа DUPLICATE_SAME_ACCESS в наш хендлер с помощью функции DuplicateHandle(). Дальше мы можем делать с этим хендлером всё что угодно, так как он ссылается уже нужный нам файл и может тоже в него писать, удалять его и т.д.
В моем примере программа выводит имена всех открытых файлов для процесса, думаю вам такое приложение тоже может быть полезно иногда, так что компилируйте на здоровье (Только ObjectType согласно вашей ОС версии подставьте). Пока что ещё криво работает, некоторые файлы повторяются, не разобрался ещё почему, API ведь не документирован и информацию приходится самому выковыривать, но тем не менее список содержит именно все файлы отрытые процессом.

Солюшин:

1 лайк

Update:
Теперь тулза и удаляет связь изначальной программы с файлом если при её вызове присутствует третий параметр (любой текст, мне влом было копаться)

if (!DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(),    &TargetHandleValueTemp, 0, FALSE, (argv[3] ? DUPLICATE_CLOSE_SOURCE : DUPLICATE_SAME_ACCESS)))
	{
		TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
	}

Для виндовс 8.1 бинарник:
http://wikisend.com/download/592400/OpenedFilesByProcess.exe

Для других версий ОС не уверен что сработает но можете попробовать, плохого не будет.
OpenedFilesByProcess.exe

Если файлнейм не указан, то просто выводитс список файлов по процесу