作 者: newjueqi
链 接: http://bbs.pediy.com/showthread.php?t=81208
=========原创信息还是必须保留滴 敬重技术达人=============
具体的思路:其实自动保存功能就是程序隔一段时间保存一次,而记事本程序是自带了保存功能的,所以只要编程安装一个记时器,每隔一段时间模拟点击“保存菜单”,就能实现自动保存,最后退出时把记时器撤销。
首先,用eXeScope给记事本增加两个菜单项“自动保存”“关闭自动保存”,如图1所示:
图1
其中,“自动保存”的菜单ID是8 ,“关闭自动保存” 的菜单ID是13。
完成后的菜单选项如图2所示:
图2
本次修改要用到3个window API函数: SetTimer, KillTimer , SendMessageA, 这3个API没包括在记事本的输入表里,所以要用LordPE 在输入表里增加这3个API。
用LordPE打开记事本程序,依次选择Direction->输入表的“…”按钮¬->点击右键->add import,出现如图3的界面,就可以在输入表里增加新的API
图三
完成后就新增了一个区段Slivana如图4,放的就是新的IID数据,如图4所示
图4
添加完新的API后又有一个新的问题了,那就是要确定新的API地址,这个在PEDIY的过程中是要自己解决的,而平时是编译器帮忙的。获得API地址有两个方法:
(1)直接查看新增的IID数据,载入程序后在命令行打入d 1013000,如图5所示:
图5
0006FDE0 /0006FE0C ; ebp的值0006FDE4 |77D18734 ; 返回到 user32.77D18734,返回地址值0006FDE8 |00100618 ;窗口的句柄0006FDEC |00000111 ;WM_COMMAND的16进制值,可查阅WinUser.h文件获得0006FDF0 |00000008 ;wParam,“自动保存”的菜单ID是80006FDF4 |00000000 ;lParam,
由此可知,[ebp+c]是消息的类型,[ebp+10]是wParam参数,获取菜单的ID就需要知道wParam参数。
另外还有一个问题要解决,SetTimer和KillTimer这两个API函数的参数中必须要传入窗口句柄作为参数,但窗口句柄怎么找呢?我们知道,在用CreateWindowExW函数创建窗口后会返回一个窗口句柄,在OD里对CreateWindowExW下断点,中断后代码如图9:
图9
从红框部分可知,窗口句柄保存在地址[1009830]。
0100874F . 55 push ebp01008750 . 8BEC mov ebp, esp01008752 . 60 pushad01008753 . 817D 0C 11010>cmp dword ptr [ebp+C], 111 ;先比较消息的类型,看是否WM_COMMAND, 如果是WM_COMMAND的话再检查wParam参数进一步确定是哪个菜单的消息0100875A . 75 0C jnz short 01008768 ;如果不是WM_COMMAND消息的话就检查是否WM_TIMER或WM_CLOSE消息0100875C . 837D 10 08 cmp dword ptr [ebp+10], 8 ;比较菜单的ID号,看是否“自动保存”的菜单ID01008760 . 74 1C je short 0100877E ;不是的话就跳去检查其它的消息类型01008762 . 837D 10 0D cmp dword ptr [ebp+10], 0D ;比较菜单的ID号,看是否“关闭自动保存”的菜单ID01008766 . 74 48 je short 010087B0 ;不是的话就跳去检查其它的消息类型01008768 > 817D 0C 13010>cmp dword ptr [ebp+C], 113 ;比较消息的类型是否是WM_TIMER消息,响应定时器消息0100876F . 74 5F je short 010087D0 ;不是的话就跳去函数的结束清场工作01008771 . 837D 0C 10 cmp dword ptr [ebp+C], 10 ;比较消息的类型是否是WM_CLOSE消息,闭关时要先撤销定时器01008775 . 74 39 je short 010087B0 ;不是的话就跳去函数的结束清场工作01008777 > 61 popad01008778 . 5D pop ebp01008779 .^ E9 ABACFFFF jmp 01003429 ;跳回原来记事本的消息循环0100877E > C605 20890001>mov byte ptr [1008920], 1 ;标记已使用自动保存功能01008785 . 6A 00 push 0 ; /Timerproc = NULL01008787 . 68 60EA0000 push 0EA60 ; |Timeout = 60000. ms0100878C . 6A 01 push 1 ; |TimerID = 10100878E . FF35 30980001 push dword ptr [1009830] ; |hWnd = [1009830],在CreateWindowExW后保存窗口句柄的地址01008794 . FF15 2C300101 call dword ptr [<&user32.SetTimer>] ; \SetTimer0100879A . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL0100879C . 68 00DB0001 push 0100DB00 ; |Title = "Note"010087A1 . 68 10DB0001 push 0100DB10 ; |Text = "AutoSave Start!"010087A6 . 6A 00 push 0 ; |hOwner = NULL010087A8 . FF15 30300101 call dword ptr [<&user32.MessageBoxA>>; \MessageBoxA ;提示已使用自动保存功能010087AE .^ EB C7 jmp short 01008777 ;跳去函数结束清场010087B0 > 803D 20890001>cmp byte ptr [1008920], 0 ;先比较是否已启动定时器010087B7 .^ 74 BE je short 01008777 ;如果没启动定时器就跳去函数结束清场010087B9 . C605 20890001>mov byte ptr [1008920], 0 ;把启动定时器的标记恢复010087C0 . 6A 01 push 1 ; /TimerID = 1010087C2 . FF35 30980001 push dword ptr [1009830] ; |hWnd,在CreateWindowExW后保存窗口句柄的地址010087C8 . FF15 34300101 call dword ptr [<&user32.KillTimer>] ; \KillTimer,撤销定时器010087CE .^ EB A7 jmp short 01008777 ;跳去函数结束清场010087D0 > 6A 00 push 0 ; /lParam = 0010087D2 . 6A 03 push 3 ; |wParam = 3 ,“保存”菜单的ID号010087D4 . 68 11010000 push 111 ; |Message = WM_COMMAND010087D9 . FF35 30980001 push dword ptr [1009830] ; |hWnd ,在CreateWindowExW后保存窗口句柄的地址010087DF . FF15 40120001 call dword ptr [<&USER32.SendMessageW>; \SendMessageW ;发送点击菜单“保存”的信号给记事本窗口,实现保存功能。010087E5 .^ EB 90 jmp short 01008777 ;跳去函数结束清场