日志记录挂钩的挂钩过程从未被调用

2024-02-16

我正在尝试创建一个简单的应用程序来记录和播放一系列键盘和鼠标命令(宏)。阅读文档并得出结论,最合适的实现(如果不是唯一的实现)是设置 Windows 日志记录挂钩(WH_JOURNALRECORD)并用日志回放一个(WH_JOURNAL_PLAYBACK).

根据文档,这些挂钩不需要驻留在 DLL 中,而是可以位于可执行文件(应用程序)中。因此,我让 Visual Studio 为我创建了一个简单的 Win32 应用程序。这是一个非常经典的应用程序,注册窗口类、创建窗口并运行消息循环。该文档还提到了钩子程序WH_JOURNALRECORD/WH_JOURNAL_PLAYBACK钩子在设置它们的线程的上下文中运行。但是,它没有具体提及该线程应该做什么,例如运行消息循环、在可警报状态下睡眠或什么。所以我只是设置钩子并运行消息循环 - 它是应用程序的主线程,也是唯一的线程。我发现的一些代码示例也是这样做的,尽管它们现在似乎无法工作,因为它们已经很旧了,而且一些 Windows 安全更新使事情变得更加困难。

我相信我已经采取了在一些示例和帖子中找到的所有必要步骤:

  • 设置清单选项“UAC执行级别" to "requireAdministrator (/level='requireAdministrator')" and "UAC绕过UI保护" to "是 (/uiAccess='true')".
  • 创建并安装证书 - 应用程序在构建后使用它进行签名。
  • 可执行文件被复制到 System32(受信任的文件夹)并从那里“以管理员身份”运行。 如果不执行上述操作,挂钩安装将失败,错误代码为 5(访问被拒绝)。

我已经成功(?)安装了WH_JOURNALRECORD hook (SetWindowsHookEx()返回一个非零句柄),但是不会调用钩子过程。

下面是我的代码(我省略了窗口类注册、窗口创建、窗口过程和关于对话框的内容,因为其中没有什么有趣或特别的东西 - 它们只是做准系统):

// Not sure if these are needed, found it in some code samples
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
HHOOK hhJournal = NULL;
#pragma data_seg()

// Not sure if the Journal proc needs to be exported
__declspec(dllexport) LRESULT CALLBACK _JournalRProc(_In_ int code, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
    Beep(1000, 30); // Clumsy way to trace the JournalRProc calls

    return CallNextHookEx(NULL, code, wParam, lParam);
}

void AddKMHooks(HMODULE _hMod)
{
    if (hhJournal) return;
    MessageBox(NULL, "Adding Hooks", szTitle, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
    hhJournal = SetWindowsHookEx(WH_JOURNALRECORD, _JournalRProc, _hMod, 0);
    if (!hhJournal)
    {
        CHAR s[100];
        wsprintf(s, "Record Journal Hook Failed!\nThe Error-Code was %d", GetLastError());
        MessageBox(NULL, s, szTitle, MB_OK | MB_ICONSTOP | MB_TASKMODAL);
    }
}

void RemoveKMHooks()
{
    if (!hhJournal) return;
    MessageBox(NULL, "Removing Hooks", szTitle, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
    UnhookWindowsHookEx(hhJournal);
    hhJournal = NULL;
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_KMRECORD, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance(hInstance, nCmdShow)) return FALSE;

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_KMRECORD));

    AddKMHooks(hInstance);
    // Calling AddKMHooks(GetModuleHandle(NULL)) instead, delivers the same results

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    // Once the hook has is set the GetMessage() call above 
    // always returns a WM_TIMER message with a timer ID of 1,
    // posted to the queue with the PostMessage() function,
    // as the Spy++ tool reports

    RemoveKMHooks();

    return (int) msg.wParam;
}

我用Spy++工具监控应用程序,发现当设置钩子时,应用程序会收到一系列连续的WM_TIMER计时器消息,计时器 ID 为 1,发布到队列中PostMessage()函数(Spy++ 中的 P)。据报告,这些消息的窗口句柄与主窗口属于同一应用程序和线程,其类名称为“UserAdapterWindowClass”。我的代码既不创建计时器,也不显式创建此类的任何窗口,因此显然这些是由系统创建的。此外,还有另一条消息,ID 为 0x0060(未知!),仅在第一次或第二次之后发布到同一窗口一次WM_TIMER one.

该应用程序似乎以某种方式“锁定”系统(录制、等待资源,或者什么?),直到我按 Alt+Ctrl+Del,文档说停止录制(我还没有实现某种机制来停止录制/随意卸载钩子,所以这是我目前使用的)。钩子过程似乎永远不会被调用,这就是我目前面临的问题。我考虑过检查code钩子过程中的参数并采取相应的行动,但我还没有接近这一点,因为该过程从未被调用 - 因此它不会产生任何效果 - 所以我只是调用CallNextHookEx()在那里(并假设它会运作良好)。

Notes:

  • 钩子过程有时可能只被调用一次,但这种情况相当罕见(几乎不可重现)并且绝对不一致,所以我认为我不能依赖于此;这code参数为 0 (HC_ACTION)。但测试了它,并返回零或非零,或者调用CallNextHookEx()或不,根本没有区别。
  • 我还尝试在另一个线程中设置挂钩(在主线程开始处理消息后创建),然后该线程也运行消息循环,但我得到了完全相同的行为。

有人可以解释一下这里可能出了什么问题吗?还检查了其他一些帖子,特别是这些:WH_JOURRNALRECORD 的 SetWindowsHookEx 在 Vista/Windows 7 下失败 https://stackoverflow.com/questions/9165666/setwindowshookex-for-wh-journalrecord-fails-under-vista-windows-7 and Windows (C++) 中的 WH_JOURNALRECORD 挂钩 - 从未调用过回调。 https://stackoverflow.com/questions/3157212/wh-journalrecord-hook-in-windows-c-callback-never-called/3157256,但是找不到解决方案,而且我必须注意使用条件也不同。我所经历的最接近这个SetWindowsHookEx(WH_JOURRNALRECORD, ..) 有时会挂起系统 https://stackoverflow.com/questions/29335012/setwindowshookexwh-journalrecord-sometimes-hang-the-system尽管就我而言,这种情况总是会发生,而不仅仅是“有时”。

我将非常感谢任何帮助。

我已经上传了解决方案(源+ VS 文件,但不是 .exe、.obj.、.pch、.pdb 等文件,因此需要重建)here https://github.com/GCoves81/KbdMouseRecorderSource,如果有人想看的话。

先感谢您


EDIT:

在不同配置下测试应用程序。

  • 最初,该应用程序是在 Visual Studio 2017 中创建的,并在 Windows 10 Pro 32 位版本 1803、2 核 AMD 处理器计算机(本机上安装了 VS2017)下进行了测试。得到了上面描述的结果。
  • 然后在Windows 10 Pro 64位版本1903、4核AMD处理器电脑下进行测试。这台机器安装了一个非常旧版本的Visual Studio(尽管它没有以任何方式参与开发和测试)。安装证书并运行应用程序(均在另一台计算机上创建)。最初的结果是相同的(钩子过程从未被调用)。
  • 尝试从“PrivateCertStore”存储位置删除证书,只保留“受信任的根证书颁发机构”下的副本(这是我编写的批处理文件调用 makecert 和 certmgr 存储证书的方式,即在上述两个位置下) 。出乎意料,但它有效,当我移动鼠标时听到多次蜂鸣声!再次测试,添加/删除/移动证书,行为完全可重现:只需将证书安装在“受信任的根证书颁发机构”下,挂钩即可工作。
  • 然后在32位机器上重复上述测试。它在那里不起作用,应用程序像以前一样被“冻结”(仅获取 WM_TIMER 消息)。
  • 在64位机器上,卸载旧的VS版本和安装的相当多的Windows SDK版本,并安装VS 2019社区版。在 VS2019 中重建应用程序(重新创建并安装证书,并对可执行文件进行签名)。该应用程序现在无法在任何一台机器上运行(同样,钩子创建成功,但未调用钩子过程)。可能是 VS2019 安装或某些 Windows 更新导致了此问题。
  • 同样,在 32 位计算机上创建的应用程序/证书现在在任何一台计算机上都不起作用。

所以它一定是 Windows 模块或我不满足的一些有关证书的要求,导致了这种情况。在互联网上搜索了很多,但找不到证书必须符合哪些规范。例如,对格式、私钥或用途有什么要求(现在我已经检查了所有用途,尽管我也尝试过仅检查代码签名,这没有什么区别)。 makecert 实用程序现已弃用(文档建议使用 PowerShell 创建证书),但我不知道这是否与我的问题有关。

我只得出两个结论: - 证书必须安装在“PrivateCertStore”下,才能构建应用程序(否则签名失败)。可能是因为我在脚本中设置了 /s PrivateCertStore 选项。但, - 证书必须安装在“受信任的根证书颁发机构”下,应用程序才能运行(否则执行会失败,并出现拒绝访问错误)。


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

日志记录挂钩的挂钩过程从未被调用 的相关文章

  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 如何使用来自 Microsoft-Windows-NDIS-PacketCapture 提供程序的实时 ETW 事件?

    更大的问题是一般如何使用实时 ETW 网络堆栈事件 但我特别感兴趣Microsoft Windows NDIS PacketCapture 提供程序 所有其他网络堆栈提供程序都部分工作 但 NDIS PacketCapture NDIS P
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l

随机推荐

  • 无法将 JSON 对象插入 Firebase 实时数据库

    我正在尝试将用户数据存储在我的 Firebase 数据库中 这是我处理 onClick 并将数据发送到数据库的代码 public void onClickStore final View view String name binding g
  • 停止观察reactjs中的文件夹变化

    我正在开发一个反应项目 用户可以在其中上传文件 我面临的问题是当我将文件上传到服务器并将该文件保存到位于公共文件夹中的名为 uploads 的文件夹中时 然后当此过程完成页面刷新 这是因为应用程序正在监视任何更改并刷新页面 我知道我可以通过
  • 尽管安装并加载了 reshape2,但仍找不到功能“cast”

    跟随哈德利 威克姆 Hadley Wickham 探索数据和模型的实用工具 http had co nz thesis 2 4 节中的示例 铸造熔融数据我越来越Error could not find function cast 我已经安装
  • 一键运行 Javascript 2 个函数

    我使用从网上下载的 HTML 和 JS 代码来录制音频 但有一个问题 因为页面加载到屏幕上后立即出现允许麦克风的消息 正是因为window onload function init 在源代码record js中 但我想在单击按钮后显示消息
  • 在控制台应用程序中捕获 ctrl+c 事件(多线程)

    我有一个控制台应用程序的主线程 它以这种方式运行很少的外部进程 private static MyExternalProcess p1 private static MyExternalProcess p2 private static M
  • 304 未修改问题

    抱歉 标题可能有误 我正在编写一些代码来处理 If Modified Since 和 If None Match 请求作为缓存的一部分 除了 PHP 在标头后面返回一些内容 空行 之外 一切都很完美 页面内容应该为空 我正在使用的代码是
  • 是否可以将别名模板标记为好友?

    想象一下我们有这样的代码 template
  • 在字符串文字中展开宏

    我想做的是 define一个宏 define a 2 然后在字符串文字中使用它 string a 我希望该字符串不被解释为字符串 而是获取值a 即2 我没有成功 有人可以帮忙吗 define STRINGIFY2 X X define ST
  • 参数作用域与局部变量作用域?

    我正在读我的 AP cs 书 它谈到了三种类型的变量 实例变量 局部变量 参数 实例变量在整个类中都是可见的等等 参数只能在方法内使用 局部变量也是如此 因此 我的问题是 如果参数和局部变量包含相同的范围 为什么他们会将参数和局部变量分类为
  • MySql 适合大型数据库吗? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我在一家公司工作 我们总是访问外部网站以获取信息 该网站是由一家过时的软件开发公司开发的 该公司甚至没有网站 他们在我所在的州几乎拥有垄断地
  • 如果 Blob URL 是不可变的,Media Source Extension API 如何使用它们来流式传输视频?

    让我们从一个例子开始 您访问 youtube com 该网站在某些设备上使用带有 HTML5 的媒体源扩展 MSE MSE 使用 blob URL 注入 标记 它看起来像这样 blob https www youtube com blahb
  • 了解 xargs 中的递归 grep

    以下两个命令之间有什么实际区别 命令A find type f print0 xargs 0 grep r masi 命令B find type f print0 xargs 0 grep masi 简而言之 命令 A 的实际好处是什么 N
  • 使用Python将文件加载到内存中

    我尝试使用以下命令将文件加载到内存中 import mmap with open path fileinput example txt rb as f fileinput mmap mmap f fileno 0 prot mmap PRO
  • Python Pandas 用户警告:由于非串联轴未对齐而进行排序

    我正在做一些代码练习并在执行此操作时应用数据帧合并 收到用户警告 usr lib64 python2 7 site packages pandas core frame py 6201 FutureWarning 由于非串联轴未对齐而进行排
  • python Flask如何将动态参数传递给装饰器

    我正在使用 python Flask 框架 我写了一个装饰器 它需要一个参数 并且这个参数将是动态的 我的装饰器如下所示 将获得一个密钥 并使用该密钥从 Redis 获取数据 def redis hash shop style key de
  • JOINed 表中的条件显示错误 CakePHP

    我有两张桌子employee personals存储员工的所有个人记录的地方telephone bills其中存储每月支付给特定员工的电话账单 现在在我的employeePersonalsController php我有一个函数叫做api
  • Excel、Vba 宏可将形状“移动”到不同的形状,无需复制和粘贴

    我想将形状移动到不同的工作表 而不在宏中使用复制和粘贴 还有其他方法可以做到这一点吗 如果形状是图表对象 您只需更改其位置即可 ActiveChart Location Where xlLocationAsObject Name Sheet
  • 我可以将编译的系统库(例如 libxml2)合并到可以部署到 Heroku 的 gem(例如 nokogiri)中吗?

    Nokogiri 在与 UTF 8 字符之间进行转换时遇到问题 结果发现该问题来自 libxml2 特别是版本 2 7 6 这是 Ubuntu 10 04 LTS 上支持的最高版本 该错误在 2 7 7 及更高版本中得到修复 但由于我们的应
  • 如何使用张量流和卷积神经网络检测和定位对象?

    我的问题陈述如下 使用 Tensorflow 和卷积神经网络进行对象检测和定位 我做了什么 我已经使用 tflearn 库完成了从图像中进行猫检测 我成功地使用 25000 张猫图像训练了一个模型 并且其工作良好且准确 Current Re
  • 日志记录挂钩的挂钩过程从未被调用

    我正在尝试创建一个简单的应用程序来记录和播放一系列键盘和鼠标命令 宏 阅读文档并得出结论 最合适的实现 如果不是唯一的实现 是设置 Windows 日志记录挂钩 WH JOURNALRECORD 并用日志回放一个 WH JOURNAL PL