间谍++显示错误的结果?

 xi曦 发布于 2022-12-13 09:14

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

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

这是结果的截图:

在此输入图像描述

这是源代码:

#define UNICODE

#include 
#include 

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;
}

Hans Passant.. 8

Spy ++的工作方式有点公开,您可以轻松判断何时运行Dumpbin.exe /imports.exe文件.对于spyxx_amd64.exe(64位版本),最相关的条目是:

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

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

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

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

实际上证明 Spy ++得到了这个错误是很难做到的,而且我已经相当长一段时间了.任何试图在使用它时捕获Spy ++安装钩子的尝试都是一个破坏,钩子在程序启动时很早就安装好了.我最终发现的调试技术:

我首先NtUserSetWindowHookEx通过反汇编SetWindowsHookExW的代码来找到本机api入口点.在我的机器(Win8.1)上,它位于0x00007FFECC3BA970.

启动VS提升,需要启动Spy ++.

文件+打开+项目/解决方案,然后选择Spyxx_amd64.exe.

Debug + Step Into.这将启动程序并在AfxWinMain中找到执行点(Spy ++是使用MFC库编写的).

Debug + Windows + Disassembly,将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版本.

1 个回答
  • Spy ++的工作方式有点公开,您可以轻松判断何时运行Dumpbin.exe /imports.exe文件.对于spyxx_amd64.exe(64位版本),最相关的条目是:

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

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

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

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

    实际上证明 Spy ++得到了这个错误是很难做到的,而且我已经相当长一段时间了.任何试图在使用它时捕获Spy ++安装钩子的尝试都是一个破坏,钩子在程序启动时很早就安装好了.我最终发现的调试技术:

    我首先NtUserSetWindowHookEx通过反汇编SetWindowsHookExW的代码来找到本机api入口点.在我的机器(Win8.1)上,它位于0x00007FFECC3BA970.

    启动VS提升,需要启动Spy ++.

    文件+打开+项目/解决方案,然后选择Spyxx_amd64.exe.

    Debug + Step Into.这将启动程序并在AfxWinMain中找到执行点(Spy ++是使用MFC库编写的).

    Debug + Windows + Disassembly,将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版本.

    2022-12-13 09:18 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有