使用 EasyHook (c#) 从 ntdll.dll 挂钩 NtCreateFile API

Posted

技术标签:

【中文标题】使用 EasyHook (c#) 从 ntdll.dll 挂钩 NtCreateFile API【英文标题】:Hooking NtCreateFile API from ntdll.dll with EasyHook (c#) 【发布时间】:2013-11-28 14:32:44 【问题描述】:

这是我第一次尝试挂钩 windows API。我的目标是监视进程将要创建/打开/读取/写入的所有文件。 为了尽可能地冗长,我决定挂钩 ntdll.dll API,例如 NtCreateFile() 和 NtOpenFile()。所以,为了实现这个目标,我继续使用 EasyHook,它看起来简单而强大。 我基本上遵循了 FileMon 示例,改变了我真正想要的:Hooked 函数。 当我尝试读取有关将要打开的文件的信息时,我尝试从 OBJECT_ATTRIBUTES 结构中读取信息,例如 对象名。这些是整数指针,所以我希望使用函数 Marshal.PtrToStringAuto(attributes.objectName) 来获取字符串值。但是,结果是我只能有坏字符串,没有任何意义。此外,文件访问似乎不起作用。我想这有问题 代码,可能在 DllImport 签名中。请注意,我必须用 IntPtr 替换 SafeHandle,因为 EasyHook 抱怨要编组它们。 有人可以帮我吗?

这是我注入的DLL的具体代码:

这是 Run 方法代码

public void Run(RemoteHooking.IContext InContext, String inChannelName) 
        
            // First of all, install all the hooks
            try
            
                // NtCreateFile
                fileCreationHook = LocalHook.Create(
                    LocalHook.GetProcAddress("ntdll.dll", "NtCreateFile"),
                    new CreateFileDelegate(CreateFile_Hooked),
                    this
                    );

                fileCreationHook = LocalHook.Create(
                    LocalHook.GetProcAddress("ntdll.dll", "NtOpenFile"),
                    new OpenFileDelegate(OpenFile_Hooked),
                    this
                    );

                fileCreationHook.ThreadACL.SetExclusiveACL(new Int32[]  0 );
                remoteIf.Log("File creation Hook correctly installed on pid "+RemoteHooking.GetCurrentProcessId());


            
            catch (Exception e)
            
                remoteIf.Log(e.Message);
                remoteIf.Log(e.StackTrace);
                return;
            

            // Wake up the process
            remoteIf.Log("Waiking up process...");
            RemoteHooking.WakeUpProcess();

            while (true)
            
                Thread.Sleep(500);

                if (queue.Count > 0)
                
                    String[] package = null;

                    lock (queue)
                    
                        package = queue.ToArray();
                        queue.Clear();
                    

                    remoteIf.OnCreateFile(RemoteHooking.GetCurrentProcessId(), package);
                
                else
                    remoteIf.Ping();
            

        

这是构造函数代码:

public InjectedDLL(RemoteHooking.IContext InContext, String inChannelName)
        
            // Create the structure which will contain all the messages
            queue = new Stack<string>();
            // Initiate the connection to the Injector process, getting back its interface
            remoteIf = RemoteHooking.IpcConnectClient<IPCInterface>(inChannelName);
            // Try invocating a method to test the connection.
            remoteIf.Ping();
        

这里有 Hook 委托和钩子函数

public delegate int CreateFileDelegate(out  IntPtr handle,
            System.IO.FileAccess access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK iostatus,
            ref long allocSize,
            uint fileAttributes,
            System.IO.FileShare share,
            uint createDisposition,
            uint createOptions,
            IntPtr eaBuffer,
            uint eaLength);

        public int CreateFile_Hooked(
            out  IntPtr handle,
            System.IO.FileAccess access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            ref long allocSize,
            uint fileAttributes,
            System.IO.FileShare share,
            uint createDisposition,
            uint createOptions,
            IntPtr eaBuffer,
            uint eaLength)
        

            //string s = Marshal.PtrToStringAuto(objectAttributes.ObjectName);
            int res = NtCreateFile(out handle, access,ref objectAttributes,out ioStatus, ref allocSize,fileAttributes, share,createDisposition,createOptions,eaBuffer,eaLength);
            return res;
        

这里有 NtDll.Dll 原生函数:

[DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
        public static extern int NtCreateFile(
            out  IntPtr handle,
            System.IO.FileAccess access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            ref long allocSize,
            uint fileAttributes,
            System.IO.FileShare share,
            uint createDisposition,
            uint createOptions,
            IntPtr eaBuffer,
            uint eaLength);

        [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
        public static extern int NtOpenFile(
            out  IntPtr handle,
            System.IO.FileAccess access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            System.IO.FileShare share,
            uint openOptions
            );

        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct OBJECT_ATTRIBUTES
        
            public Int32 Length;
            public IntPtr RootDirectory;
            public IntPtr ObjectName;
            public uint Attributes;
            public IntPtr SecurityDescriptor;
            public IntPtr SecurityQualityOfService;

        

        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct IO_STATUS_BLOCK
        
            public uint status;
            public IntPtr information;
        

【问题讨论】:

你有想过这个吗? 不,我切换回 Microsoft DeTorus。 【参考方案1】:

ObjectName 是一个指向 UNICODE_STRING 结构的指针。托管等效项如下所示:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct UNICODE_STRING

    public ushort Length;
    public ushort MaximumLength;
    [MarshalAs(UnmanagedType.LPWStr)]
    public String Buffer;

您需要使用编组来获取结构的托管副本。

var us = Marshal.PtrToStructure<UNICODE_STRING>(objectAttributes.ObjectName);

拥有托管结构后,您可以访问 Buffer 字段以获取对象的名称。

【讨论】:

以上是关于使用 EasyHook (c#) 从 ntdll.dll 挂钩 NtCreateFile API的主要内容,如果未能解决你的问题,请参考以下文章

C# Hook原理及EasyHook简易教程

EasyHook库系列使用教程之四钩子的启动与停止

EasyHook 不适用于其他线程

Easyhook 引发 System.NotSupportedException

.NET Windows 服务在 ntdll.dll 中崩溃

ntdll.dll 没有 PDB 文件