How can I get around UAC when using ReadDirectoryChanges?

て烟熏妆下的殇ゞ 提交于 2019-12-12 09:52:31

问题


I have an application that needs to monitor the primary drive for file changes via ReadDirectoryChangesW. However, when UAC is enabled, it doesn't work.

All of the Windows API calls succeed, but I'm not notified of any changes.

I can work around this by individually monitoring each directory in the root, but this is a problem, because it can potentially cause a blue screen if there are too many directories.

Is there an acceptable way to get around UAC and receive file change notifications on the entire primary drive?

The relevant CreateFile and ReadDirectoryChangesW is below. In the case where it doesn't work, directory is C:\. If I monitor any secondary drive (i.e. E:\, F:\, G:\) it works as expected. None of the calls return errors.

HANDLE fileHandle = CreateFileW(directory.c_str(), FILE_LIST_DIRECTORY, 
    FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 
    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);

BOOL success = ReadDirectoryChangesW(fileHandle, watched.buffer.data(),
    watched.buffer.size(), TRUE, 
    FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 
    NULL, &watched.overlapped, NULL);

Interestingly, the .NET System.IO.FileSystemWatcher does work correctly, and it uses the exact same functions and parameters as I'm using, but it behaves correctly.


回答1:


First it is best for applications that use the ReadDirectoryChangesW API to run elevated make a manifest file for you app and set requireAdministrator as the requestedExecutionLevel level. Check here for reference.

Try removing FILE_SHARE_WRITE from the CreateFile call if you are using it.

Another option is to make your program run as a service, im not sure how applicable this is to your needs. You could post some code as to how you are getting the file handle and what are you passing to ReadDirectoryChangesW




回答2:


Here's some working test code, for future reference.

#include <Windows.h>

#include <stdio.h>

int main(int argc, char ** argv)
{
    HANDLE filehandle;
    BYTE buffer[65536];
    DWORD dw;
    FILE_NOTIFY_INFORMATION * fni;
    OVERLAPPED overlapped = {0};

    overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (overlapped.hEvent == NULL)
    {
        printf("CreateEvent: %u\n", GetLastError());
        return 1;
    }

    filehandle = CreateFile(L"C:\\", 
        FILE_LIST_DIRECTORY, 
        FILE_SHARE_READ | FILE_SHARE_DELETE, 
        NULL, 
        OPEN_EXISTING, 
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 
        NULL);

    if (filehandle == INVALID_HANDLE_VALUE)
    {
        printf("CreateFile: %u\n", GetLastError());
        return 1;
    }

    for (;;)
    {
        if (!ReadDirectoryChangesW(filehandle, buffer, sizeof(buffer),
            TRUE, 
            FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 
            NULL, &overlapped, NULL))
        {
            printf("ReadDirectoryChangesW: %u\n", GetLastError());
            return 1;
        }

        printf("Queued OK.\n");

        if (!GetOverlappedResult(filehandle, &overlapped, &dw, TRUE))
        {
            printf("GetOverlappedResult: %u\n", GetLastError());
            return 1;
        }

        printf("%u bytes read.\n", dw);

        fni = (FILE_NOTIFY_INFORMATION *)buffer;

        for (;;)
        {
            printf("Next entry offset = %u\n", fni->NextEntryOffset);
            printf("Action = %u\n", fni->Action);
            printf("File name = %.*ws\n", 
                                  fni->FileNameLength / 2, 
                                  fni->FileName);

            if (fni->NextEntryOffset == 0) break;

            fni = (FILE_NOTIFY_INFORMATION *)
                               (((BYTE *)fni) + fni->NextEntryOffset);
        }
    }

    printf("All done\n");
    return 0;
}



回答3:


You can adjust the privileges of your process yourself like this:

// enable the required privileges for this process

LPCTSTR arPrivelegeNames[] = {  SE_BACKUP_NAME,
                                SE_RESTORE_NAME,
                                SE_CHANGE_NOTIFY_NAME
                             };

for (int i=0; i<(sizeof(arPrivelegeNames)/sizeof(LPCTSTR)); ++i)
{
    CAutoGeneralHandle hToken;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken.GetPointer()))
    {
        TOKEN_PRIVILEGES tp = { 1 };

        if (LookupPrivilegeValue(NULL, arPrivelegeNames[i],  &tp.Privileges[0].Luid))
        {
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

            AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
        }
    }
}

This works also for non-privileged processes (a.k.a. normal user processes).



来源:https://stackoverflow.com/questions/10708476/how-can-i-get-around-uac-when-using-readdirectorychanges

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!