hook ImmGetCompositionString进行中文记录出错求助(已解决)
本帖最后由 gto250 于 2010-9-9 11:04 编辑一个半成品的中文键盘记录,记事本程序的中文记录,用的是P版的hook api
对ImmGetCompositionString进行hook
LONG ImmGetCompositionStringA LPVOID lpBuf (
__in HIMC hIMC,
__in DWORD dwIndex,
__outLPVOID lpBuf,
__in DWORD dwBufLen
);
我在网上看到的文章是只要dwIndex=0x0800dwBufLen不为空就可以获取lpBuf
lpBuf就是字符串。我用的输入法是搜狗输入法,不管我输入的是什么字,获取到的lpBuf都是0x0012F96C
不知道哪里出错了,请指正
#include <RTApiHook32.au3>
$hCallBack = DllCallbackRegister("_ApiHookCallBack", "dword", "handle;ptr")
$pCallBack = DllCallbackGetPtr($hCallBack)
$hProcess = _RTOpenProcess("notepad.exe")
$immA = _RTGetProcAddress("imm32.dll", "ImmGetCompositionStringA")
$immW = _RTGetProcAddress("imm32.dll", "ImmGetCompositionStringW")
$tHookimmA = _RTApiHookEx($hProcess, $immA, 4, $pCallBack, $APIHOOK_Flags_Default)
$tHookimmW = _RTApiHookEx($hProcess, $immW, 4, $pCallBack, $APIHOOK_Flags_Default)
HotKeySet("^{f5}", "_Close")
OnAutoItExitRegister("_Close")
While 1
Sleep(100)
WEnd
Func _ApiHookCallBack($hProcess, $pCallInfo)
Switch _RTApiHookReadProcedure($hProcess, $pCallInfo)
Case $tHookimmA
$dwIndex = _RTApiHookReadParam($hProcess, $pCallInfo, 2)
$dwBufLen = _RTApiHookReadParam($hProcess, $pCallInfo, 4)
$Buffer = _RTApiHookReadParam($hProcess, $pCallInfo, 3)
MsgBox(0, $dwBufLen, $Buffer)
Case $tHookimmW
EndSwitch
EndFunc ;==>_ApiHookCallBack
Func _Close()
_RTApiUnhook($hProcess, $immA, DllStructGetData($tHookimmA, 6))
_RTApiUnhook($hProcess, $immW, DllStructGetData($tHookimmW, 6))
Exit
EndFunc ;==>_Close
把代码整理好就跟你说,格式缩进还有空行等等。 好了!{:face (394):} LPVOID lpBuf是个字符串指针,你读出lpBuf的值都是0x0012F96C是对的,这个地址里存放的就是你想获取的字符串。
所有的字符串参数都是这样的,不能直接传递字符串,而是先将字符串放入一个缓存区中,然后将缓存区的地址作为参数传递给函数。
另外_RTApiHookReadProcedure($hProcess, $pCallInfo)返回的是一个HOOK实例所挂钩的系统函数地址,而非tHookimmA结构,应该改成:Switch _RTApiHookReadProcedure($hProcess, $pCallInfo)
Case $pImmA
;;;
Case $pImmW
;;;
EndSwitch另外所有有两个版本的函数(unicode、ansi),只需要挂钩UNICODE版本的就行了,因为Ansi版本的函数大多是通过MultiByteToWideChar将ANSI字符串转换为UNICODE之后再调用UNICODE版本的函数的。当然也有一些双版本的函数不是这样,但上例中的ImmGetCompositionString,只需要挂钩ImmGetCompositionStringW就行了。
另外最初调用_RTApiHookEx挂钩函数的时候,使用$APIHOOK_Flags_Default是错误的,这个标识的含义是在调用系统函数之前通知回调函数,一些函数你若想取得它的返回信息,必须在调用完成之后截取它。
用$APIHOOK_Flags_2(在调用完成但仍没有返回时调用回调函数)代替。
#include <RTApiHook32.au3>
$hCallBack = DllCallbackRegister("_ApiHookCallBack", "dword", "handle;ptr")
$pCallBack = DllCallbackGetPtr($hCallBack)
$hProcess = _RTOpenProcess("notepad.exe")
$immW = _RTGetProcAddress("imm32.dll", "ImmGetCompositionStringW")
$tHookimmW = _RTApiHookEx($hProcess, $immW, 4, $pCallBack, $APIHOOK_Flags_2)
HotKeySet("^{f5}", "_Close")
OnAutoItExitRegister("_Close")
While 1
Sleep(100)
WEnd
Func _ApiHookCallBack($hProcess, $pCallInfo)
Switch _RTApiHookReadProcedure($hProcess, $pCallInfo)
Case $immW
$dwIndex = _RTApiHookReadParam($hProcess, $pCallInfo, 2)
$dwBufLen = _RTApiHookReadParam($hProcess, $pCallInfo, 4)
$Buffer = _RTApiHookReadParam($hProcess, $pCallInfo, 3)
$sNewFileName = _RTReadProcessMemory($hProcess, $Buffer, "", 1024, "wstr")
MsgBox(0, $dwBufLen, $sNewFileName)
EndSwitch
EndFunc ;==>_ApiHookCallBack
Func _Close()
_RTApiUnhook($hProcess, $immW, DllStructGetData($tHookimmW, 6))
Exit
EndFunc ;==>_Close
这个是我修改后的,的确能取得汉字,但是还是有几个问题!
第一、$dwBufLen取得的值不管是几个汉字永远都是0x0000018E
第二、$sNewFileName所取得的汉字,只要是输入的汉字是小于8个,那么总是汉字后面跟着乱码,只要输入的汉字大于等于8个取得的汉字就正常 回复 5# gto250
我测试没问题,MsgBox能够正确输出,没有乱码,$dwBufLen显示的也是正确的字节数。
搜狗版本5.0,AutoIt版本3.3.5.3,系统版本XP SP3英文。 搜狗5.0 正式版
系统:虚拟机里是 sp3中文本机是win7旗舰版
autoit 3.3.6.1
在虚拟机中 $dwBufLen值0x0000018E与在win7系统中一样
但是如果只输入单个字的话在win7中显示正常,多个字乱码,刚好和在虚拟机中相反
不知道什么原因
明天去公司试试
公司的AutoIt版本是3.3.5.3 不是系统原因也不是au3版本原因,是我的notepad记事本原因,我用的是notepad2,虽然进程也是notepad,但是我用系统自带的notepad就显示正常
页:
[1]