找回密码
 加入
搜索
查看: 7163|回复: 7

[系统综合] hook ImmGetCompositionString进行中文记录出错求助(已解决)

  [复制链接]
发表于 2010-9-8 21:50:25 | 显示全部楼层 |阅读模式
本帖最后由 gto250 于 2010-9-9 11:04 编辑

一个半成品的中文键盘记录,记事本程序的中文记录,用的是P版的hook api
对ImmGetCompositionString进行hook
LONG ImmGetCompositionStringA LPVOID lpBuf (
  __in   HIMC hIMC,
  __in   DWORD dwIndex,
  __out  LPVOID lpBuf,
  __in   DWORD dwBufLen
);

我在网上看到的文章是只要dwIndex=0x0800  dwBufLen不为空就可以获取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

评分

参与人数 1金钱 +10 收起 理由
afan + 10 感谢主动将修改帖子分类为[已解决],请继续 ...

查看全部评分

发表于 2010-9-8 22:04:06 | 显示全部楼层
把代码整理好就跟你说,格式缩进还有空行等等。
 楼主| 发表于 2010-9-8 22:33:39 | 显示全部楼层
好了!
发表于 2010-9-8 22:47:56 | 显示全部楼层
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(在调用完成但仍没有返回时调用回调函数)代替。

评分

参与人数 1金钱 +30 收起 理由
afan + 30

查看全部评分

 楼主| 发表于 2010-9-8 23:47:30 | 显示全部楼层
#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个取得的汉字就正常
发表于 2010-9-9 00:04:29 | 显示全部楼层
回复 5# gto250


    我测试没问题,MsgBox能够正确输出,没有乱码,$dwBufLen显示的也是正确的字节数。
搜狗版本5.0,AutoIt版本3.3.5.3,系统版本XP SP3英文。
 楼主| 发表于 2010-9-9 00:16:19 | 显示全部楼层
搜狗5.0 正式版
系统:虚拟机里是 sp3中文  本机是win7旗舰版
autoit 3.3.6.1

在虚拟机中 $dwBufLen值0x0000018E与在win7系统中一样
但是如果只输入单个字的话在win7中显示正常,多个字乱码,刚好和在虚拟机中相反

不知道什么原因
明天去公司试试
公司的AutoIt版本是3.3.5.3
 楼主| 发表于 2010-9-9 11:04:17 | 显示全部楼层
不是系统原因也不是au3版本原因,是我的notepad记事本原因,我用的是notepad2,虽然进程也是notepad,但是我用系统自带的notepad就显示正常
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-11-18 18:47 , Processed in 0.102104 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表