Сценарий Powershell / C # keyhook NullReferenceException внешне - PullRequest
0 голосов
/ 04 апреля 2019

Я пытаюсь использовать скрипт 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/ (слегка измененный).

Редактировать: я принял ответ Стюарда, так как он был очень полезным, но, как я сказал в комментариях, для работы потребовались небольшие модификации. Для удобства будущих читателей, вот модификации, которые сработали:

 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 Ответ

1 голос
/ 04 апреля 2019

Это может сделать это: создайте поле, которое ссылается на 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


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...