win32汇编 钩子的编写与使用
来源:互联网 发布:java程序员接私活经验 编辑:程序博客网 时间:2024/05/22 03:10
说到钩子也许我们都很陌生(我以前从来没有接触过这个东西。。。),但是说到木马程序记录你的键盘信息,盗取账号密码等信息这种事情,我们应该很清楚, 其实钩子实现的功能就是这样,windows操作系统是以消息机制为基础的,钩子:WIN32API手册中这样描述--钩子是windows的消息处理机制中的一个监视点,应用程序可以在这里安装一个监视子程序,这样就可以在系统中的消息流到达目的窗口过程前监控它们。(其实钩子就是监视某种消息,当收到这种消息的时候,钩子会将这种消息拦截并根据自己的回调函数将不同的消息进行不同的处理,然后将处理结果直接以自定义的消息发送到监视进程的窗口过程中进行消息处理)
这样的解释也许会和DOS中拦截中断信息的操作相混淆(对于这种情况我只想说:不要想太多,在如今windows的保护模式下不可能再做那种为所欲为的事了),钩子可以分为局部和远程的,按照字面上的意思我们也应该可以猜到,局部钩子只限于自身进程内(也就是说局部钩子只能挂钩自身的进程,需要指定自身进程的中某个线程的ID号,也许只有一个线程)。远程钩子就显而易见了,它监视的是自身和其它进程(也就是说它可以包含局部钩子),钩子也必须依赖一个主程序(这个程序的进程也可以是后台进程,远程钩子的回调函数必须放在DLL文件中,当监视其他程序的的进程的时候,钩子监视的是消息,当某个程序收到这个消息的时候,就会调用钩子,就会在本程序的进程中安装钩子,此时必须调用钩子函数,因为进程间的地址空间是隔离的,所以钩子必须位于DLL文件中才可以被其他程序调用)本次例子中就是建立的一个全局钩子来监视键盘消息(WH_KEYBOARD类型),来记录键盘输入的信息,然后在建立的一个对话框的窗口过程中处理自定义消息WM_HOOK,将记录的信息显示在编辑文本框中。这就是本次程序的功能。
下面就来看一下钩子的实现过程。
首先是主程序资源文件:
首先看一下主程序的资源文件:
依然使用的是ResEdit工具,资源文件包含3部分 一个对话框,一个29字样的图标,一个可以输入文字的文本编辑框,这部分没有什么大问题,注意在使用此工具时在对话框的风格中一般会被加上WS_SHELLFONT这个风格,由于不支持,在使用RadASM工具编译的时候会出现无法识别这个风格的问题,以前也遇见过,对此我采取的措施是直接将这个没有什么用途的风格直去掉,然后一切OK。下面来看一下资源文件代码:
// Generated by ResEdit 1.6.6// Copyright (C) 2006-2015// http://www.resedit.net#include <windows.h>#include <commctrl.h>#include <richedit.h>#include "resource.h"//// Dialog resources//LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRALIDD_DIALOG1 DIALOG 0, 0, 279, 159STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENUCAPTION "键盘钩子"FONT 8, "Ms Shell Dlg"{ EDITTEXT IDC_TEXT, 11, 10, 244, 128, WS_VSCROLL | WS_SIZEBOX | ES_AUTOHSCROLL | ES_MULTILINE | ES_READONLY, WS_EX_LEFT}//// Icon resources//LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRALIDI_ICON2 ICON "icon2.ico"
下面来看一下DLL文件的编写,DLL文件的格式注意,一定要有入口函数以及结尾标记。编写DLL文件遇见了一个问题那就是 在编写完代码29.asm和定义文件29.def之后,编译连接构建生成DLL文件(29.dll)以及29.inc
29.lib (后面这两个文件需要在主程序代码中用到,也就是主程序中的头文件include 29.inc includelib 29.lib,用来包含DLL文件中的功能函数的,这样就可以在主程序中直接使用DLL文件中的相关函数了),但是构建生成的文件29.inc其实是个空的文本,里面什么内容都没有,是需要自己写入的,不写入的话,在主程序编译的时候会出现未定义的函数的错误,在本次的程序中29.inc文件的内容如下:
HookProc proto _dwCode:dword,_wParam:dword,_lParam:dword
InstallHook proto _hWnd:dword,_dwMessage:dword
UninstallHook proto
这个也是我根据上一次编写DLL文件时在书上看到的书写格式,如上使用的是一个 proto 后面的跟的是函数的各个参数名称(这个跟DLL文件中的函数的参数的名称一样)还要指定参数的类型,各个参数之间用冒号隔开。这其实就是个函数声明(我在网上查的是这样说的,我感觉也就是那个意思,就是声明一下这个函数)。
还有一个问题就是全局钩子的DLL文件要求共享数据段,在本程序中共享的就是.data?段 这个段在可执行文件中的节区名称是.bss,所以在用LINK.EXE进行连接的时候需要更改一下连接选项:
/subsystem:windows /Dll /section:.bss,S 其实就是在后面加上/section:.bss,S 选项就是共享.data?段的意思,详细的可以查阅LINK.EXE的参数。在编写上面的DLL文件的时候,不是使用RadASM工具编写的,只是资源文件用RadASM编译,为啥呢? 因为我在配置RadASM的 masm.ini中的makefile文件或者是RadASM中的工程-->工程选项中的“连接”那一栏的,加入上面的连接选项,但是改过之后使用RadASM连接的时候会出现错误,找不到一些文件,搞了很久也没有解决这个问题,最后我还是果断使用黑框了(就是NMAKE 工具 这个还需要自己编写MAKEFILE文件,而且还得编写批处理文件设置路径,很麻烦),使用这个方式可以编译好,但是RadASM的我实在搞不出来,求破。
下面看一下DLL代码:
.386 .model flat,stdcall option casemap:none include windows.incinclude user32.incincludelib user32.libinclude kernel32.incincludelib kernel32.lib .datahInstance dd ? .data?hWnd dd ?hHook dd ?dwMessage dd ?szAscii dd 4 dup(?) .codeDllEntry proc _hInstance,_dwReason,_dwReserved push _hInstance pop hInstance mov eax,TRUE retDllEntry endpHookProc proc _dwCode,_wParam,_lParam LOCAL @szKeyState[256]:byte invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam invoke GetKeyboardState,addr @szKeyState invoke GetKeyState,VK_SHIFT mov @szKeyState + VK_SHIFT,al mov ecx,_lParam shr ecx,16 invoke ToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0 mov byte ptr szAscii [eax],0 invoke SendMessage,hWnd,dwMessage,dword ptr szAscii,NULL xor eax,eax retHookProc endpInstallHook proc _hWnd,_dwMessage push _hWnd pop hWnd push _dwMessage pop dwMessage invoke SetWindowsHookEx,WH_KEYBOARD,addr HookProc,hInstance,NULL mov hHook,eax retInstallHook endpUninstallHook proc invoke UnhookWindowsHookEx,hHook retUninstallHook endp end DllEntry29.def文件如下:EXPORTS HookProc InstallHook UninstallHook下面来看一下主程序:主程序中只包含了一个处理消息的窗口过程,需要注意的就是WM_HOOK这个自定义的消息,windows的ID值在WM_USER以后的值都可以由用户使用,所以说,在此后的ID之中都可以定义自定义的消息。代码如下: .386 .model flat,stdcall option casemap :none include windows.incinclude user32.incincludelib user32.libinclude kernel32.incincludelib kernel32.libinclude 29.incincludelib 29.libIDI_ICON2 equ 101IDD_DIALOG1 equ 102IDC_TEXT equ 40000WM_HOOK equ WM_USER + 100h .code_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam LOCAL @dwTemp mov eax,wMsg .if eax == WM_CLOSE invoke UninstallHook invoke EndDialog,hWnd,NULL .elseif eax == WM_INITDIALOG invoke InstallHook,hWnd,WM_HOOK .if ! eax invoke EndDialog,hWnd,NULL .endif .elseif eax == WM_HOOK ;注意此处的自定义的消息的处理 mov eax,wParam .if al == 0dh mov eax,0a0dh .endif mov @dwTemp,eax invoke SendDlgItemMessage,hWnd,IDC_TEXT,EM_REPLACESEL,0,addr @dwTemp .else mov eax,FALSE ret .endif mov eax,TRUE ret_ProcDlgMain endpstart: invoke GetModuleHandle,NULL invoke DialogBoxParam,eax,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL invoke ExitProcess,NULL end start
下面来看一下API函数:
CallNextHookEx()
功能:
可以将钩子信息传递到当前钩子链中的下一个子程序,一个钩子程序可以调用这个函数之前或之后处理钩子信息。
原型:
LRESULT WINAPI CallNextHookEx( _In_opt_ HHOOK hhk, _In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam);
参数:
1. hhk[可选]
说明:当前钩子的句柄
类型:HHOOK
此参数将被忽略。
2. nCode [in]
说明:钩子代码; 就是给下一个钩子要交待的
类型:INT
钩传递给当前Hook过程的代码。下一个钩子程序使用此代码,以确定如何处理钩的信息。
3. wParam[in]
说明:要传递的参数; 由钩子类型决定是什么参数
类型:WPARAM
wParam参数值传递给当前Hook过程。此参数的含义取决于当前的钩链与钩的类型。
4. lParam[in]
说明:要传递的参数; 由钩子类型决定是什么参数
类型:LPARAM
lParam的值传递给当前Hook过程。此参数的含义取决于当前的钩链与钩的类型
1. 类型:LRESULT
2. 返回这个值链中的下一个钩子程序。当前Hook过程也必须返回该值。返回值的含义取决于钩型。有关详细信息,请参阅个人钩子程序的描述
GetKeyboardState()
功能:
该函数将256个虚拟键的状态拷贝到指定的缓冲区中。
参数:
IpKeyState:指向一个256字节的数组,数组用于接收每个虚拟键的状态。
GetKeyState()
功能:
该函数检取指定虚拟键的状态。该状态指定此键是UP状态,DOWN状态,还是被触发的(开关每次按下此键时进行切换)。
原型:
SHORT GetKeyState(int nVirtKey);
参数:
nVrtKey:定义一虚拟键。若要求的虚拟键是字母或数字(A~Z,a~z或0~9),nVirtKey必须被置为相应字符的ASCII码值,对于其他的键,nVirtKey必须是一虚拟键码。
返回值:
例子:
::GetKeyState(VK_SHIFT) > 0 没按下
::GetKeyState(VK_SHIFT) < 0被按下
返回值给出了给定虚拟键的状态,状态如下:
若高序位为1,则键处于DOWN状态,否则为UP状态。
若低序位为1,则键被触发。例如CAPS LOCK键,被找开时将被触发。若低序位置为0,则键被关闭,且不被触发。触发键在键盘上的指示灯,当键被触发时即亮,键不被触发时即灭
ToAscii()
功能:
该函数将指定的虚拟键码和键盘状态翻译为相应的字符或字符串。该函数使用由给定的键盘布局句柄标识的物理键盘布局和输入语言来翻译代码。
原型:
int ToAscii(UINT uVirtKey,UINT uScanCode,PBYTE lpKeyState,LPWORD lpChar,UINT uFlags);
参数:
nVirtkey:指定要翻译的虚拟键码。
uScanCode:定义被翻译键的硬件扫描码。若该键处于up状态,则该值的最高位被设置。
LpKeyState:指向包含当前键盘状态的一个256字节数组。数组的每个成员包含一个键的状态。若某字节的最高位被设置,则该键处于down状态。若最低位被设置,则表明该键被触发。在此函数中,仅有capslock键的触发位是相关的。NumloCk和scroll loCk键的触发状态将被忽略。
LpChar:指向接受翻译所得字符或字符串的缓冲区。
UFlags:定义一个菜单是否处于激活状态。若一菜单是活动的,则该参数为1,否则为0
返回值:若定义的键为死键,则返回值为负值。否则,返回值应为如下的值:
O:对于当前键盘状态,所定义的虚拟键没有翻译。
1:一个字符被拷贝到缓冲区。
2:两个字符被拷贝到缓冲区。当一个存储在键盘布局中的死键(重音或双音字符)无法与所定义的虚拟键形成一个单字符时,通常会返回该值。
功能:
把一个应用程序定义的钩子安装到钩子链表中
参数原型:
HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,即它处理的消息类型
HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
// 或是一个由别的进程创建的线程的标识,
// lpfn必须指向DLL中的钩子。
// 除此以外,lpfn可以指向当前进程的一段钩子子程代码。
// 钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程的DLL。
// 如果dwThreadId 标识当前进程创建的一个线程,
// 而且子程代码位于当前进程,hMod必须为NULL。
// 可以很简单的设定其为本应用程序的实例句柄。
DWORD dwThreadId // 与安装的钩子相关联的线程的标识符。
// 如果为0,钩子与所有的线程关联,即为全局钩子。);
返回值:函数成功则返回钩子的句柄,失败返回NULL。
功能:
卸载安装的钩子
原型:
BOOL WINAPI UnhookWindowsHookEx( __in HHOOK hhk);
参数:
类型: HHOOK
要删除的钩子的句柄。这个参数是上一个函数SetWindowsHookEx的返回值.
返回值:类型: BOOL
如果函数成功,返回值为非零值。
如果函数失败,返回值为零。 要获得更多的错误信息,调用GetLastError函数.
- win32汇编 钩子的编写与使用
- win32汇编动态链接库的编写及使用
- Win32汇编——钩子
- win32汇编头文件的编写注意
- WIN32汇编对话框的使用
- WIN32汇编定时器的使用
- WIN32汇编 状态栏的使用
- WIN32 汇编 工具栏的使用
- WIN32汇编: 24.WINDOWS钩子函数
- Win32环境下代码注入与API钩子的实现
- Win32环境下代码注入与API钩子的实现
- Win32环境下代码注入与API钩子的实现
- Win32环境下代码注入与API钩子的实现
- Win32环境下代码注入与API钩子的实现
- Win32汇编教程四 编写一个简单的窗口
- Win32汇编教程四:编写一个简单的窗口
- 用WIN32汇编写的超简单钩子(初学者适用)
- WIN32汇编列表框的使用
- ACdream 1195 判断数独棋盘是否合法
- 经典重拾-第一部分 语言篇 第一章 程序设计入门
- liunx关闭weblogic 启动tomcat
- 服务器建立redis服务傻瓜教程
- 银河U1 VB 真空烧 + 银河北斗 + 锐科特小蓝火
- win32汇编 钩子的编写与使用
- poj3258 River Hopscotch(二分)
- eclipse启动tomcat的根目录
- JBO-27023: 无法验证事务处理中的所有行。
- 公共基础-CodeReview
- content-type
- Windows下MySql错误代码1045的解决方法
- Android手机通过wifi进行数据传输(二)
- oracle 11gR2RAC修改public ip (同网段)