Powershell / C#键盘挂钩脚本NullReferenceException在外部

时间:2019-04-04 14:26:13

标签: c# windows powershell keylogger keyhook

我正在尝试使用Powershell脚本(使用C#)来监听按键。在出错之前,它会工作很短的时间。有趣的是,在我添加了一些控制台写操作之后,似乎该错误发生在我的代码外部。

这是powreshell脚本:

Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    namespace KeyLogger {
        public static class Program {
            private const int WH_KEYBOARD_LL = 13;
            private static IntPtr hookId = IntPtr.Zero;

            public static void Begin() {
                hookId = SetHook();
                Application.Run();
                UnhookWindowsHookEx(hookId);
            }

            private static IntPtr SetHook() {
                IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
                return SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, moduleHandle, 0);
            }

            private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
                Console.WriteLine('0');
                if (nCode == 0) {
                    Console.WriteLine('1');
                    Console.WriteLine(Marshal.ReadInt32(lParam) + " " + wParam + " ");
                }
                Console.WriteLine('2');
                IntPtr x = CallNextHookEx(hookId, nCode, wParam, lParam);
                Console.WriteLine('3');
                return x;
            }

            private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

            [DllImport("user32.dll")]
            private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
            [DllImport("user32.dll")]
            private static extern bool UnhookWindowsHookEx(IntPtr hhk);
            [DllImport("user32.dll")]
            private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
            [DllImport("kernel32.dll")]
            private static extern IntPtr GetModuleHandle(string lpModuleName);
        }
    }
"@ -ReferencedAssemblies System.Windows.Forms

[KeyLogger.Program]::Begin();

错误是:

  

发生了未正确处理的错误。其他信息如下所示。 Windows PowerShell进程将退出。       未处理的异常:System.NullReferenceException:对象引用未设置为对象的实例。

请注意Console.WriteLine方法中的HookCallback。但是最后打印的调试行是3,表明错误发生在HookCallback之外。更有意思的是,如果我有多个脚本实例在运行,它们不会同时出错。一个可能会崩溃,但其余的会继续运行。

我对Powershell或C#不太熟悉,所以想知道如何获取更多调试信息吗?我希望发生错误的行号,文件或库名,但不确定如何获取该信息。

免责声明,我从这里https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/(稍微修改)中获取了脚本。

编辑:我接受了Stuartd的回答,因为它非常有帮助,但是正如我在评论中所说,它需要进行一些小的修改才能起作用。 为便于将来的读者阅读,以下是可行的修改:

 private static HookProc callback;
 ...

 private static IntPtr SetHook() {
     callback = HookCallback;
     IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
     return SetWindowsHookEx(WH_KEYBOARD_LL, callback, moduleHandle, 0);
 }
 ...

我已经完成了更多关于C#的搜索和阅读,看来原因是SetWindowsHookEx无法管理/保持它的hookProc委托参数有效,并且传递静态方法直接创建了本地( SetHook方法返回后即可删除的委托。

1 个答案:

答案 0 :(得分:1)

可能会这样做:创建一个指向HookProc的字段,并告诉GC使其保持活动状态:

public static class Program
{
    private const int WH_KEYBOARD_LL = 13;
    private static IntPtr hookId = IntPtr.Zero;
    private static HookProc proc;

    public static void Begin()
    {
        proc = HookCallback;
        hookId = SetHook();
        GC.KeepAlive(proc);
        Application.Run();
        UnhookWindowsHookEx(hookId);
    }

     … etc