Obtain a filename from a file handle?

我怕爱的太早我们不能终老 提交于 2020-01-14 10:24:47

问题


I have the ntdll.dll's NtCreateFile() function hooked to allow/deny the access of certain files. Unlike kernel32.dll's CreateFile() which easily gives you the full path to the file in question, ntdll.dll's NtCreateFile() function only gives you the handle to the file. I need to obtain the full path of the file from a file handle, to consequently allow/deny access. I've searched around and there doesn't seem to be a working C# solution.

This solution is in C++, and documented from Microsoft. I've tried to port it over to C# with not much success. Here is my attempt at the C# equivalent of the C++ version of "obtaining a filename from a file handle":

    public string GetFileNameFromHandle(IntPtr FileHandle)
    {
        string fileName = String.Empty;
        IntPtr fileMap = IntPtr.Zero, fileSizeHi = IntPtr.Zero;
        UInt32 fileSizeLo = 0;

        fileSizeLo = GetFileSize(FileHandle, fileSizeHi);

        if (fileSizeLo == 0 && fileSizeHi == IntPtr.Zero)
        {
            // cannot map an 0 byte file
            return String.Empty;
        }

        fileMap = CreateFileMapping(FileHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 1, null);

        if (fileMap != IntPtr.Zero)
        {
            IntPtr pMem = MapViewOfFile(fileMap, FileMapAccess.FileMapRead, 0, 0, 1);
            if (pMem != IntPtr.Zero)
            {
                StringBuilder fn = new StringBuilder(250);
                GetMappedFileName(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, pMem, fn, 250);
                if (fileName.Length > 0)
                {
                    UnmapViewOfFile(pMem);
                    CloseHandle(FileHandle);
                    return fn.ToString();
                }
                else
                {
                    UnmapViewOfFile(pMem);
                    CloseHandle(FileHandle);
                    return String.Empty;
                }
            }
        }

        return String.Empty;
    }

I have, of course, all the necessary DLLImports and user-defined types. When I use this function on handles, I get an empty string in return. It's also pretty hard to debug this, since this method is in a DLL that gets injected into a target process, not like something you can set a breakpoint at and enjoy Visual Studio's debugging system. I guess I could write a log file or some trace system, but I'm not that desperate yet. I just need a successful C# version of "get filename from file handle".

Any insight, code fixes, links?


回答1:


Solved it myself. Here's the working code with the references and stuff.

[DllImport("kernel32.dll")]
static extern uint GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFileMapping(
    IntPtr hFile,
    IntPtr lpFileMappingAttributes,
    FileMapProtection flProtect,
    uint dwMaximumSizeHigh,
    uint dwMaximumSizeLow,
    [MarshalAs(UnmanagedType.LPTStr)]string lpName);

[Flags]
public enum FileMapProtection : uint
{
    PageReadonly = 0x02,
    PageReadWrite = 0x04,
    PageWriteCopy = 0x08,
    PageExecuteRead = 0x20,
    PageExecuteReadWrite = 0x40,
    SectionCommit = 0x8000000,
    SectionImage = 0x1000000,
    SectionNoCache = 0x10000000,
    SectionReserve = 0x4000000,
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr MapViewOfFile(
    IntPtr hFileMappingObject,
    FileMapAccess dwDesiredAccess,
    uint dwFileOffsetHigh,
    uint dwFileOffsetLow,
    uint dwNumberOfBytesToMap);

[Flags]
public enum FileMapAccess : uint
{
    FileMapCopy = 0x0001,
    FileMapWrite = 0x0002,
    FileMapRead = 0x0004,
    FileMapAllAccess = 0x001f,
    fileMapExecute = 0x0020,
}

[DllImport("psapi.dll", SetLastError = true)]
public static extern uint GetMappedFileName(IntPtr m_hProcess, IntPtr lpv, StringBuilder 
        lpFilename, uint nSize);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

public static string GetFileNameFromHandle(IntPtr FileHandle)
{
    string fileName = String.Empty;
    IntPtr fileMap = IntPtr.Zero, fileSizeHi = IntPtr.Zero;
    UInt32 fileSizeLo = 0;

    fileSizeLo = GetFileSize(FileHandle, fileSizeHi);

    if (fileSizeLo == 0)
    {
        // cannot map an 0 byte file
        return "Empty file.";
    }

    fileMap = CreateFileMapping(FileHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 1, null);

    if (fileMap != IntPtr.Zero)
    {
        IntPtr pMem = MapViewOfFile(fileMap, FileMapAccess.FileMapRead, 0, 0, 1);
        if (pMem != IntPtr.Zero)
        {
            StringBuilder fn = new StringBuilder(250);
            GetMappedFileName(System.Diagnostics.Process.GetCurrentProcess().Handle, pMem, fn, 250);
            if (fn.Length > 0)
            {
                UnmapViewOfFile(pMem);
                CloseHandle(FileHandle);
                return fn.ToString();
            }
            else
            {
                UnmapViewOfFile(pMem);
                CloseHandle(FileHandle);
                return "Empty filename.";
            }
        }
    }

    return "Empty filemap handle.";
}



回答2:


From http://msdn.microsoft.com/en-us/library/aa366789.aspx

"The following example obtains a file name from a handle to a file object using a file mapping object. It uses the CreateFileMapping and MapViewOfFile functions to create the mapping. Next, it uses the GetMappedFileName function to obtain the file name."

Code looks legit to me, hope that helps.




回答3:


The code you posted here has been copied from the MSDN. It has several disadvantages: It requires a real file bigger than 0 Bytes to work. It does not work for files of 0 Bytes nor does it work for directories. (and I'm not even talking about network drives)

I have posted a perfectly working code here: How to get name associated with open HANDLE



来源:https://stackoverflow.com/questions/3314239/obtain-a-filename-from-a-file-handle

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