上次哪位让我做给豪杰添加快捷键的来着,今天发上来,请指正。
豪杰V8添加快捷键
作者:nbw[NE365]
www.vxer.com
nboy.cnwlt.com
Email: [email]advice107@sina.com[/email]
这篇文章我讲以下如何给豪杰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),这个可以在程序结束的时候处理,大家有兴趣可以自己加上。同时我只做了一个快进,也没有处理后退功能。处理方法一样,但是我还是想先把毕业论文做完,嘿嘿。
点击下载:附件!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课