From http://zerray.com/
Looking at the hooks in Win32 compilation, I was wondering how to write a whole-person program that changed the keyboard layout.
Check the information and find that the underlying keyboard hook (wh_keyboard_ll) can be implemented. First, install and uninstall the HOOK:
Installhook proc hins: DWORD
Invoke setwindowshookex, wh_keyboard_ll, ADDR keyproc, hins, null
MoV hhook, eax
RET
Installhook endp
Uninstallhook proc
Invoke unhookwindowshookex, hhook
RET
Uninstallhook endp
Like other hooks, In the callback function keyproc, The ncode value is hc_action, and wparam is the key message (wm_keydown, wm_keyup, wm_syskeydown, wm_syskeyup.
First, I want to capture the key X. in order to know whether the key is captured, I asked the program to bring up a dialog box when X is pressed.
Keyproc proc ncode: DWORD, wparam: wparam, lparam: lparam
. If ncode = hc_action
. If (wparam = wm_keydown)
MoV edX, lparam
Assume edX: PTR KBDLLHOOKSTRUCT
. If ([edX]. vkcode = vk_x)
Invoke MessageBox, null, ADDR szmsg, ADDR sztit, mb_ OK
. Endif
. Endif
. Endif
Invoke callnexthookex, hhook, ncode, wparam, lparam
RET
Keyproc endp
The program is very simple. when X is pressed, a dialog box is displayed. Click it and try again. OK! We have captured the buttons.
Now, how can I change the X button to another one? First try other programs to process the key message after our hook function: Change the invoke sentence in keyproc to ret. When you run the program, Press X, huh, and the X key is blocked. It seems that the priority of the hook function to process the key message is very high. If you change the message to another key, then it will change the key? Try it!
Keyproc proc ncode: DWORD, wparam: wparam, lparam: lparam
. If ncode = hc_action
. If (wparam = wm_keydown)
MoV edX, lparam
Assume edX: PTR KBDLLHOOKSTRUCT
. If ([edX]. vkcode = vk_x)
MoV [edX]. vkcode, vk_y
. Endif
. Endif
. Endif
Invoke callnexthookex, hhook, ncode, wparam, lparam
RET
Keyproc endp
I changed the vkcode to vk_y. Now the message from other programs should be Press Y? Run, Press X, strange, or X ?? Why? Do scancode also need to be changed ?? Check the scancode of vk_y and modify it. Isn't our program having the permission to modify the memory? How can I improve the permissions of a program? It's too troublesome. Think about other methods! Now that we can block a button, can we use keybd_event to simulate the button? Yes, that's it!
We now shield the keys X and Y, then simulate the keys y when the keys X, and simulate the keys X when the keys y, so that the keyboard positions of X and Y are changed.
Keyproc proc ncode: DWORD, wparam: wparam, lparam: lparam
. If ncode = hc_action
. If (wparam = wm_keydown)
MoV edX, lparam
Assume edX: PTR KBDLLHOOKSTRUCT
. If ([edX]. vkcode = vk_x)
Invoke keybd_event, vk_y, 0, 0, 0
RET
. Elseif ([edX]. vkcode = vk_y)
Invoke keybd_event, vk_x, 0, 0, 0
RET
. Endif
. Endif
. Endif
Invoke callnexthookex, hhook, ncode, wparam, lparam
RET
Keyproc endp
It should be okay this time, right? Run it! Oh, no, there is another problem. After pressing X or Y, the exchange of X and Y keeps changing, and the message is circulating? Yes, keys used for keybd_event simulation are captured by the underlying keyboard hook! What should we do? In fact, it is better to judge the scancode. The simulated key is different from the actual key scancode. Now the problem is completely solved! Add the wm_syskeydown judgment to make the change more thorough. The following is a complete program:
. 386
. Model flat, stdcall
Option Casemap: None
Include/masm32/include/Windows. inc
Include/masm32/include/kernel32.inc
Include/masm32/include/user32.inc
Includelib/masm32/lib/kernel32.lib
Includelib/masm32/lib/user32.lib
Winmain proto: DWORD,: DWORD
Installhook proto: DWORD
Uninstallhook proto
Hotkeyid1 equ 1
Hotkeyid2 equ 2
KBDLLHOOKSTRUCT struct
Vkcode DWORD?
Scancode DWORD?
Flags DWORD?
Time DWORD?
Dwextrainfo ulong?
KBDLLHOOKSTRUCT ends
. Const
Classname dB 'hookxclass', 0
Appname dB 'hookx', 0
Running dB 'I am running...', 0
. Data?
Inst dd?
Hhook dd?
CMD dd?
. Code
Start:
Invoke getmodulehandle, null
MoV inst, eax
Invoke getcommandline
MoV cmd, eax
Invoke winmain, inst, null, CMD, sw_hide; the whole-person program, of course, cannot display the window!
Invoke exitprocess, eax
Winmain proc hinst: hinstance, hprevinst: hinstance, using line: lpstr, cmdshow: DWORD
Local WC: wndclassex
Local MSG: msg
Local hwnd: hwnd
MoV WC. cbsize, sizeof wndclassex
MoV WC. style, cs_hredraw or cs_vredraw
MoV WC. lpfnwndproc, offset wndproc
MoV WC. cbclsextra, null
MoV WC. cbwndextra, null
Push hinst
Pop WC. hinstance
MoV WC. hbrbackground, color_window + 1
MoV WC. lpszmenuname, null
MoV WC. lpszclassname, offset classname
Invoke loadicon, null, idi_application
MoV WC. hicon, eax
MoV WC. hiconsm, eax
Invoke loadcursor, null, idc_arrow
MoV WC. hcursor, eax
Invoke registerclassex, ADDR WC
Invoke createmediawex, null ,/
ADDR classname ,/
ADDR appname ,/
Ws_overlappedwindow ,/
Cw_usedefault ,/
Cw_usedefault ,/
Cw_usedefault ,/
Cw_usedefault ,/
Null ,/
Null ,/
Hinst ,/
Null
MoV hwnd, eax
Invoke showwindow, hwnd, cmdshow
Invoke updatewindow, hwnd
. While true
Invoke getmessage, addr msg, null, 0, 0
. Break. If (! Eax)
Invoke translatemessage, ADDR msg
Invoke dispatchmessage, ADDR msg
. Endw
MoV eax, MSG. wparam
RET
Winmain endp
Wndproc proc hwnd: hwnd, umsg: uint, wparam: wparam, lparam: lparam
. If umsg = wm_create
Invoke installhook, Inst
Invoke registerhotkey, hwnd, hotkeyid1, mod_alt, vk_8; register two shortcut keys to view the program running and closing the program
Invoke registerhotkey, hwnd, hotkeyid2, mod_alt, vk_9
. Elseif umsg = wm_hotkey
. If wparam = hotkeyid1
Invoke MessageBox, null, ADDR running, ADDR appname, mb_ OK
. Elseif wparam = hotkeyid2
Invoke uninstallhook
Invoke postmessage, hwnd, wm_destroy, null, null
. Endif
. Elseif umsg = wm_destroy
Invoke unregisterhotkey, hwnd, hotkeyid2
Invoke unregisterhotkey, hwnd, hotkeyid1
Invoke uninstallhook
Invoke postquitmessage, null
. Else
Invoke defwindowproc, hwnd, umsg, wparam, lparam
RET
. Endif
XOR eax, eax
RET
Wndproc endp
Keyproc proc ncode: DWORD, wparam: wparam, lparam: lparam
. If ncode = hc_action
. If (wparam = wm_keydown) | (wparam = wm_syskeydown)
MoV edX, lparam
Assume edX: PTR KBDLLHOOKSTRUCT
. If ([edX]. vkcode = vk_x) & ([edX]. scancode! = 0)
Invoke keybd_event, vk_y, 0, 0, 0
RET
. Elseif ([edX]. vkcode = vk_y) & ([edX]. scancode! = 0)
Invoke keybd_event, vk_x, 0, 0, 0
RET
. Endif
. Endif
. Endif
Invoke callnexthookex, hhook, ncode, wparam, lparam
RET
Keyproc endp
Installhook proc hins: DWORD
Invoke setwindowshookex, wh_keyboard_ll, ADDR keyproc, hins, null
MoV hhook, eax
RET
Installhook endp
Uninstallhook proc
Invoke unhookwindowshookex, hhook
RET
Uninstallhook endp
End start
Now, I can secretly put this program on a classmate's machine to run it.
, Why? What's wrong with my keyboard?