Reputation: 391
Currently I have a software which has a file filter driver, during installation of software the driver is started as service in this way:
CreateService(serviceManager, name, displayName,
SERVICE_START | DELETE | SERVICE_QUERY_STATUS | SERVICE_STOP,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
path, NULL, NULL, NULL, NULL, NULL);
Where path is C:\Program Files(x86)\TSU\driver\TSUfsd.sys
.
The problem I'm having is during uninstallation of the software. It gives me access denied when software tries to delete TSUfsd.sys
file.
I've checked how the software deletes the driver, and turns out it deletes it with DeleteService
function, and waits for service to change its state from SERVICE_STOP_PENDING
to SERVICE_STOPPED
and if it doesn't happen after some time, it gets the service PID
and kills it with ProcessTerminate
and then tries to delete the file with rmdir /S /Q C:\Program Files(x86)\TSU\
.
I've tried to find the process which could have had the handle of the file(with Process Explorer) but could not find any. Then I thought maybe the service is still alive so I typed sc query TSUfsd
but the service was gone too.
I've also tried to change permissions and grant full permissions to my user but same error still occurred.
So my questions are:
Is there any other ways to check which process(or anything else) can have a hold of a file?
I've also noticed that, whenever I try to delete the file with Cygwin(rm TSUfsd.sys
) it deletes the file without a problem. What is the difference between deleting file with cmd(del /f <filename>
) and with cygwin?
Upvotes: 4
Views: 3241
Reputation: 33744
For this task, starting with Windows Vista special exist FileProcessIdsUsingFileInformation
FILE_INFORMATION_CLASS
.
So we need open file with FILE_READ_ATTRIBUTES
(this is possible even if somebody open file with 0 share mode. of if we have no access to file (by it DACL) but have read access to parent directory). and call NtQueryInformationFile
with FileProcessIdsUsingFileInformation
. on return we got FILE_PROCESS_IDS_USING_FILE_INFORMATION
structure (defined in wdm.h
) where list of ProcessId
which hold this file(open file handle or mapped section. say if this file is exe/dll - we got process ids where it loaded). good also with this print process name for every id:
volatile UCHAR guz = 0;
NTSTATUS PrintProcessesUsingFile(HANDLE hFile)
{
NTSTATUS status;
IO_STATUS_BLOCK iosb;
ULONG cb = 0, rcb = FIELD_OFFSET(FILE_PROCESS_IDS_USING_FILE_INFORMATION, ProcessIdList[64]);
union {
PVOID buf;
PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi;
};
PVOID stack = alloca(guz);
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQueryInformationFile(hFile, &iosb, ppiufi, cb, FileProcessIdsUsingFileInformation)))
{
if (ppiufi->NumberOfProcessIdsInList)
{
PrintProcessesUsingFile(ppiufi);
}
}
rcb = (ULONG)iosb.Information;
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
NTSTATUS PrintProcessesUsingFile(POBJECT_ATTRIBUTES poa)
{
IO_STATUS_BLOCK iosb;
HANDLE hFile;
NTSTATUS status;
if (0 <= (status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, 0)))
{
status = PrintProcessesUsingFile(hFile);
NtClose(hFile);
}
return status;
}
NTSTATUS PrintProcessesUsingFile(PCWSTR FileName)
{
UNICODE_STRING ObjectName;
NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(FileName, &ObjectName, 0, 0);
if (0 <= status)
{
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
status = PrintProcessesUsingFile(&oa);
RtlFreeUnicodeString(&ObjectName);
}
return status;
}
NTSTATUS PrintProcessesUsingFile(PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi)
{
NTSTATUS status;
ULONG cb = 0x8000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PVOID buf = new BYTE[cb])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
ULONG NumberOfProcessIdsInList = ppiufi->NumberOfProcessIdsInList;
PULONG_PTR ProcessIdList = ppiufi->ProcessIdList;
do
{
if (*ProcessIdList++ == (ULONG_PTR)pspi->UniqueProcessId)
{
DbgPrint("%p %wZ\n", pspi->UniqueProcessId, &pspi->ImageName);
break;
}
} while (--NumberOfProcessIdsInList);
} while (NextEntryOffset = pspi->NextEntryOffset);
}
delete [] buf;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
Upvotes: 10