Visualbasic 6.0 SetWindowsHookEx를 이용한 시스템 후킹
[6.0] SetWindowsHookEx를 이용한 시스템 후킹 - 1. 키보드
Windows에서는 마우스나 키보드같은 GUI 입력을 이용하여 대화 상자와 대화할 수 있고,
마우스나 키보드 같은 입력을 컨트롤하는 API도 지원합니다. 대표적으로 아래와 같은 API가 있습니다.
저수준
- mouse_event (마우스 입력을 발생시켜주는 API)
- keybd_event (키보드 입력을 발생시켜주는 API)
- SendInput (마우스나 키보드 입력을 보내주는 API)
고수준
- BlockInput (마우스나 키보드 입력을 차단하는 API)
- SetCursorPos (커서의 좌표를 설정하는 API)
- SendKeys (마우스나 키보드 입력을 지시하는 VB 내장함수)
(VB의 SendKeys는 WH_JOURNALPLAYBACK 훅을 이용해서 입력을 만든다.)
그렇다면, SetWindowsHookEx는 무엇을 하는 API일까요? 이 API는 윈도우를 만든 MS가 프로그래머에게 준
고귀한 선물 이라고 할 수 있는데, 시스템을 전역적으로 후킹할 수 있는 API라고 보시면 됩니다.
우선 이 API는 아래와 같은 후킹 방법을 제공합니다.
WH_CALLWNDPROC
WH_CBT
WH_DEBUG
WH_FOREGROUNDIDLE
WH_GETMESSAGE
WH_KEYBOARD
WH_KEYBOARD_LL
WH_MOUSE
WH_MOUSE_LL
WH_JOURNALRECORD
WH_JOURNALPLAYBACK
WH_MSGFILTER
WH_SHELL
...
여기서 눈여겨 볼것은 WH_KEYBOARD 와 WH_KEYBOARD_LL 입니다.
이번 강좌에서는 WH_KEYBOARD_LL 후크를 이용해서 시스템의 키 입력을 가장 먼저
가로채서 '키 입력을 무시하거나..', '키 눌림을 감지하는 키로거 등...' 활용할 수 있는 기초적인
방법을 소개해드리겠습니다. (이 방법은 Win 2000/XP 이상에서만 사용 가능합니다.)
SetWindowsHookEx의 선언문은 아래와 같습니다.
Public Declare Function SetWindowsHookEx Lib "user32.dll" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
- idHook: 후크의 종류 (WH_XXX)
- lpfn: 후킹 프로시저(함수)의 주소값(AddressOf XXX)
- hmod: App.hInstance 의 값
- dwThreadId: App.ThreadID 의 값. (후크의 종류에 따라 이것은 넣지 않을수도 있다.)
- 반환값: 후킹의 핸들 (HHOOK) 32-bit 정수 (0 이면 실패)
이런 후킹을 해제하는 함수는 아래와 같습니다.
- UnhookWindowsHookEx
Public Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hHook As Long) As Long
- hHook: SetWindowsHookEx에서 반환했던 후크의 핸들
- 반환값이 0이면 실패이다.
후크의 종류에 따라 lpfn에 들어가는 함수의 주소값의 함수 선언은 달라질 수 있습니다.
WH_KEYBOARD_LL에 대응하는 후크 프로시져는 아래와 같습니다.
LRESULT CALLBACK LowLevelKeyboardProc(
int nCode,
WPARAM wParam,
LPARAM lParam
);
이를 비주얼 베이직 함수 형태로 고치면..
Public Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
....
End Function
형태가 됩니다. (p.s: 이런 함수는 주소값을 구해야하므로 폼이나 클래스 모듈이 아닌 '모듈'에 선언해야합니다.)
MSDN에 의하면
-----------------------------------------//
Parameters
nCode
[in] Specifies a code the hook procedure uses to determine how to process the message. If nCode is less than zero, the hook procedure must pass the message to the :Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl05',this);" href="http://msdn2.microsoft.com/en-us/library/ms644974(VS.85).aspx">CallNextHookEx function without further processing and should return the value returned by CallNextHookEx. This parameter can be one of the following values.
HC_ACTION
The wParam and lParam parameters contain information about a keyboard message.
wParam
[in] Specifies the identifier of the keyboard message. This parameter can be one of the following messages: :Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl06',this);" href="http://msdn2.microsoft.com/en-us/library/ms646280(VS.85).aspx">WM_KEYDOWN, :Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl07',this);" href="http://msdn2.microsoft.com/en-us/library/ms646281(VS.85).aspx">WM_KEYUP, :Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl08',this);" href="http://msdn2.microsoft.com/en-us/library/ms646286(VS.85).aspx">WM_SYSKEYDOWN, or :Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl09',this);" href="http://msdn2.microsoft.com/en-us/library/ms646287(VS.85).aspx">WM_SYSKEYUP.
lParam
[in] Pointer to a :Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl10',this);" href="http://msdn2.microsoft.com/en-us/library/ms644967(VS.85).aspx">KBDLLHOOKSTRUCT structure.
-----------------------------------------//
이렇게 나와있습니다. 'nCode는 메시지를 처리할 방법' 을 말한다는것 같고, wParam는 이 프로시저가
어떠한 키 눌림조작에 의해 실행되었는지를 나타냅니다. (4개중에 하나),
lParam는 'KBDLLHOOKSTRUCT' 구조체의 포인터(메모리 주소값)가 대입된다고 합니다.
- 참고로 KBDLLHOOKSTRUCT는 아래와 같은 구조체입니다.
Public Type KBDLLHOOKSTRUCT
vkCode As Long ' VK_XXX 키 코드
scanCode As Long ' 하드웨어 스캔 코드
flags As Long
time As Long
pdwExtraInfo As Long
End Type
그리고, 해당 키 입력이 유효하지 않게 하려면(다른 훅이 키보드 입력을 받지 못하게 방지하는 기능도 합니다)
후크 프로시저에서 0이 아닌 값을 반환하면 되고,
유효하게 하려면 CallNextHookEx를 호출해 그 반환값을 돌려줘야한다고 MSDN에 써있습니다.
(CallNextHookEx는 아래와 같은 api입니다)
Public Declare Function CallNextHookEx Lib "user32.dll" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
그럼 이것을 참고로 하여 A 키와 B 키를 서로 바꿔주는 프로그램을 한번 코딩해봅시다.
아래에 나오는 코드는 모두 모듈에 넣어주시면 됩니다.
Public Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Public Declare Function SetWindowsHookEx Lib "user32.dll" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hHook As Long) As Long
Public Declare Function CallNextHookEx Lib "user32.dll" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Public Const WH_KEYBOARD_LL As Long = 13
Public Const WM_KEYDOWN As Long = &H100
Public Const WM_KEYUP As Long = &H101
Public Type KBDLLHOOKSTRUCT
vkCode As Long ' VK_XXX 키 코드
scanCode As Long ' 하드웨어 스캔 코드
flags As Long
time As Long
dwExtraInfo As Long ' 부가 정보 (keybd_event의 4번째 인자)
End Type
Private hHook As Long
Sub Main()
' 후킹 프로시저 설치!
MsgBox "후킹 프로시저를 설치합니다."
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0)
If hHook = 0 Then
MsgBox "후킹 프로시저를 설치할 수 없었습니다."
End
End If
MsgBox "후킹 프로시저가 동작중입니다. [확인]을 누르면 제거됩니다."
If UnhookWindowsHookEx(hHook) = 0 Then
MsgBox "후킹 프로시저를 제거할 수 없었습니다."
End
End If
MsgBox "후킹 프로시저가 제거되었습니다."
End Sub
Public Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, lParam As KBDLLHOOKSTRUCT) As Long
If nCode < 0 Then GoTo Finalize
If lParam.dwExtraInfo = 33 Then GoTo Finalize ' 33은 그냥 정한 숫자
If wParam = WM_KEYDOWN Or wParam = WM_KEYUP Then
If lParam.vkCode = vbKeyA Then
keybd_event vbKeyB, 0, IIf(wParam = WM_KEYUP, 2, 0), 33
LowLevelKeyboardProc = 1
Exit Function
End If
If lParam.vkCode = vbKeyB Then
keybd_event vbKeyA, 0, IIf(wParam = WM_KEYUP, 2, 0), 33
LowLevelKeyboardProc = 1
Exit Function
End If
End If
Finalize:
LowLevelKeyboardProc = CallNextHookEx(hHook, nCode, wParam, lParam)
End Function
이 코드에 대한 설명은 다음에 하겠습니다.
'scrap > Visual Basic' 카테고리의 다른 글
Visualbasic Delay() (1) | 2011.02.04 |
---|---|
[vb] SendKeys 함수가 먹히지 않는 곳에서의 key event (1) | 2011.02.04 |
비주얼 베이직 으로 사이트내 특정 위치에서 마우스 클릭 프로그램 (1) | 2011.02.04 |
visualbasic 외부파일 연결 (0) | 2011.02.04 |
visual basic 으로 cpu 점유율 100% 만들기 (0) | 2011.02.04 |