从文件句柄获取文件名?

发布于 2024-09-11 09:14:02 字数 1977 浏览 6 评论 0原文

我连接了 ntdll.dll 的 NtCreateFile() 函数来允许/拒绝某些文件的访问。与 kernel32.dll 的 CreateFile() 函数不同,它可以轻松地为您提供相关文件的完整路径,而 ntdll.dll 的 NtCreateFile() 函数仅为您提供文件的句柄。我需要从文件句柄获取文件的完整路径,以允许/拒绝访问。我查了一下,似乎没有可行的 C# 解决方案。

解决方案采用 C++ 语言,并由 Microsoft 提供文档。我尝试将其移植到 C#,但没有取得太大成功。这是我对“从文件句柄获取文件名”的 C++ 版本等效的 C# 尝试:

    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;
    }

当然,我拥有所有必需的 DLLImports 和用户定义类型。当我在句柄上使用此函数时,我得到一个空字符串作为回报。调试它也相当困难,因为该方法位于注入目标进程的 DLL 中,不像您可以设置断点并享受 Visual Studio 的调试系统的东西。我想我可以写一个日志文件或一些跟踪系统,但我还没有那么绝望。我只需要一个成功的 C# 版本的“从文件句柄获取文件名”。

有任何见解、代码修复、链接吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

挽清梦 2024-09-18 09:14:02

我自己解决了。这是带有参考资料和内容的工作代码。

[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.";
}

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.";
}
千纸鹤带着心事 2024-09-18 09:14:02

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

"下面的示例使用文件映射对象从文件对象的句柄获取文件名。它使用 CreateFileMapping 和 MapViewOfFile 函数创建映射。接下来,它使用 GetMappedFileName 函数获取文件姓名。”

代码对我来说看起来合法,希望有帮助。

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.

八巷 2024-09-18 09:14:02

您在此处发布的代码是从 MSDN 复制的。
它有几个缺点: 它需要大于 0 字节的真实文件才能工作。它不适用于 0 字节的文件,也不适用于目录。 (我什至没有谈论网络驱动器)

我在这里发布了一个完美工作的代码:
如何获取与打开的 HANDLE 关联的名称

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文