外部 Powershell / C# keyhook 脚本 NullReferenceException
Powershell / C# keyhook script NullReferenceException externally
我正在尝试使用 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();
错误是:
An error has occurred that was not properly handled. Additional information is shown below. The Windows PowerShell process will exit.
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
注意 HookCallback
方法中的 Console.WriteLine
。但最后打印的调试行是 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
方法 returns.
就可以删除的委托
可能会这样做:创建一个引用 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
我正在尝试使用 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();
错误是:
An error has occurred that was not properly handled. Additional information is shown below. The Windows PowerShell process will exit. Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
注意 HookCallback
方法中的 Console.WriteLine
。但最后打印的调试行是 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
方法 returns.
可能会这样做:创建一个引用 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