标 题: 豪杰V8添加快捷键 作 者: nbw 时 间: 2004-06-05,21:22:21 链 接: http://bbs./showthread.php?t=1695 上次哪位让我做给豪杰添加快捷键的来着,今天发上来,请指正。 豪杰V8添加快捷键 作者:nbw[NE365] www. nboy.cnwlt.com Email: advice107@sina.com 这篇文章我讲以下如何给豪杰V8添加快捷键。豪杰的快进快捷键是:Ctrl+PageDown 。我想修改为右方向键。 在早期,大约是豪杰2000,修改快捷键很方便,当时的处理方式我记得是 cmp eax, ***** ; jz ----- ;其中修改**** 为相应的按键消息就完成了快捷键修改。后来,豪杰提供了修改快捷键的功能。修改快捷键更方便。但是到了V8好象这些都没有了。以至于修改快捷键很困难。 这里要感谢轻描淡写的朋友和NE365的朋友,弟兄们提出不少方法来修改。有的说用RegisterHotKey,有的说用钩子,我这里用钩子来做,因为这种方法很通用,如果设置成全局钩子,就可以作成“一键呼出”那种。不过如果别的方法更方便,还请告诉我。 首先,我把钩子函数写为动态库Hookdll.dll,把里面的函数先导入到豪杰中,用PEDIT就可以。 导入KeyDll信息到豪杰主程序: InstallHook : RVA==AD228 UninstallHook : RVA==AD22C 安装钩子 获得窗口句柄: 由于钩子函数需要窗口句柄,因此,需从内存中找到句柄存放位置。我在以前写的“豪杰最大化按钮无效”的文章中介绍过寻找方法。这里再粗略说说。 打开豪杰,用工具(比如TRW的Hwnd命令)查看主窗口句柄,比如说是FD4 H。用WinHex打开豪杰进程的内存空间,以Hex方式搜索 D40F,可以找到:43C9F4 处有这个内容。则,句柄存放位置为:43C9F4 。但是这个地址的内容是程序初始化的时候填入的,下命令bpm 43C9F4 w 。重新打开豪杰,2次中断后,(:410684处), :43C9F4 处被填入正确句柄,具体位置如下: * Possible Reference to String Resource ID=00001: 'Select Directory' | :0041067C 6A01 push 00000001 :0041067E 51 push ecx :0041067F E83CF5FFFF call 0040FBC0 :00410684 83C410 add esp, 00000010 ;到了这里,窗口句柄被存放到:43C9F4 。所以从这里便可以获得句柄。 :00410687 6870D24300 push 0043D270 :0041068C E8839C0100 call 0042A314 :00410691 8B0D70D24300 mov ecx, dword ptr [0043D270] 寻找剩余空间: 用我写的剩余空间查看器分析,部分结果如下: 名称 RVA OA 尺寸D 可写否 .text 00030000 00030000 0 可 但是文件地址:30000上面有全零空间。从2FE10 ------ 2FFFF 全为可用空间。且有可读属性。 转华容道(跳转到剩余空间): :0041067F E83CF5FFFF call 0040FBC0 :00410684 83C410 add esp, 00000010 :00410687 6870D24300 push 0043D270 修改为: :0041067F E83CF5FFFF call 0040FBC0 :00410684 jmp 42FE20 nop nop nop :0041068C E8839C0100 call 0042A314 少了:00410684 add esp, 00000010 和 :00410687 push 0043D270 记下来,以后补上。 添加自己的代码: 从42FE20开始: 初始化钩子函数 :42FE20 add esp,10 ;修补上面占用的代码 push 43D270 pushad push 000 push [43C9F4] call dword [4AD228] ;设置钩子函数 popad @@: jmp 10689 ;返回 到了这里,钩子便被安装上了,以后在使用豪杰时点任何一个按键,就会被我们的钩子函数拦截。下面我们就要在钩子函数中实现快进功能。首先看看我最开始写的钩子函数: HookProc 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 ;_lParam的高16位可以标志每个按键。该参数定义可以参考MSDN shr ecx,16 and ecx,0fffh cmp ecx,014dh ;如果是 014D则说明是右方向键 jnz @F call _forward ;这里就可以填写用来快进的函数或者代码 @@: xor eax,eax ret HookProc endp 上面的函数很简单,首先获得键盘状态,保存在ecx中,处理ecx,如果为014dh,则说明是右方向键。说实话这个014d是我自己实验得来的,或许不准确。代码中的call _forward 是用来快进的函数。毫无疑问这个函数不好编写,事实上我也不会自己写。 这个用来快进的函数很好寻找。因为程序的控制菜单中有快进项,所以考虑处理这个菜单的地方。利用我以前的文章讲过的方法,很容易可以找到处理菜单消息的函数是::00410E48 E8E30A0000 call 00411930 。打开一部电影,在菜单中选快进项,会被中断在这里。进入这个函数,单步运行,注意播放屏幕的变化,当走过:004127BA FF5218 call [edx+18] 时屏幕发生很大变动,就是向前快进了很多。这个函数就是传说中的快进函数。 你或许会说直接把上面的call _forward 改成call [edx+18] 就可以,当然首先需要确定edx值,如果有需要的话再事先传几个参数就可以。但事实往往和人的想法不一样。因为我没有找到那几个函数的正确的参数,因此也不会正确调用call [edx+18] 。不过不用怕,可以把call _forward 改成跳转,跳到那个函数的地方,也就是jmp 004127BA (call [edx+18]所处的位置)。按照正常理解,这样的跳转肯定会出问题的,但下面我讲讲所谓的“模拟跳转”。 没有人提出来所谓的“模拟跳转”概念,但肯定有人用过。处理菜单的函数是call 00411930,这个函数的入口如下: :00411930 81EC24090000 sub esp, 00000924 ;这里是入口 :00411936 A1EC3C4300 mov eax, dword ptr [00433CEC] :0041193B 53 push ebx :0041193C 55 push ebp :0041193D 56 push esi 。。。。。。。 。。。。。。。 。。。。。。。 :004127BA FF5218 call [edx+18] ;这是快进函数 。。。。。。。 在这个函数中便有快进函数。我所谓的“跳转”是说跳转到入口:00411930处 ,所谓的“模拟”是指跳转以前把所有需要设置的参数设置好。这些参数包括寄存器,堆栈和其他一些必要数据。下面是我找的一些参数。 mov eax,01c385H mov [esp+4],eax mov eax,543a63h push eax mov eax,433cech pop eax mov ebx,1c385h mov ebp,0111h xor esi,esi mov edi,0234h mov eax,411930h push 410e4dh jmp eax ;模仿按下快进按钮,跳转到处理函数 把上面这些替代call _forward ,就可以执行快进函数了。我找的这个模拟环境或许有多余的,我懒得测试,一并写上了。由于这个模拟环境并没有实现完全的模拟,就是说环境设置的不够完全,所以虽然可以执行完快进函数,但继续向下运行就会出错。既然如此,就不用继续运行,而是在运行完快进函数后返回到钩子函数,如下: :004127B3 6810270000 push 00002710 :004127B8 8B11 mov edx, dword ptr [ecx] :004127BA FF5218 call [edx+18] ;快进函数 :004127BD E9451B0000 jmp 00414307 ;把这里修改,返回到钩子函数 修改这个jmp,跳转到@@: xor eax,eax 就是 call _forward 下面的地方。但返回后又要恢复原来钩子函数的堆栈,所以可以在模拟跳转以前把堆栈入口保存,返回后再恢复。我把堆栈入口保存在了[42fe10h] 。返回后从这里取就可以了。同时,修改:004127BD jmp 00414307 也必须遵照SMC的标准,不要改变原来程序的可读性。具体的代码请看下文。 标志位:[42FE14]==01 -----> 按右方向键 [42FE14]==00 ------>没有按右方向键 钩子函数: HookProc 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 ;_lParam的高16位可以标志每个按键。该参数定义可以参考MSDN shr ecx,16 ;414D and ecx,0fffh cmp ecx,014dh jnz @F ;判断是不是有方向键 pushad mov eax,42fe10h mov dword ptr [eax],esp ;保存堆栈入口 mov eax,42fe14h mov dword ptr [eax],001h ;设定标志位为1 mov eax,01c385H ;设定模拟环境 mov [esp+4],eax mov eax,543a63h push eax mov eax,433cech pop eax mov ebx,1c385h mov ebp,0111h xor esi,esi mov edi,0234h mov eax,41192CH push 410e4dh jmp eax ;模仿按下快进按钮,跳转到处理函数 nop ;快进函数执行完毕后便跳转到这个地方 nop mov eax,42fe14h ;va=0e810a7h mov dword ptr [eax],000h ;恢复标志位 mov eax,42fe10h mov esp,dword ptr [eax] ;恢复原来的堆栈地址.一般来说上面有了pushad,下面直接用popad ;便可以了.但是我们这里没有很好地恢复堆栈,所以只好手动调整 popad ;恢复原来保存的环境 @@: xor eax,eax ret HookProc endp 处理快进的函数调用: :004127B8 8B11 mov edx, dword ptr [ecx] mov edx,010AF8F8 :004127BA FF5218 call [edx+18] ;快进函数 :004127BD E9451B0000 jmp 00414307 改成: :004127BA FF5218 call [edx+18] :004127BD E9451B0000 jmp 0042FE5A ;跳转到剩余空间 剩余空间添加代码: 0042FE5A: push eax mov eax,42fe14h mov eax,dword ptr [eax] dec eax test eax,eax pop eax jnz 00414307 ;标志位不为1,直接跳转到程序原来设定的地方。 pop eax jmp 0e810a7 ;标志位为1,回到钩子函数后面。 这样整个修改过程就完工了。当按右方向键就会实现快进的功能。当然原来的ctrl+pagedown也可以用。我想我这篇文章肯定给人很凌乱的感觉,但我也没办法了。在技术上,代码写的很有“冗余”度,也没有卸载钩子(UninstallHook),这个可以在程序结束的时候处理,大家有兴趣可以自己加上。同时我只做了一个快进,也没有处理后退功能。处理方法一样,但是我还是想先把毕业论文做完,嘿嘿。 点击下载:附件!*转载请注明来自看雪论坛@PEdiy.com |
|