首页
论坛
专栏
课程

[原创]让记事本[状态栏]不再受[自动换行]影响

2010-6-29 18:34 12220

[原创]让记事本[状态栏]不再受[自动换行]影响

2010-6-29 18:34
12220
【软件名称】: NOTEPAD.EXE(来自WinServer2003)
【下载地址】: 附件中
【操作环境】: Windows 7,OD
【作者声明】: 只是学习,没有其他目的。失误之处恳请各位指出!

Windows自带的记事本轻巧方便,但使用中我们发现一个问题,就是不能同时选取【自动换行】和【状态栏】两个菜单项。
开发人员这么做必然有他自己的理由,但我们今天就试着来改变一下。
很自然的,我们想到修改记事本的窗口处理过程。那么我们开始吧!

OD载入notepade.exe,命令行下 bp SendMessageW。
F9运行,断在USER32.SendMessageW。
Alt+M 打开内存映射,在 NOTEPAD 的代码段(.text)F2下访问断点。
F9运行,断在下面:

01003449      8BFF          MOV EDI,EDI
0100344B  /.  55            PUSH EBP
0100344C  |.  8BEC          MOV EBP,ESP
0100344E  |.  51            PUSH ECX
0100344F  |.  51            PUSH ECX
01003450  |.  56            PUSH ESI
01003451  |.  8B75 0C       MOV ESI,DWORD PTR SS:[EBP+C]
01003454  |.  83FE 1C       CMP ESI,1C                               ;  Switch (cases 2..8001)


看看,呵,不错,直接到窗口函数入口了。往下拉一拉,也就看到了 WM_COMMAND 分支,如下:

010038E7  |> \3B3D 18980001 CMP EDI,DWORD PTR DS:[1009818]           ;  Case 111 (WM_COMMAND) of switch 01003454

现在就可以设置断点跟踪了。当然,如果想更有针对性的话,可以下条件断点。比如在入口 01003449 处,Shift+F4打开条件记录断点窗口,如下图设置确定即可,同时删除其它干扰断点。



为什么要这么设,原因我也讲不好,大家参考论坛中的同类帖子和下面的链接(这里【自动换行】菜单ID为0x20):
http://bbs.pediy.com/showthread.php?threadid=8899
http://msdn.microsoft.com/en-us/library/ms647591(VS.85).aspx
好,F9运行,记事本窗体出现了。现在点击【自动换行】项,不出意外的话,程序就断在了 01003449 处。F8单步,很快就来到了下面:



01003942  |.  E8 60F2FFFF   CALL NOTEPAD.01002BA7                     ; \关键,F7进去。

上面F7跟进去,F8单步,很快来到了下面:



0100315E  |> \A1 30980001   MOV EAX,DWORD PTR DS:[1009830]           ;  Case 20 of switch 01002BDE
01003163  |.  F7D8          NEG EAX                                  ;  这个分支对应【自动换行】菜单项。
01003165  |.  1BC0          SBB EAX,EAX
01003167  |.  25 00001000   AND EAX,100000
0100316C  |.  05 04012050   ADD EAX,50200104
01003171  |.  50            PUSH EAX                                 ; /Arg1
01003172  |.  E8 EA290000   CALL NOTEPAD.01005B61                    ; \NOTEPAD.01005B61
01003177  |.  85C0          TEST EAX,EAX
01003179  |.  74 12         JE SHORT NOTEPAD.0100318D
0100317B  |.  33C0          XOR EAX,EAX
0100317D  |.  3935 30980001 CMP DWORD PTR DS:[1009830],ESI           ;  DS:[1009830]-->【自动换行】先前状态:0-未选中;1-选中。
01003183  |.  0F94C0        SETE AL
01003186  |.  A3 30980001   MOV DWORD PTR DS:[1009830],EAX
0100318B  |.  EB 1A         JMP SHORT NOTEPAD.010031A7
0100318D  |>  6A 30         PUSH 30                                  ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0100318F  |.  FF35 3C900001 PUSH DWORD PTR DS:[100903C]              ; |Title = "记事本"
01003195  |.  FF35 54900001 PUSH DWORD PTR DS:[1009054]              ; |Text = "不能进行自动换行,因为该文件的正文太长。"
0100319B  |.  FF35 10980001 PUSH DWORD PTR DS:[1009810]              ; |hOwner = 00011564 ('无标题 - 记事本',class='Notepad')
010031A1  |.  FF15 64120001 CALL DWORD PTR DS:[<&USER32.MessageBoxW>>; \MessageBoxW
010031A7  |>  3935 30980001 CMP DWORD PTR DS:[1009830],ESI
010031AD      74 50         JE SHORT NOTEPAD.010031FF                ;  跳走即说明将要取消自动换行。
010031AF  |.  A1 20980001   MOV EAX,DWORD PTR DS:[1009820]           ;  【状态栏】先前状态:0-未选中;1-选中。
010031B4  |.  3BC6          CMP EAX,ESI
010031B6  |.  A3 24980001   MOV DWORD PTR DS:[1009824],EAX
010031BB      74 13         JE SHORT NOTEPAD.010031D0                ;  若已被选中,则取消选中并使之变灰。
010031BD  |.  56            PUSH ESI                                 ; /lParam
010031BE  |.  53            PUSH EBX                                 ; |wParam
010031BF  |.  68 11010000   PUSH 111                                 ; |Message = WM_COMMAND
010031C4  |.  FFB5 F0FDFFFF PUSH DWORD PTR SS:[EBP-210]              ; |hWnd
010031CA  |.  FF15 3C120001 CALL DWORD PTR DS:[<&USER32.SendMessageW>; \SendMessageW
010031D0  |>  FF35 10980001 PUSH DWORD PTR DS:[1009810]              ; /hWnd = 00011564 ('无标题 - 记事本',class='Notepad')
010031D6  |.  FF15 60120001 CALL DWORD PTR DS:[<&USER32.GetMenu>]    ; \GetMenu
010031DC  |.  56            PUSH ESI                                 ; /Flags
010031DD  |.  8B35 5C120001 MOV ESI,DWORD PTR DS:[<&USER32.GetSubMen>; |USER32.GetSubMenu
010031E3  |.  53            PUSH EBX                                 ; |ItemId
010031E4  |.  8BF8          MOV EDI,EAX                              ; |
010031E6  |.  6A 03         PUSH 3                                   ; |/Pos = 3
010031E8  |.  57            PUSH EDI                                 ; ||hMenu
010031E9  |.  FFD6          CALL ESI                                 ; |\GetSubMenu
010031EB  |.  50            PUSH EAX                                 ; |hMenu
010031EC  |.  FF15 44120001 CALL DWORD PTR DS:[<&USER32.CheckMenuIte>; \CheckMenuItem(注:MF_CHECKED=0x8)
010031F2  |.  6A 01         PUSH 1                                   ;  注:MF_GRAYED=0x1,使【状态栏】变灰。
010031F4  |.  53            PUSH EBX
010031F5  |.  6A 03         PUSH 3                                   ; /Pos = 3
010031F7  |.  57            PUSH EDI                                 ; |hMenu
010031F8  |.  FFD6          CALL ESI                                 ; \GetSubMenu
010031FA  |.^ E9 3FFDFFFF   JMP NOTEPAD.01002F3E


01002F3E  |> /50            PUSH EAX                                 ; |hMenu
01002F3F  |. |FF15 58120001 CALL DWORD PTR DS:[<&USER32.EnableMenuIt>; \EnableMenuItem
01002F45  |. |E9 3D040000   JMP NOTEPAD.01003387


010031FF  |> \FF35 10980001 PUSH DWORD PTR DS:[1009810]              ; /hWnd = 00011564 ('无标题 - 记事本',class='Notepad')
01003205  |.  FF15 60120001 CALL DWORD PTR DS:[<&USER32.GetMenu>]    ; \GetMenu
0100320B  |.  56            PUSH ESI                                 ; /Flags
0100320C  |.  53            PUSH EBX                                 ; |ItemID
0100320D  |.  6A 03         PUSH 3                                   ; |/Pos = 3
0100320F  |.  50            PUSH EAX                                 ; ||hMenu
01003210  |.  FF15 5C120001 CALL DWORD PTR DS:[<&USER32.GetSubMenu>] ; |\GetSubMenu
01003216  |.  50            PUSH EAX                                 ; |hMenu
01003217  |.  FF15 58120001 CALL DWORD PTR DS:[<&USER32.EnableMenuIt>; \EnableMenuItem
0100321D  |.  3935 24980001 CMP DWORD PTR DS:[1009824],ESI           ;  以下恢复【状态栏】先前状态。
01003223      0F84 5E010000 JE NOTEPAD.01003387
01003229  |.  56            PUSH ESI
0100322A  |.  53            PUSH EBX
0100322B  |.  68 11010000   PUSH 111
01003230  |.  FFB5 F0FDFFFF PUSH DWORD PTR SS:[EBP-210]
01003236  |.^ E9 69FCFFFF   JMP NOTEPAD.01002EA4


01002EA4  |> /FF15 3C120001 CALL DWORD PTR DS:[<&USER32.SendMessageW>; \SendMessageW
01002EAA  |. |E9 D8040000   JMP NOTEPAD.01003387


可以看出,将
010031AD     /74 50         JE SHORT NOTEPAD.010031FF
修改为
010031AD     /EB 50         JMP SHORT NOTEPAD.010031FF
即可解决问题,实践证明确实可行。
修改并复制到可执行文件,运行,发现有个瑕疵,就是当记事本关闭时如果【自动换行】是勾选的,下次打开记事本的时候【状态栏】是灰色的。
现在解决这个问题,程序必定是在加载过程中对【自动换行】是否选中进行了判断。好,Ctrl+F2重新开始,删除无用断点(若有的话),命令行下 bp EnableMenuItem,F9运行。
断下,Alt+F9返回到下面:



呵,又见 DS:[1009830],稍微分析一下就很清楚了,运气不错,一下子就到我们想要的地方了。
0100483E  |. /74 20         JE SHORT NOTEPAD.01004860
修改为
0100483E     /EB 20         JMP SHORT NOTEPAD.01004860
保存为可执行文件(不要丢掉了上面的那个修改)。OK,运行,嗯,挺好,没问题了。
当然,修改这个貌似没什么必要,主要是学习,呵呵。

其它说明:

记事本的配置信息保存在注册表里,如下:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Notepad]
"iWindowPosX"=dword:00000106
"iWindowPosY"=dword:000000ff
"iWindowPosDX"=dword:000003af
"iWindowPosDY"=dword:00000197
"fWrap"=dword:00000000
"StatusBar"=dword:00000000
"lfEscapement"=dword:00000000
"lfOrientation"=dword:00000000
"lfWeight"=dword:00000190
"lfItalic"=dword:00000000
"lfUnderline"=dword:00000000
"lfStrikeOut"=dword:00000000
"lfCharSet"=dword:00000000
"lfOutPrecision"=dword:00000001
"lfClipPrecision"=dword:00000002
"lfQuality"=dword:00000002
"lfPitchAndFamily"=dword:00000031
"iPointSize"=dword:00000064
"fSaveWindowPositions"=dword:00000000
"lfFaceName"="Lucida Console"
"szHeader"="&f"
"szTrailer"="第 &p 页"
"iMarginTop"=dword:000009c4
"iMarginBottom"=dword:000009c4
"iMarginLeft"=dword:000007d0
"iMarginRight"=dword:000007d0
"fMLE_is_broken"=dword:00000000


各项含义比较容易理解,这里当然关注下面两项了:
"fWrap"=dword:00000000
"StatusBar"=dword:00000000

为了验证上面的 DS:[1009830] 和 DS:[1009820] 存放的数据,Ctrl+F2重新开始。在数据窗口中 Ctrl+G 跳转到 1009830 处,并在该处设置内存写入断点,如下图,同时删除无用断点:



F9运行,断在下面:



01003E2D  |.  E8 7BFBFFFF   CALL NOTEPAD.010039AD                     ; \NOTEPAD.010039AD
上面的这个CALL我们重点关注下,在 01003E1F F2下断。Ctrl+F2重新开始,F9运行,断在 01003E1F 处,F7进入 01003E2D 处的CALL,如下图:



此时堆栈数据如下:



可以看到,上面所说是正确的。同样,1009820处的数据也可类似验证之,但这里我再重点介绍一下条件断点。
Ctrl+F2重新开始,删除无用、干扰断点,在命令行下条件断点 bp RegQueryValueExW,[UNICODE [esp+8]]=="StatusBar"。F9运行,断下,此时堆栈窗口数据如下:



Alt+F9返回到下面:



F8单步直到返回,如下:



01003E4E  |.  A3 20980001   MOV DWORD PTR DS:[1009820],EAX            ; |
上面已经可以说明问题了。

  By D.L.
2010/06/29

2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!

上传的附件:
最新回复 (15)
sdnyzjzx 2010-6-29 19:04
2
0
厉害!开眼界了!
sessiondiy 4 2010-6-29 19:20
3
0
我的记事本没[状态栏]
demoscene 7 2010-6-29 20:06
4
0
[QUOTE=sessiondiy;830071]我的记事本没[状态栏] [/QUOTE]

我的也没
slore 2 2010-7-4 17:06
5
0
不同时开是为了不混淆你。

你写一个很长的一个字符串。如果自动换行了,他就是多行。。。但是状态栏难道不该显示实际行数和列数麽?

11111
11111

你显示第二第2列?还是第1行第5列……

不过DIY的不错。
dahual 2 2010-7-4 19:40
6
0
说的对,应该按实际保存的数据来显示。我貌似只看到了表象。。。
whypro 2010-7-4 20:59
7
0
很好呀!楼主继续呀!
slore 2 2010-7-4 21:18
8
0
呵呵,发现系统的记事本没有对注册表上这2个设置做互斥……

你改的设置好后,系统的打开也都显示了,虽然按钮显示灰色=。=

就是改下注册表2个状态都设置,系统的记事本就和你改的一样了,缺点是不能在菜单上改动了,改了就还原回去了。
victoryf 2010-7-5 07:42
9
0
这个也很有用
niuxuexin 2010-7-5 10:03
10
0
都是厉害的人啊
lixupeng 2010-8-8 14:33
11
0
继续DIY
winddyj 2011-2-10 18:29
12
0
刚才才发现记事本在自动换行时状态栏不可用
正好有前辈解决了
radiolyl 2011-5-16 16:10
13
0
好帖,貌似自动换行很有用
killbr 2013-3-5 15:36
14
0
最喜欢这样去BUG类文章了,真是好人啊~~~~~
killbr 2013-3-5 20:48
15
0
高人东西 就是不一样啊,基本就明白了。折腾一次学到东西了,感谢。
金海 2013-6-21 15:16
16
0
MS可能考虑,启用自动换行后,下面显示的是第5行。  但实际的是一行。
游客
登录 | 注册 方可回帖
返回