江湖上传言:
中国移动真正比联通强的原因(一定要试试看呀!)
如果你的电脑*作系统是win2000或winxp的话,
那么:1、在桌面上点右键,选择新建 - 文本文档;
2、打开“新建 文本文档”,录入“移动”两字后存盘退出;
3、重新打开“新建 文本文档”,看到什么了?
4、是不是刚刚录入的“移动”两字?
咱们换过来
1、在桌面上点右键,选择新建 - 文本文档;
2、打开“新建 文本文档”,录入“联通”两字后存盘退出;
3、重新打开“新建 文本文档”,看到什么了?
4、是不是刚刚录入的“联通”两字不见了,取而代之是个烧焦的手机电池的模样?
移动真的强过联通吗? 想知道到底为什么出现了这样的结果,所以调试了一把记事本程序,这个与我相伴多时的应用程序。
首先,OD载入记事本,让程序运行起来。
在打开一个文件浏览时,势必要调用CreateFileA or CreateFileW, 记事本用的是Unicode,
所以只需在 CreateFileW 下断点即可,点记事本的菜单文件-打开,选中文件,
这个时候会断下来,此时程序停在Kernel32.CreateFileW函数的入口,
Alt-F9,执行返回到用户代码,
此时查看代码下面一段,会发现有读文件和发送消息的函数调用,
0100263C |. 57 PUSH EDI ; /hTemplateFile => NULL
0100263D |. 68 80000000 PUSH 80 ; |Attributes = NORMAL
01002642 |. 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
01002644 |. 57 PUSH EDI ; |pSecurity => NULL
01002645 |. 6A 01 PUSH 1 ; |ShareMode = FILE_SHARE_READ
01002647 |. 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ
0100264C |. 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C] ; |
01002652 |. 50 PUSH EAX ; |FileName
01002653 |. FF15 04110001 CALL DWORD PTR DS:[<&KERNEL32.CreateFileW>] ; \CreateFileW
01002659 |. 83F8 FF CMP EAX,-1
0100265C |. 8985 ECF9FFFF MOV DWORD PTR SS:[EBP-614],EAX
01002662 |. 0F84 91000000 JE notepad.010026F9
01002668 |. 57 PUSH EDI ; /pOverlapped => NULL
01002669 |. 8D8D F0F9FFFF LEA ECX,DWORD PTR SS:[EBP-610] ; |
0100266F |. 51 PUSH ECX ; |pBytesRead
01002670 |. 68 00040000 PUSH 400 ; |BytesToRead = 400 (1024.)
01002675 |. 8D8D F4F9FFFF LEA ECX,DWORD PTR SS:[EBP-60C] ; |
0100267B |. 51 PUSH ECX ; |Buffer
0100267C |. 50 PUSH EAX ; |hFile
0100267D |. FF15 00110001 CALL DWORD PTR DS:[<&KERNEL32.ReadFile>] ; \ReadFile
01002683 |. 85C0 TEST EAX,EAX
01002685 |. 7E 66 JLE SHORT notepad.010026ED
01002687 |. 39BD F0F9FFFF CMP DWORD PTR SS:[EBP-610],EDI
0100268D |. 74 5E JE SHORT notepad.010026ED
0100268F |. FFB5 F0F9FFFF PUSH DWORD PTR SS:[EBP-610] ; /读取的字节数
01002695 |. 8D85 F4F9FFFF LEA EAX,DWORD PTR SS:[EBP-60C] ; |
0100269B |. 50 PUSH EAX ; |缓冲区地址
0100269C |. E8 FCFCFFFF CALL notepad.0100239D ; \notepad.0100239D
010026A1 |. 8B0D B4900001 MOV ECX,DWORD PTR DS:[10090B4] ; 编码标志
010026A7 |. A3 30900001 MOV DWORD PTR DS:[1009030],EAX ; 返回值是3
010026AC |. 48 DEC EAX ; Switch (cases 1..3)
010026AD |. 74 16 JE SHORT notepad.010026C5
010026AF |. 48 DEC EAX
010026B0 |. 74 0B JE SHORT notepad.010026BD
010026B2 |. 48 DEC EAX
010026B3 |. 75 16 JNZ SHORT notepad.010026CB
010026B5 |. 8B0D C0900001 MOV ECX,DWORD PTR DS:[10090C0] ; Case 3 of switch 010026AC
010026BB |. EB 0E JMP SHORT notepad.010026CB
010026BD |> 8B0D BC900001 MOV ECX,DWORD PTR DS:[10090BC] ; Case 2 of switch 010026AC
010026C3 |. EB 06 JMP SHORT notepad.010026CB
010026C5 |> 8B0D B8900001 MOV ECX,DWORD PTR DS:[10090B8] ; Case 1 of switch 010026AC
010026CB |> 51 PUSH ECX ; /lParam; Default case of switch 010026AC
010026CC |. 6A FF PUSH -1 ; |wParam = FFFFFFFF
010026CE |. 68 4D010000 PUSH 14D ; |Message = CB_SELECTSTRING
010026D3 |. 68 01010000 PUSH 101 ; |ControlID = 101 (257.)
010026D8 |. 56 PUSH ESI ; |hWnd
010026D9 |. FF15 3C120001 CALL DWORD PTR DS:[<&USER32.SendDlgItemMessageW>] ; \SendDlgItemMessageW
在两个熟悉的函数中间 发现还有一个函数,即
0100269C |. E8 FCFCFFFF CALL notepad.0100239D
而其参数正是读取的字节数和读取数据的缓冲区地址,
所以怀疑这个函数中有对字符编码方面的判断,跟进发现确实有对字符编码的判断操作,
0100239D /$ 8BFF MOV EDI,EDI
0100239F |. 55 PUSH EBP
010023A0 |. 8BEC MOV EBP,ESP
010023A2 |. 57 PUSH EDI
010023A3 |. 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C] ; 获得字节数
010023A6 |. 33C0 XOR EAX,EAX
010023A8 |. 83FF 01 CMP EDI,1
010023AB |. 76 52 JBE SHORT notepad.010023FF
010023AD |. 56 PUSH ESI
010023AE |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ; 获得缓冲区地址
010023B1 |. 0FB70E MOVZX ECX,WORD PTR DS:[ESI]
010023B4 |. 81F9 EFBB0000 CMP ECX,0BBEF ; 比较前两个字节
010023BA |. 74 34 JE SHORT notepad.010023F0
010023BC |. 81F9 FFFE0000 CMP ECX,0FEFF
010023C2 |. 74 13 JE SHORT notepad.010023D7
010023C4 |. 81F9 FEFF0000 CMP ECX,0FFFE
010023CA |. 74 20 JE SHORT notepad.010023EC
010023CC |. 57 PUSH EDI
010023CD |. 56 PUSH ESI
010023CE |. E8 DE4C0000 CALL notepad.010070B1 ; 内调用了 ADVAPI32.IsTextUnicode
010023D3 |. 85C0 TEST EAX,EAX
010023D5 |. 74 05 JE SHORT notepad.010023DC
010023D7 |> 33C0 XOR EAX,EAX
010023D9 |. 40 INC EAX
010023DA |. EB 22 JMP SHORT notepad.010023FE
010023DC |> 57 PUSH EDI ; /Arg2
010023DD |. 56 PUSH ESI ; |Arg1
010023DE |. E8 764C0000 CALL notepad.01007059 ; \notepad.01007059
010023E3 |. F7D8 NEG EAX ; call 107059的返回值,很重要,也影响了当前返回值
010023E5 |. 1BC0 SBB EAX,EAX
010023E7 |. 83E0 03 AND EAX,3
010023EA |. EB 12 JMP SHORT notepad.010023FE
010023EC |> 6A 02 PUSH 2
010023EE |. EB 0D JMP SHORT notepad.010023FD
010023F0 |> 83FF 02 CMP EDI,2
010023F3 |. 76 09 JBE SHORT notepad.010023FE
010023F5 |. 807E 02 BF CMP BYTE PTR DS:[ESI+2],0BF
010023F9 |. 75 03 JNZ SHORT notepad.010023FE
010023FB |. 6A 03 PUSH 3
010023FD |> 58 POP EAX
010023FE |> 5E POP ESI
010023FF |> 5F POP EDI
01002400 |. 5D POP EBP
01002401 \. C2 0800 RETN 8
但是发现真正左右返回值的是 CALL notepad.01007059 ,分析此函数~
01007059 /$ 8BFF MOV EDI,EDI
0100705B |. 55 PUSH EBP
0100705C |. 8BEC MOV EBP,ESP
0100705E |. 56 PUSH ESI
0100705F |. 33F6 XOR ESI,ESI
01007061 |. 33C9 XOR ECX,ECX
01007063 |. 46 INC ESI
01007064 |. 33D2 XOR EDX,EDX
01007066 |. 394D 0C CMP DWORD PTR SS:[EBP+C],ECX
01007069 |. 7E 35 JLE SHORT notepad.010070A0
0100706B |> 8B45 08 /MOV EAX,DWORD PTR SS:[EBP+8] ; 缓冲区地址
0100706E |. 8A0401 |MOV AL,BYTE PTR DS:[ECX+EAX] ; 循环取得每个字符
01007071 |. 84C0 |TEST AL,AL
01007073 |. 79 02 |JNS SHORT notepad.01007077
01007075 |. 33F6 |XOR ESI,ESI
01007077 |> 85D2 |TEST EDX,EDX
01007079 |. 75 10 |JNZ SHORT notepad.0100708B ; 这个跳转将最大可能出现al大于80的情况
0100707B |. 3C 80 |CMP AL,80 ; 考察符号位
0100707D |. 72 13 |JB SHORT notepad.01007092 ; 低于则跳转
0100707F |> D0E0 |/SHL AL,1 ; al必须小于80 ~~~~
01007081 |. 42 ||INC EDX
01007082 |. 84C0 ||TEST AL,AL
01007084 |.^ 78 F9 |\JS SHORT notepad.0100707F ; 直到al的最高位为0跳出循环
01007086 |. 4A |DEC EDX
01007087 |. 74 17 |JE SHORT notepad.010070A0 ; al = 0 时跳转
01007089 |. EB 07 |JMP SHORT notepad.01007092
0100708B |> 24 C0 |AND AL,0C0
0100708D |. 3C 80 |CMP AL,80 ;联通 的 ascii 经过计算 al 会等于 80
0100708F 75 0F JNZ SHORT notepad.010070A0 ; 关键跳转,正是这个跳转导致错误的出现了
01007091 |. 4A |DEC EDX ;将 jnz 改为 jle 即成功~~
01007092 |> 41 |INC ECX
01007093 |. 3B4D 0C |CMP ECX,DWORD PTR SS:[EBP+C]
01007096 |.^ 7C D3 \JL SHORT notepad.0100706B
01007098 |. 85D2 TEST EDX,EDX
0100709A |. 77 04 JA SHORT notepad.010070A0
0100709C |. 85F6 TEST ESI,ESI
0100709E |. 74 04 JE SHORT notepad.010070A4
010070A0 |> 33C0 XOR EAX,EAX
010070A2 |. EB 03 JMP SHORT notepad.010070A7 ; 跳转 返回值为0,代表ascii
010070A4 |> 33C0 XOR EAX,EAX
010070A6 |. 40 INC EAX
010070A7 |> 5E POP ESI
010070A8 |. 5D POP EBP
010070A9 \. C2 0800 RETN 8
在上面这个函数 即找到了错误的所在。
另外原始的记事本程序,输入5个“联”,保存打开后什么也显不出来的。
经过修正后,显示正常~
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!