gpt4 book ai didi

c++ - Spy++ 显示错误结果?

转载 作者:可可西里 更新时间:2023-11-01 16:07:13 47 4
gpt4 key购买 nike

我创建了一个简单的 Unicode 窗口,我按下键盘上的一个键以查看 WM_CHAR 消息的 wParam 值是多少,它给了我预期的字符的 Unicode 代码点,我按下了'S' 键,我的键盘布局设置为阿拉伯语(因此阿拉伯语字符为 'س')。

现在,我还捕获了 Spy++ 中的窗口消息,但我注意到它为我提供了错误的 wParam 值,它实际上为我提供了 Windows 中字符代码的值:阿拉伯语代码页!

这是结果的截图:

enter image description here

这是源代码:

#define UNICODE

#include <Windows.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CHAR:
char str[256];
sprintf(str, "0x%.4x", wParam);
MessageBoxA(NULL, str, "", 0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);

HWND hWnd = CreateWindowEx(0, L"WinClass", L"My Title", WS_OVERLAPPEDWINDOW, 261, 172, 594, 384, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

最佳答案

Spy++ 的工作原理是一个公开的 secret ,当您在 .exe 文件上运行 Dumpbin.exe/imports 时,您可以很容易地知道。对于 spyxx_amd64.exe(64 位版本),最相关的条目是:

SPYXXHK_AMD64.DLL
...
3 SpyxxCallWndRetProc
2 SpyxxCallWndProc
4 SpyxxGetMsgProc
USER32.dll
...
320 SetWindowsHookExW
31F SetWindowsHookExA

换句话说,它使用 SetWindowsHookEx() 来设置 3 个 Hook ,WH_CALLWNDPROC、WH_CALLWNDPROCRET 和 WH_GETMESSAGE。 Spyxxhk_amd64.dll 是注入(inject)到每个进程的 DLL,它包含钩子(Hook)回调。

请注意,它同时使用了 Unicode 和 Ansi 版本的 SetWindowsHookEx()。可以轻松解释结果的一种方法是在 Unicode 窗口上使用 Ansi 版本 (SetWindowsHookExA)。这样的钩子(Hook)只能观察到 WM_CHAR 消息的 Ansi 版本。

请记住,当您在包含 Unicode 和 Ansi 窗口的桌面上运行进程时,Spy++ 有一个无法解决的问题,这种情况并不少见,它无法让所有人都满意。最简单的假设是它只是将 SetWindowsHookExA 作为最低公分母。

实际上,证明 Spy++ 弄错了要困难得多,我为此努力了很长时间。任何试图捕捉 Spy++ 在使用它时安装钩子(Hook)的尝试都被证明是失败的,钩子(Hook)在程序启动时很早就安装了。我最终发现的调试技术:

  • 我首先通过反汇编 SetWindowsHookExW 的代码找到了 native api 入口点 NtUserSetWindowHookEx。在我的机器 (Win8.1) 上,它位于 0x00007FFECC3BA970。
  • 启动 VS 提升,需要启动 Spy++。
  • 文件 + 打开 + 项目/解决方案并选择 Spyxx_amd64.exe。
  • 调试 + 进入。这将启动程序并将执行点定位在 AfxWinMain(Spy++ 是使用 MFC 库编写的)。
  • 调试+Windows+反汇编,将0x00007FFECC3BA970粘贴到地址栏
  • 在此地址设置断点。按 F5

有两个误命中,MFC内部使用了SetWindowsHookExW()。但随后它亮了起来,三个看起来都与此相似的点击:

user32.dll!NtUserSetWindowsHookEx()     
user32.dll!_SetWindowsHookEx() + 0x5b bytes
user32.dll!SetWindowsHookExAW() + 0x5b bytes
user32.dll!SetWindowsHookExA() + 0x11 bytes
spyxx_amd64.exe!SetMsgHook() + 0x6a bytes
spyxx_amd64.exe!HookMain() + 0x470 bytes
msvcr120.dll!_callthreadstart() Line 257 C
msvcr120.dll!_threadstart(void * ptd) Line 237 + 0x5 bytes C
kernel32.dll!BaseThreadInitThunk() + 0xd bytes
ntdll.dll!RtlUserThreadStart() + 0x34 bytes

这就是证据,您可以看到调用了 SetWindowsHookExA()。 Ansi 版本,Spy++ 只能显示 WM_CHAR 消息的 Ansi 版本。

关于c++ - Spy++ 显示错误结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26748851/

47 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com